]> git.proxmox.com Git - systemd.git/commitdiff
move imported udev into place
authorKay Sievers <kay.sievers@vrfy.org>
Tue, 3 Apr 2012 19:24:46 +0000 (21:24 +0200)
committerKay Sievers <kay.sievers@vrfy.org>
Wed, 4 Apr 2012 03:05:07 +0000 (05:05 +0200)
395 files changed:
.gitignore
Makefile.am
TODO
autogen.sh
configure.ac
m4/.gitignore
man/udev.xml [new file with mode: 0644]
man/udevadm.xml [new file with mode: 0644]
man/udevd.xml [new file with mode: 0644]
rules/.gitignore [new file with mode: 0644]
rules/42-usb-hid-pm.rules [new file with mode: 0644]
rules/50-udev-default.rules [new file with mode: 0644]
rules/60-persistent-alsa.rules [new file with mode: 0644]
rules/60-persistent-input.rules [new file with mode: 0644]
rules/60-persistent-serial.rules [new file with mode: 0644]
rules/60-persistent-storage-tape.rules [new file with mode: 0644]
rules/60-persistent-storage.rules [new file with mode: 0644]
rules/75-net-description.rules [new file with mode: 0644]
rules/75-tty-description.rules [new file with mode: 0644]
rules/78-sound-card.rules [new file with mode: 0644]
rules/80-drivers.rules [new file with mode: 0644]
rules/95-udev-late.rules [new file with mode: 0644]
rules/99-systemd.rules.in [new file with mode: 0644]
src/99-systemd.rules.in [deleted file]
src/udev/.gitignore
src/udev/COPYING [deleted file]
src/udev/ChangeLog [deleted file]
src/udev/INSTALL [deleted file]
src/udev/Makefile.am [deleted file]
src/udev/NEWS [deleted file]
src/udev/README [deleted file]
src/udev/TODO [deleted file]
src/udev/accelerometer/61-accelerometer.rules [new file with mode: 0644]
src/udev/accelerometer/accelerometer.c [new file with mode: 0644]
src/udev/ata_id/ata_id.c [new file with mode: 0644]
src/udev/autogen.sh [deleted file]
src/udev/cdrom_id/60-cdrom_id.rules [new file with mode: 0644]
src/udev/cdrom_id/cdrom_id.c [new file with mode: 0644]
src/udev/collect/collect.c [new file with mode: 0644]
src/udev/configure.ac [deleted file]
src/udev/docs/.gitignore [new file with mode: 0644]
src/udev/docs/Makefile.am [new file with mode: 0644]
src/udev/docs/libudev-docs.xml [new file with mode: 0644]
src/udev/docs/libudev-sections.txt [new file with mode: 0644]
src/udev/docs/libudev.types [new file with mode: 0644]
src/udev/docs/version.xml.in [new file with mode: 0644]
src/udev/gudev/.gitignore [new file with mode: 0644]
src/udev/gudev/docs/.gitignore [new file with mode: 0644]
src/udev/gudev/docs/Makefile.am [new file with mode: 0644]
src/udev/gudev/docs/gudev-docs.xml [new file with mode: 0644]
src/udev/gudev/docs/gudev-sections.txt [new file with mode: 0644]
src/udev/gudev/docs/gudev.types [new file with mode: 0644]
src/udev/gudev/docs/version.xml.in [new file with mode: 0644]
src/udev/gudev/gjs-example.js [new file with mode: 0755]
src/udev/gudev/gudev-1.0.pc.in [new file with mode: 0644]
src/udev/gudev/gudev.h [new file with mode: 0644]
src/udev/gudev/gudevclient.c [new file with mode: 0644]
src/udev/gudev/gudevclient.h [new file with mode: 0644]
src/udev/gudev/gudevdevice.c [new file with mode: 0644]
src/udev/gudev/gudevdevice.h [new file with mode: 0644]
src/udev/gudev/gudevenumerator.c [new file with mode: 0644]
src/udev/gudev/gudevenumerator.h [new file with mode: 0644]
src/udev/gudev/gudevenums.h [new file with mode: 0644]
src/udev/gudev/gudevenumtypes.c.template [new file with mode: 0644]
src/udev/gudev/gudevenumtypes.h.template [new file with mode: 0644]
src/udev/gudev/gudevmarshal.list [new file with mode: 0644]
src/udev/gudev/gudevprivate.h [new file with mode: 0644]
src/udev/gudev/gudevtypes.h [new file with mode: 0644]
src/udev/gudev/seed-example-enum.js [new file with mode: 0755]
src/udev/gudev/seed-example.js [new file with mode: 0755]
src/udev/keymap/.gitignore [new file with mode: 0644]
src/udev/keymap/95-keyboard-force-release.rules [new file with mode: 0644]
src/udev/keymap/95-keymap.rules [new file with mode: 0644]
src/udev/keymap/README.keymap.txt [new file with mode: 0644]
src/udev/keymap/check-keymaps.sh [new file with mode: 0755]
src/udev/keymap/findkeyboards [new file with mode: 0755]
src/udev/keymap/force-release-maps/common-volume-keys [new file with mode: 0644]
src/udev/keymap/force-release-maps/dell-touchpad [new file with mode: 0644]
src/udev/keymap/force-release-maps/hp-other [new file with mode: 0644]
src/udev/keymap/force-release-maps/samsung-90x3a [new file with mode: 0644]
src/udev/keymap/force-release-maps/samsung-other [new file with mode: 0644]
src/udev/keymap/keyboard-force-release.sh.in [new file with mode: 0755]
src/udev/keymap/keymap.c [new file with mode: 0644]
src/udev/keymap/keymaps/acer [new file with mode: 0644]
src/udev/keymap/keymaps/acer-aspire_5720 [new file with mode: 0644]
src/udev/keymap/keymaps/acer-aspire_5920g [new file with mode: 0644]
src/udev/keymap/keymaps/acer-aspire_6920 [new file with mode: 0644]
src/udev/keymap/keymaps/acer-aspire_8930 [new file with mode: 0644]
src/udev/keymap/keymaps/acer-travelmate_c300 [new file with mode: 0644]
src/udev/keymap/keymaps/asus [new file with mode: 0644]
src/udev/keymap/keymaps/compaq-e_evo [new file with mode: 0644]
src/udev/keymap/keymaps/dell [new file with mode: 0644]
src/udev/keymap/keymaps/dell-latitude-xt2 [new file with mode: 0644]
src/udev/keymap/keymaps/everex-xt5000 [new file with mode: 0644]
src/udev/keymap/keymaps/fujitsu-amilo_li_2732 [new file with mode: 0644]
src/udev/keymap/keymaps/fujitsu-amilo_pa_2548 [new file with mode: 0644]
src/udev/keymap/keymaps/fujitsu-amilo_pro_edition_v3505 [new file with mode: 0644]
src/udev/keymap/keymaps/fujitsu-amilo_pro_v3205 [new file with mode: 0644]
src/udev/keymap/keymaps/fujitsu-amilo_si_1520 [new file with mode: 0644]
src/udev/keymap/keymaps/fujitsu-esprimo_mobile_v5 [new file with mode: 0644]
src/udev/keymap/keymaps/fujitsu-esprimo_mobile_v6 [new file with mode: 0644]
src/udev/keymap/keymaps/genius-slimstar-320 [new file with mode: 0644]
src/udev/keymap/keymaps/hewlett-packard [new file with mode: 0644]
src/udev/keymap/keymaps/hewlett-packard-2510p_2530p [new file with mode: 0644]
src/udev/keymap/keymaps/hewlett-packard-compaq_elitebook [new file with mode: 0644]
src/udev/keymap/keymaps/hewlett-packard-pavilion [new file with mode: 0644]
src/udev/keymap/keymaps/hewlett-packard-presario-2100 [new file with mode: 0644]
src/udev/keymap/keymaps/hewlett-packard-tablet [new file with mode: 0644]
src/udev/keymap/keymaps/hewlett-packard-tx2 [new file with mode: 0644]
src/udev/keymap/keymaps/ibm-thinkpad-usb-keyboard-trackpoint [new file with mode: 0644]
src/udev/keymap/keymaps/inventec-symphony_6.0_7.0 [new file with mode: 0644]
src/udev/keymap/keymaps/lenovo-3000 [new file with mode: 0644]
src/udev/keymap/keymaps/lenovo-ideapad [new file with mode: 0644]
src/udev/keymap/keymaps/lenovo-thinkpad-usb-keyboard-trackpoint [new file with mode: 0644]
src/udev/keymap/keymaps/lenovo-thinkpad_x200_tablet [new file with mode: 0644]
src/udev/keymap/keymaps/lenovo-thinkpad_x6_tablet [new file with mode: 0644]
src/udev/keymap/keymaps/lg-x110 [new file with mode: 0644]
src/udev/keymap/keymaps/logitech-wave [new file with mode: 0644]
src/udev/keymap/keymaps/logitech-wave-cordless [new file with mode: 0644]
src/udev/keymap/keymaps/logitech-wave-pro-cordless [new file with mode: 0644]
src/udev/keymap/keymaps/maxdata-pro_7000 [new file with mode: 0644]
src/udev/keymap/keymaps/medion-fid2060 [new file with mode: 0644]
src/udev/keymap/keymaps/medionnb-a555 [new file with mode: 0644]
src/udev/keymap/keymaps/micro-star [new file with mode: 0644]
src/udev/keymap/keymaps/module-asus-w3j [new file with mode: 0644]
src/udev/keymap/keymaps/module-ibm [new file with mode: 0644]
src/udev/keymap/keymaps/module-lenovo [new file with mode: 0644]
src/udev/keymap/keymaps/module-sony [new file with mode: 0644]
src/udev/keymap/keymaps/module-sony-old [new file with mode: 0644]
src/udev/keymap/keymaps/module-sony-vgn [new file with mode: 0644]
src/udev/keymap/keymaps/olpc-xo [new file with mode: 0644]
src/udev/keymap/keymaps/onkyo [new file with mode: 0644]
src/udev/keymap/keymaps/oqo-model2 [new file with mode: 0644]
src/udev/keymap/keymaps/samsung-90x3a [new file with mode: 0644]
src/udev/keymap/keymaps/samsung-other [new file with mode: 0644]
src/udev/keymap/keymaps/samsung-sq1us [new file with mode: 0644]
src/udev/keymap/keymaps/samsung-sx20s [new file with mode: 0644]
src/udev/keymap/keymaps/toshiba-satellite_a100 [new file with mode: 0644]
src/udev/keymap/keymaps/toshiba-satellite_a110 [new file with mode: 0644]
src/udev/keymap/keymaps/toshiba-satellite_m30x [new file with mode: 0644]
src/udev/keymap/keymaps/zepto-znote [new file with mode: 0644]
src/udev/libudev-device-private.c [new file with mode: 0644]
src/udev/libudev-device.c [new file with mode: 0644]
src/udev/libudev-enumerate.c [new file with mode: 0644]
src/udev/libudev-list.c [new file with mode: 0644]
src/udev/libudev-monitor.c [new file with mode: 0644]
src/udev/libudev-private.h [new file with mode: 0644]
src/udev/libudev-queue-private.c [new file with mode: 0644]
src/udev/libudev-queue.c [new file with mode: 0644]
src/udev/libudev-selinux-private.c [new file with mode: 0644]
src/udev/libudev-util-private.c [new file with mode: 0644]
src/udev/libudev-util.c [new file with mode: 0644]
src/udev/libudev.c [new file with mode: 0644]
src/udev/libudev.h [new file with mode: 0644]
src/udev/libudev.pc.in [new file with mode: 0644]
src/udev/m4/.gitignore [deleted file]
src/udev/mtd_probe/75-probe_mtd.rules [new file with mode: 0644]
src/udev/mtd_probe/mtd_probe.c [new file with mode: 0644]
src/udev/mtd_probe/mtd_probe.h [new file with mode: 0644]
src/udev/mtd_probe/probe_smartmedia.c [new file with mode: 0644]
src/udev/rules/42-usb-hid-pm.rules [deleted file]
src/udev/rules/50-udev-default.rules [deleted file]
src/udev/rules/60-persistent-alsa.rules [deleted file]
src/udev/rules/60-persistent-input.rules [deleted file]
src/udev/rules/60-persistent-serial.rules [deleted file]
src/udev/rules/60-persistent-storage-tape.rules [deleted file]
src/udev/rules/60-persistent-storage.rules [deleted file]
src/udev/rules/75-net-description.rules [deleted file]
src/udev/rules/75-tty-description.rules [deleted file]
src/udev/rules/78-sound-card.rules [deleted file]
src/udev/rules/80-drivers.rules [deleted file]
src/udev/rules/95-udev-late.rules [deleted file]
src/udev/scsi_id/.gitignore [new file with mode: 0644]
src/udev/scsi_id/README [new file with mode: 0644]
src/udev/scsi_id/scsi.h [new file with mode: 0644]
src/udev/scsi_id/scsi_id.c [new file with mode: 0644]
src/udev/scsi_id/scsi_id.h [new file with mode: 0644]
src/udev/scsi_id/scsi_serial.c [new file with mode: 0644]
src/udev/src/.gitignore [deleted file]
src/udev/src/COPYING [deleted file]
src/udev/src/accelerometer/61-accelerometer.rules [deleted file]
src/udev/src/accelerometer/accelerometer.c [deleted file]
src/udev/src/ata_id/ata_id.c [deleted file]
src/udev/src/cdrom_id/60-cdrom_id.rules [deleted file]
src/udev/src/cdrom_id/cdrom_id.c [deleted file]
src/udev/src/collect/collect.c [deleted file]
src/udev/src/docs/.gitignore [deleted file]
src/udev/src/docs/Makefile.am [deleted file]
src/udev/src/docs/libudev-docs.xml [deleted file]
src/udev/src/docs/libudev-sections.txt [deleted file]
src/udev/src/docs/libudev.types [deleted file]
src/udev/src/docs/version.xml.in [deleted file]
src/udev/src/floppy/60-floppy.rules [deleted file]
src/udev/src/floppy/create_floppy_devices.c [deleted file]
src/udev/src/gudev/.gitignore [deleted file]
src/udev/src/gudev/COPYING [deleted file]
src/udev/src/gudev/docs/.gitignore [deleted file]
src/udev/src/gudev/docs/Makefile.am [deleted file]
src/udev/src/gudev/docs/gudev-docs.xml [deleted file]
src/udev/src/gudev/docs/gudev-sections.txt [deleted file]
src/udev/src/gudev/docs/gudev.types [deleted file]
src/udev/src/gudev/docs/version.xml.in [deleted file]
src/udev/src/gudev/gjs-example.js [deleted file]
src/udev/src/gudev/gudev-1.0.pc.in [deleted file]
src/udev/src/gudev/gudev.h [deleted file]
src/udev/src/gudev/gudevclient.c [deleted file]
src/udev/src/gudev/gudevclient.h [deleted file]
src/udev/src/gudev/gudevdevice.c [deleted file]
src/udev/src/gudev/gudevdevice.h [deleted file]
src/udev/src/gudev/gudevenumerator.c [deleted file]
src/udev/src/gudev/gudevenumerator.h [deleted file]
src/udev/src/gudev/gudevenums.h [deleted file]
src/udev/src/gudev/gudevenumtypes.c.template [deleted file]
src/udev/src/gudev/gudevenumtypes.h.template [deleted file]
src/udev/src/gudev/gudevmarshal.list [deleted file]
src/udev/src/gudev/gudevprivate.h [deleted file]
src/udev/src/gudev/gudevtypes.h [deleted file]
src/udev/src/gudev/seed-example-enum.js [deleted file]
src/udev/src/gudev/seed-example.js [deleted file]
src/udev/src/keymap/.gitignore [deleted file]
src/udev/src/keymap/95-keyboard-force-release.rules [deleted file]
src/udev/src/keymap/95-keymap.rules [deleted file]
src/udev/src/keymap/README.keymap.txt [deleted file]
src/udev/src/keymap/check-keymaps.sh [deleted file]
src/udev/src/keymap/findkeyboards [deleted file]
src/udev/src/keymap/force-release-maps/common-volume-keys [deleted file]
src/udev/src/keymap/force-release-maps/dell-touchpad [deleted file]
src/udev/src/keymap/force-release-maps/hp-other [deleted file]
src/udev/src/keymap/force-release-maps/samsung-90x3a [deleted file]
src/udev/src/keymap/force-release-maps/samsung-other [deleted file]
src/udev/src/keymap/keyboard-force-release.sh.in [deleted file]
src/udev/src/keymap/keymap.c [deleted file]
src/udev/src/keymap/keymaps/acer [deleted file]
src/udev/src/keymap/keymaps/acer-aspire_5720 [deleted file]
src/udev/src/keymap/keymaps/acer-aspire_5920g [deleted file]
src/udev/src/keymap/keymaps/acer-aspire_6920 [deleted file]
src/udev/src/keymap/keymaps/acer-aspire_8930 [deleted file]
src/udev/src/keymap/keymaps/acer-travelmate_c300 [deleted file]
src/udev/src/keymap/keymaps/asus [deleted file]
src/udev/src/keymap/keymaps/compaq-e_evo [deleted file]
src/udev/src/keymap/keymaps/dell [deleted file]
src/udev/src/keymap/keymaps/dell-latitude-xt2 [deleted file]
src/udev/src/keymap/keymaps/everex-xt5000 [deleted file]
src/udev/src/keymap/keymaps/fujitsu-amilo_li_2732 [deleted file]
src/udev/src/keymap/keymaps/fujitsu-amilo_pa_2548 [deleted file]
src/udev/src/keymap/keymaps/fujitsu-amilo_pro_edition_v3505 [deleted file]
src/udev/src/keymap/keymaps/fujitsu-amilo_pro_v3205 [deleted file]
src/udev/src/keymap/keymaps/fujitsu-amilo_si_1520 [deleted file]
src/udev/src/keymap/keymaps/fujitsu-esprimo_mobile_v5 [deleted file]
src/udev/src/keymap/keymaps/fujitsu-esprimo_mobile_v6 [deleted file]
src/udev/src/keymap/keymaps/genius-slimstar-320 [deleted file]
src/udev/src/keymap/keymaps/hewlett-packard [deleted file]
src/udev/src/keymap/keymaps/hewlett-packard-2510p_2530p [deleted file]
src/udev/src/keymap/keymaps/hewlett-packard-compaq_elitebook [deleted file]
src/udev/src/keymap/keymaps/hewlett-packard-pavilion [deleted file]
src/udev/src/keymap/keymaps/hewlett-packard-presario-2100 [deleted file]
src/udev/src/keymap/keymaps/hewlett-packard-tablet [deleted file]
src/udev/src/keymap/keymaps/hewlett-packard-tx2 [deleted file]
src/udev/src/keymap/keymaps/ibm-thinkpad-usb-keyboard-trackpoint [deleted file]
src/udev/src/keymap/keymaps/inventec-symphony_6.0_7.0 [deleted file]
src/udev/src/keymap/keymaps/lenovo-3000 [deleted file]
src/udev/src/keymap/keymaps/lenovo-ideapad [deleted file]
src/udev/src/keymap/keymaps/lenovo-thinkpad-usb-keyboard-trackpoint [deleted file]
src/udev/src/keymap/keymaps/lenovo-thinkpad_x200_tablet [deleted file]
src/udev/src/keymap/keymaps/lenovo-thinkpad_x6_tablet [deleted file]
src/udev/src/keymap/keymaps/lg-x110 [deleted file]
src/udev/src/keymap/keymaps/logitech-wave [deleted file]
src/udev/src/keymap/keymaps/logitech-wave-cordless [deleted file]
src/udev/src/keymap/keymaps/logitech-wave-pro-cordless [deleted file]
src/udev/src/keymap/keymaps/maxdata-pro_7000 [deleted file]
src/udev/src/keymap/keymaps/medion-fid2060 [deleted file]
src/udev/src/keymap/keymaps/medionnb-a555 [deleted file]
src/udev/src/keymap/keymaps/micro-star [deleted file]
src/udev/src/keymap/keymaps/module-asus-w3j [deleted file]
src/udev/src/keymap/keymaps/module-ibm [deleted file]
src/udev/src/keymap/keymaps/module-lenovo [deleted file]
src/udev/src/keymap/keymaps/module-sony [deleted file]
src/udev/src/keymap/keymaps/module-sony-old [deleted file]
src/udev/src/keymap/keymaps/module-sony-vgn [deleted file]
src/udev/src/keymap/keymaps/olpc-xo [deleted file]
src/udev/src/keymap/keymaps/onkyo [deleted file]
src/udev/src/keymap/keymaps/oqo-model2 [deleted file]
src/udev/src/keymap/keymaps/samsung-90x3a [deleted file]
src/udev/src/keymap/keymaps/samsung-other [deleted file]
src/udev/src/keymap/keymaps/samsung-sq1us [deleted file]
src/udev/src/keymap/keymaps/samsung-sx20s [deleted file]
src/udev/src/keymap/keymaps/toshiba-satellite_a100 [deleted file]
src/udev/src/keymap/keymaps/toshiba-satellite_a110 [deleted file]
src/udev/src/keymap/keymaps/toshiba-satellite_m30x [deleted file]
src/udev/src/keymap/keymaps/zepto-znote [deleted file]
src/udev/src/libudev-device-private.c [deleted file]
src/udev/src/libudev-device.c [deleted file]
src/udev/src/libudev-enumerate.c [deleted file]
src/udev/src/libudev-list.c [deleted file]
src/udev/src/libudev-monitor.c [deleted file]
src/udev/src/libudev-private.h [deleted file]
src/udev/src/libudev-queue-private.c [deleted file]
src/udev/src/libudev-queue.c [deleted file]
src/udev/src/libudev-selinux-private.c [deleted file]
src/udev/src/libudev-util-private.c [deleted file]
src/udev/src/libudev-util.c [deleted file]
src/udev/src/libudev.c [deleted file]
src/udev/src/libudev.h [deleted file]
src/udev/src/libudev.pc.in [deleted file]
src/udev/src/mtd_probe/75-probe_mtd.rules [deleted file]
src/udev/src/mtd_probe/mtd_probe.c [deleted file]
src/udev/src/mtd_probe/mtd_probe.h [deleted file]
src/udev/src/mtd_probe/probe_smartmedia.c [deleted file]
src/udev/src/rule_generator/75-cd-aliases-generator.rules [deleted file]
src/udev/src/rule_generator/75-persistent-net-generator.rules [deleted file]
src/udev/src/rule_generator/rule_generator.functions [deleted file]
src/udev/src/rule_generator/write_cd_rules [deleted file]
src/udev/src/rule_generator/write_net_rules [deleted file]
src/udev/src/scsi_id/.gitignore [deleted file]
src/udev/src/scsi_id/README [deleted file]
src/udev/src/scsi_id/scsi.h [deleted file]
src/udev/src/scsi_id/scsi_id.8 [deleted file]
src/udev/src/scsi_id/scsi_id.c [deleted file]
src/udev/src/scsi_id/scsi_id.h [deleted file]
src/udev/src/scsi_id/scsi_serial.c [deleted file]
src/udev/src/sd-daemon.c [deleted file]
src/udev/src/sd-daemon.h [deleted file]
src/udev/src/test-libudev.c [deleted file]
src/udev/src/test-udev.c [deleted file]
src/udev/src/udev-builtin-blkid.c [deleted file]
src/udev/src/udev-builtin-firmware.c [deleted file]
src/udev/src/udev-builtin-hwdb.c [deleted file]
src/udev/src/udev-builtin-input_id.c [deleted file]
src/udev/src/udev-builtin-kmod.c [deleted file]
src/udev/src/udev-builtin-path_id.c [deleted file]
src/udev/src/udev-builtin-usb_id.c [deleted file]
src/udev/src/udev-builtin.c [deleted file]
src/udev/src/udev-control.socket [deleted file]
src/udev/src/udev-ctrl.c [deleted file]
src/udev/src/udev-event.c [deleted file]
src/udev/src/udev-kernel.socket [deleted file]
src/udev/src/udev-node.c [deleted file]
src/udev/src/udev-rules.c [deleted file]
src/udev/src/udev-settle.service.in [deleted file]
src/udev/src/udev-trigger.service.in [deleted file]
src/udev/src/udev-watch.c [deleted file]
src/udev/src/udev.conf [deleted file]
src/udev/src/udev.h [deleted file]
src/udev/src/udev.pc.in [deleted file]
src/udev/src/udev.service.in [deleted file]
src/udev/src/udev.xml [deleted file]
src/udev/src/udevadm-control.c [deleted file]
src/udev/src/udevadm-info.c [deleted file]
src/udev/src/udevadm-monitor.c [deleted file]
src/udev/src/udevadm-settle.c [deleted file]
src/udev/src/udevadm-test-builtin.c [deleted file]
src/udev/src/udevadm-test.c [deleted file]
src/udev/src/udevadm-trigger.c [deleted file]
src/udev/src/udevadm.c [deleted file]
src/udev/src/udevadm.xml [deleted file]
src/udev/src/udevd.c [deleted file]
src/udev/src/udevd.xml [deleted file]
src/udev/src/v4l_id/60-persistent-v4l.rules [deleted file]
src/udev/src/v4l_id/v4l_id.c [deleted file]
src/udev/test-libudev.c [new file with mode: 0644]
src/udev/test-udev.c [new file with mode: 0644]
src/udev/test/rules-test.sh
src/udev/udev-builtin-blkid.c [new file with mode: 0644]
src/udev/udev-builtin-firmware.c [new file with mode: 0644]
src/udev/udev-builtin-hwdb.c [new file with mode: 0644]
src/udev/udev-builtin-input_id.c [new file with mode: 0644]
src/udev/udev-builtin-kmod.c [new file with mode: 0644]
src/udev/udev-builtin-path_id.c [new file with mode: 0644]
src/udev/udev-builtin-usb_id.c [new file with mode: 0644]
src/udev/udev-builtin.c [new file with mode: 0644]
src/udev/udev-ctrl.c [new file with mode: 0644]
src/udev/udev-event.c [new file with mode: 0644]
src/udev/udev-node.c [new file with mode: 0644]
src/udev/udev-rules.c [new file with mode: 0644]
src/udev/udev-watch.c [new file with mode: 0644]
src/udev/udev.conf [new file with mode: 0644]
src/udev/udev.h [new file with mode: 0644]
src/udev/udev.pc.in [new file with mode: 0644]
src/udev/udevadm-control.c [new file with mode: 0644]
src/udev/udevadm-info.c [new file with mode: 0644]
src/udev/udevadm-monitor.c [new file with mode: 0644]
src/udev/udevadm-settle.c [new file with mode: 0644]
src/udev/udevadm-test-builtin.c [new file with mode: 0644]
src/udev/udevadm-test.c [new file with mode: 0644]
src/udev/udevadm-trigger.c [new file with mode: 0644]
src/udev/udevadm.c [new file with mode: 0644]
src/udev/udevd.c [new file with mode: 0644]
src/udev/v4l_id/60-persistent-v4l.rules [new file with mode: 0644]
src/udev/v4l_id/v4l_id.c [new file with mode: 0644]
units/.gitignore
units/udev-control.socket [new file with mode: 0644]
units/udev-kernel.socket [new file with mode: 0644]
units/udev-settle.service.in [new file with mode: 0644]
units/udev-trigger.service.in [new file with mode: 0644]
units/udev.service.in [new file with mode: 0644]

index f36dd8a81afd10669df05cfbf9df5d5c90830f7a..16a6f583b52a4f9d429f45bbe9c714b09f831270 100644 (file)
@@ -107,3 +107,14 @@ ltmain.sh
 *.tar.gz
 *.tar.bz2
 libtool
+/accelerometer
+/ata_id
+/cdrom_id
+/collect
+/gtk-doc.make
+/keymap
+/mtd_probe
+/scsi_id
+/udevadm
+/udevd
+/v4l_id
index 219d8ded8e6115c14f63f2dd8c24e440bb49f420..74e14d2f2a8ebf7f50c3468633ba862fd0edc1c9 100644 (file)
@@ -1,7 +1,7 @@
 #  This file is part of systemd.
 #
-#  Copyright 2011 Lennart Poettering
-#  Copyright 2011 Kay Sievers
+#  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
 #  You should have received a copy of the GNU General Public License
 #  along with systemd; If not, see <http://www.gnu.org/licenses/>.
 
-ACLOCAL_AMFLAGS = -I m4
+ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
+AM_MAKEFLAGS = --no-print-directory
 
-SUBDIRS = po
+SUBDIRS = . po
+
+LIBUDEV_CURRENT=13
+LIBUDEV_REVISION=2
+LIBUDEV_AGE=13
+
+LIBGUDEV_CURRENT=1
+LIBGUDEV_REVISION=1
+LIBGUDEV_AGE=1
 
 LIBSYSTEMD_LOGIN_CURRENT=2
 LIBSYSTEMD_LOGIN_REVISION=1
@@ -41,7 +50,6 @@ dbuspolicydir=@dbuspolicydir@
 dbussessionservicedir=@dbussessionservicedir@
 dbussystemservicedir=@dbussystemservicedir@
 dbusinterfacedir=@dbusinterfacedir@
-udevrulesdir=@udevrulesdir@
 pamlibdir=@pamlibdir@
 pkgconfigdatadir=$(datadir)/pkgconfig
 pkgconfiglibdir=$(libdir)/pkgconfig
@@ -55,6 +63,7 @@ tmpfilesdir=$(prefix)/lib/tmpfiles.d
 sysctldir=$(prefix)/lib/sysctl.d
 usergeneratordir=$(pkglibexecdir)/user-generators
 pkgincludedir=$(includedir)/systemd
+udevlibexecdir=$(rootprefix)/lib/udev
 
 # And these are the special ones for /
 rootprefix=@rootprefix@
@@ -66,17 +75,28 @@ systemunitdir=$(rootprefix)/lib/systemd/system
 
 CLEANFILES =
 EXTRA_DIST =
+BUILT_SOURCES =
 INSTALL_EXEC_HOOKS =
 UNINSTALL_EXEC_HOOKS =
 INSTALL_DATA_HOOKS =
+DISTCHECK_HOOKS =
+DISTCLEAN_LOCAL_HOOKS =
 pkginclude_HEADERS =
 lib_LTLIBRARIES =
+include_HEADERS =
 pkgconfiglib_DATA =
 polkitpolicy_in_files =
 dist_udevrules_DATA =
+nodist_udevrules_DATA =
+udevhomedir = $(libexecdir)/udev
+udevhome_SCRIPTS =
+dist_udevhome_SCRIPTS =
+dist_udevhome_DATA =
+dist_man_MANS =
 
 AM_CPPFLAGS = \
        -include $(top_builddir)/config.h \
+       -DSYSCONFDIR=\""$(sysconfdir)"\" \
        -DSYSTEM_CONFIG_FILE=\"$(pkgsysconfdir)/system.conf\" \
        -DSYSTEM_CONFIG_UNIT_PATH=\"$(pkgsysconfdir)/system\" \
        -DSYSTEM_DATA_UNIT_PATH=\"$(systemunitdir)\" \
@@ -99,12 +119,14 @@ AM_CPPFLAGS = \
        -DUSER_GENERATOR_PATH=\"$(usergeneratordir)\" \
        -DSYSTEM_SHUTDOWN_PATH=\"$(systemshutdowndir)\" \
        -DSYSTEMD_KBD_MODEL_MAP=\"$(pkgdatadir)/kbd-model-map\" \
-        -DX_SERVER=\"$(bindir)/X\" \
+       -DX_SERVER=\"$(bindir)/X\" \
+       -DUDEVLIBEXECDIR=\""$(libexecdir)/udev"\" \
        -I $(top_srcdir)/src \
        -I $(top_srcdir)/src/readahead \
        -I $(top_srcdir)/src/login \
        -I $(top_srcdir)/src/journal \
-       -I $(top_srcdir)/src/systemd
+       -I $(top_srcdir)/src/systemd \
+       -I $(top_srcdir)/src/udev
 
 AM_CFLAGS = $(WARNINGFLAGS)
 AM_LDFLAGS = $(GCLDFLAGS)
@@ -221,9 +243,6 @@ dist_dbuspolicy_DATA = \
 dist_dbussystemservice_DATA = \
        src/org.freedesktop.systemd1.service
 
-nodist_udevrules_DATA = \
-       src/99-systemd.rules
-
 dbusinterface_DATA = \
        org.freedesktop.systemd1.Manager.xml \
        org.freedesktop.systemd1.Job.xml \
@@ -299,7 +318,9 @@ dist_systemunit_DATA = \
        units/quotaon.service \
        units/systemd-ask-password-wall.path \
        units/systemd-ask-password-console.path \
-       units/syslog.target
+       units/syslog.target \
+       units/udev-control.socket \
+       units/udev-kernel.socket
 
 nodist_systemunit_DATA = \
        units/getty@.service \
@@ -323,7 +344,10 @@ nodist_systemunit_DATA = \
        units/fsck@.service \
        units/fsck-root.service \
        units/rescue.service \
-       units/user@.service
+       units/user@.service \
+       units/udev.service \
+       units/udev-trigger.service \
+       units/udev-settle.service
 
 dist_userunit_DATA = \
        units/user/default.target \
@@ -356,9 +380,11 @@ EXTRA_DIST += \
        units/fsck@.service.in \
        units/fsck-root.service.in \
        units/user@.service.in \
+       units/udev.service \
+       units/udev-trigger.service \
+       units/udev-settle.service \
        src/systemd.pc.in \
        introspect.awk \
-       src/99-systemd.rules.in \
        man/custom-html.xsl
 
 if TARGET_FEDORA
@@ -422,7 +448,7 @@ endif
 
 dist_doc_DATA = \
        README \
-        NEWS \
+       NEWS \
        LICENSE \
        DISTRO_PORTING
 
@@ -535,7 +561,6 @@ EXTRA_DIST += \
 libsystemd_core_la_CFLAGS = \
        $(AM_CFLAGS) \
        $(DBUS_CFLAGS) \
-       $(UDEV_CFLAGS) \
        $(LIBWRAP_CFLAGS) \
        $(PAM_CFLAGS) \
        $(AUDIT_CFLAGS) \
@@ -543,8 +568,8 @@ libsystemd_core_la_CFLAGS = \
 
 libsystemd_core_la_LIBADD = \
        libsystemd-basic.la \
+       libudev.la \
        $(DBUS_LIBS) \
-       $(UDEV_LIBS) \
        $(LIBWRAP_LIBS) \
        $(PAM_LIBS) \
        $(AUDIT_LIBS) \
@@ -642,9 +667,9 @@ EXTRA_DIST += \
        src/spawn-agent.h \
        src/acl-util.h \
        src/logs-show.h \
-        src/utf8.h \
-        src/journal/sparse-endian.h \
-        src/ima-setup.h
+       src/utf8.h \
+       src/journal/sparse-endian.h \
+       src/ima-setup.h
 
 MANPAGES = \
        man/systemd.1 \
@@ -687,7 +712,10 @@ MANPAGES = \
        man/systemd-cat.1 \
        man/systemd-machine-id-setup.1 \
        man/journald.conf.5 \
-       man/journalctl.1
+       man/journalctl.1 \
+       man/udev.7 \
+       man/udevadm.8 \
+       man/udevd.8
 
 MANPAGES_ALIAS = \
        man/reboot.8 \
@@ -721,8 +749,7 @@ systemd_SOURCES = \
 
 systemd_CFLAGS = \
        $(AM_CFLAGS) \
-       $(DBUS_CFLAGS) \
-       $(UDEV_CFLAGS)
+       $(DBUS_CFLAGS)
 
 systemd_LDADD = \
        libsystemd-core.la
@@ -843,13 +870,9 @@ systemd_shutdown_SOURCES = \
        src/umount.c \
        src/shutdown.c
 
-systemd_shutdown_CFLAGS = \
-       $(AM_CFLAGS) \
-       $(UDEV_CFLAGS)
-
 systemd_shutdown_LDADD = \
        libsystemd-basic.la \
-       $(UDEV_LIBS)
+       libudev.la
 
 systemd_modules_load_SOURCES = \
        src/modules-load.c
@@ -887,12 +910,11 @@ systemd_fsck_SOURCES = \
 
 systemd_fsck_CFLAGS = \
        $(AM_CFLAGS) \
-       $(UDEV_CFLAGS) \
        $(DBUS_CFLAGS)
 
 systemd_fsck_LDADD = \
        libsystemd-basic.la \
-       $(UDEV_LIBS) \
+       libudev.la \
        $(DBUS_LIBS)
 
 systemd_timestamp_SOURCES = \
@@ -904,13 +926,9 @@ systemd_timestamp_LDADD = \
 systemd_ac_power_SOURCES = \
        src/ac-power.c
 
-systemd_ac_power_CFLAGS = \
-       $(AM_CFLAGS) \
-       $(UDEV_CFLAGS)
-
 systemd_ac_power_LDADD = \
        libsystemd-basic.la \
-       $(UDEV_LIBS)
+       libudev.la
 
 systemd_detect_virt_SOURCES = \
        src/detect-virt.c
@@ -1102,6 +1120,620 @@ EXTRA_DIST += \
        src/libsystemd-daemon.pc.in \
        src/libsystemd-daemon.sym
 
+# ------------------------------------------------------------------------------
+SUBDIRS += \
+       src/udev/docs
+
+include_HEADERS += \
+       src/udev/libudev.h
+
+lib_LTLIBRARIES += \
+       libudev.la
+
+noinst_LTLIBRARIES += \
+       libudev-private.la
+
+libudev_la_SOURCES =\
+       src/udev/libudev-private.h \
+       src/udev/libudev.c \
+       src/udev/libudev-list.c \
+       src/udev/libudev-util.c \
+       src/udev/libudev-device.c \
+       src/udev/libudev-enumerate.c \
+       src/udev/libudev-monitor.c \
+       src/udev/libudev-queue.c
+
+libudev_la_LDFLAGS = \
+       $(AM_LDFLAGS) \
+       -version-info $(LIBUDEV_CURRENT):$(LIBUDEV_REVISION):$(LIBUDEV_AGE)
+
+libudev_private_la_SOURCES =\
+       $(libudev_la_SOURCES) \
+       src/udev/libudev-util-private.c \
+       src/udev/libudev-device-private.c \
+       src/udev/libudev-queue-private.c \
+       src/udev/libudev-selinux-private.c
+
+libudev_private_la_LIBADD = \
+       $(SELINUX_LIBS)
+
+pkgconfiglib_DATA += \
+       src/udev/libudev.pc
+
+EXTRA_DIST += \
+       src/udev/libudev.pc.in
+
+CLEANFILES += \
+       src/udev/libudev.pc
+
+# move lib from $(libdir) to $(rootlibdir) and update devel link, if needed
+libudev-install-move-hook:
+       if test "$(libdir)" != "$(rootlibdir)"; then \
+               mkdir -p $(DESTDIR)$(rootlibdir) && \
+               so_img_name=$$(readlink $(DESTDIR)$(libdir)/libudev.so) && \
+               so_img_rel_target_prefix=$$(echo $(libdir) | sed 's,\(^/\|\)[^/][^/]*,..,g') && \
+               ln -sf $$so_img_rel_target_prefix$(rootlibdir)/$$so_img_name $(DESTDIR)$(libdir)/libudev.so && \
+               mv $(DESTDIR)$(libdir)/libudev.so.* $(DESTDIR)$(rootlibdir); \
+       fi
+
+libudev-uninstall-move-hook:
+       rm -f $(DESTDIR)$(rootlibdir)/libudev.so*
+
+INSTALL_EXEC_HOOKS += libudev-install-move-hook
+UNINSTALL_EXEC_HOOKS += libudev-uninstall-move-hook
+
+# ------------------------------------------------------------------------------
+udev-confdirs:
+       -mkdir -p $(DESTDIR)$(sysconfdir)/udev/rules.d
+       -mkdir -p $(DESTDIR)$(libexecdir)/udev/devices
+
+INSTALL_DATA_HOOKS += udev-confdirs
+
+udevrulesdir = $(libexecdir)/udev/rules.d
+dist_udevrules_DATA += \
+       rules/99-systemd.rules \
+       rules/42-usb-hid-pm.rules \
+       rules/50-udev-default.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/75-net-description.rules \
+       rules/75-tty-description.rules \
+       rules/78-sound-card.rules \
+       rules/80-drivers.rules \
+       rules/95-udev-late.rules
+
+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/udev.service.in \
+       units/udev-trigger.service.in \
+       units/udev-settle.service.in
+
+CLEANFILES += \
+       units/udev.service \
+       units/udev-trigger.service \
+       units/udev-settle.service
+
+systemd-install-hook:
+       mkdir -p $(DESTDIR)$(systemunitdir)/sockets.target.wants
+       ln -sf ../udev-control.socket $(DESTDIR)$(systemunitdir)/sockets.target.wants/udev-control.socket
+       ln -sf ../udev-kernel.socket $(DESTDIR)$(systemunitdir)/sockets.target.wants/udev-kernel.socket
+       mkdir -p $(DESTDIR)$(systemunitdir)/basic.target.wants
+       ln -sf ../udev.service $(DESTDIR)$(systemunitdir)/basic.target.wants/udev.service
+       ln -sf ../udev-trigger.service $(DESTDIR)$(systemunitdir)/basic.target.wants/udev-trigger.service
+
+INSTALL_DATA_HOOKS += systemd-install-hook
+
+bin_PROGRAMS += \
+       udevadm
+
+udevlibexec_PROGRAMS = \
+       udevd
+
+udev_common_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-blkid.c \
+       src/udev/udev-builtin-firmware.c \
+       src/udev/udev-builtin-hwdb.c \
+       src/udev/udev-builtin-input_id.c \
+       src/udev/udev-builtin-kmod.c \
+       src/udev/udev-builtin-path_id.c \
+       src/udev/udev-builtin-usb_id.c
+
+udev_common_CFLAGS = \
+       $(BLKID_CFLAGS) \
+       $(KMOD_CFLAGS)
+
+udev_common_LDADD = \
+       libudev-private.la \
+       $(BLKID_LIBS) \
+       $(KMOD_LIBS)
+
+udev_common_CPPFLAGS = \
+       $(AM_CPPFLAGS) \
+       -DFIRMWARE_PATH="$(FIRMWARE_PATH)" \
+       -DUSB_DATABASE=\"$(USB_DATABASE)\" -DPCI_DATABASE=\"$(PCI_DATABASE)\"
+
+udevd_SOURCES = \
+       $(udev_common_sources) \
+       src/udev/udevd.c \
+       src/systemd/sd-daemon.h \
+       src/sd-daemon.c
+
+udevd_CFLAGS = \
+       $(udev_common_CFLAGS)
+
+udevd_LDADD = \
+       $(udev_common_LDADD)
+
+udevd_CPPFLAGS = \
+       $(udev_common_CPPFLAGS)
+
+udevadm_SOURCES = \
+       $(udev_common_sources) \
+       src/udev/udevadm.c \
+       src/udev/udevadm-info.c \
+       src/udev/udevadm-control.c \
+       src/udev/udevadm-monitor.c \
+       src/udev/udevadm-settle.c \
+       src/udev/udevadm-trigger.c \
+       src/udev/udevadm-test.c \
+       src/udev/udevadm-test-builtin.c
+
+udevadm_CFLAGS = \
+       $(udev_common_CFLAGS)
+
+udevadm_LDADD = \
+       $(udev_common_LDADD)
+
+udevadm_CPPFLAGS = \
+       $(udev_common_CPPFLAGS)
+
+# ------------------------------------------------------------------------------
+TESTS = \
+       src/udev/test/udev-test.pl \
+       src/udev/test/rules-test.sh
+
+check_PROGRAMS = \
+       test-libudev \
+       test-udev
+
+test_libudev_SOURCES = \
+       src/udev/test-libudev.c
+
+test_libudev_LDADD = \
+       libudev.la
+
+test_udev_SOURCES = \
+       $(udev_common_sources) \
+       src/udev/test-udev.c
+
+test_udev_CFLAGS = \
+       $(udev_common_CFLAGS)
+
+test_udev_LDADD = \
+       $(udev_common_LDADD)
+
+test_udev_CPPFLAGS = \
+       $(udev_common_CPPFLAGS)
+
+test_udev_DEPENDENCIES = \
+       src/udev/test/sys
+
+# packed sysfs test tree
+src/udev/test/sys:
+       $(AM_V_GEN)mkdir -p src/udev/test && tar -C src/udev/test/ -xJf $(top_srcdir)/src/udev/test/sys.tar.xz
+
+test-sys-distclean:
+       -rm -rf src/udev/test/sys
+DISTCLEAN_LOCAL_HOOKS += test-sys-distclean
+
+EXTRA_DIST += \
+       src/udev/test/sys.tar.xz \
+       $(TESTS) \
+       src/udev/test/rule-syntax-check.py
+
+# ------------------------------------------------------------------------------
+ata_id_SOURCES = \
+       src/udev/ata_id/ata_id.c
+
+ata_id_LDADD = \
+       libudev-private.la
+
+udevlibexec_PROGRAMS += \
+       ata_id
+
+# ------------------------------------------------------------------------------
+cdrom_id_SOURCES = \
+       src/udev/cdrom_id/cdrom_id.c
+
+cdrom_id_LDADD = \
+       libudev-private.la
+
+udevlibexec_PROGRAMS += \
+       cdrom_id
+
+dist_udevrules_DATA += \
+       src/udev/cdrom_id/60-cdrom_id.rules
+
+# ------------------------------------------------------------------------------
+collect_SOURCES = \
+       src/udev/collect/collect.c
+
+collect_LDADD = \
+       libudev-private.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-private.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-private.la
+
+udevlibexec_PROGRAMS += \
+       v4l_id
+
+dist_udevrules_DATA += \
+       src/udev/v4l_id/60-persistent-v4l.rules
+
+# ------------------------------------------------------------------------------
+accelerometer_SOURCES = \
+       src/udev/accelerometer/accelerometer.c
+
+accelerometer_LDADD = \
+       libudev-private.la -lm
+
+udevlibexec_PROGRAMS += \
+       accelerometer
+
+dist_udevrules_DATA += \
+       src/udev/accelerometer/61-accelerometer.rules
+
+# ------------------------------------------------------------------------------
+if ENABLE_GUDEV
+SUBDIRS += \
+       src/udev/gudev/docs
+
+libgudev_includedir = \
+       $(includedir)/gudev-1.0/gudev
+
+libgudev_include_HEADERS = \
+       src/udev/gudev/gudev.h \
+       src/udev/gudev/gudevenums.h \
+       src/udev/gudev/gudevenumtypes.h \
+       src/udev/gudev/gudevtypes.h \
+       src/udev/gudev/gudevclient.h \
+       src/udev/gudev/gudevdevice.h \
+       src/udev/gudev/gudevenumerator.h
+
+lib_LTLIBRARIES += libgudev-1.0.la
+
+pkgconfiglib_DATA += \
+       src/udev/gudev/gudev-1.0.pc
+
+EXTRA_DIST += \
+       src/udev/gudev/gudev-1.0.pc.in
+
+CLEANFILES += \
+       src/udev/gudev/gudev-1.0.pc
+
+libgudev_1_0_la_SOURCES = \
+       src/udev/gudev/gudevenums.h \
+       src/udev/gudev/gudevenumtypes.h \
+       src/udev/gudev/gudevenumtypes.h\
+       src/udev/gudev/gudevtypes.h \
+       src/udev/gudev/gudevclient.h \
+       src/udev/gudev/gudevclient.c \
+       src/udev/gudev/gudevdevice.h \
+       src/udev/gudev/gudevdevice.c \
+       src/udev/gudev/gudevenumerator.h \
+       src/udev/gudev/gudevenumerator.c \
+       src/udev/gudev/gudevprivate.h
+
+nodist_libgudev_1_0_la_SOURCES = \
+       src/udev/gudev/gudevmarshal.h \
+       src/udev/gudev/gudevmarshal.c \
+       src/udev/gudev/gudevenumtypes.h \
+       src/udev/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/udev/gudev \
+       -I$(top_srcdir)/src/udev/gudev \
+       -D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT \
+       -D_GUDEV_COMPILATION \
+       -DG_LOG_DOMAIN=\"GUdev\"
+
+libgudev_1_0_la_CFLAGS = \
+       -fvisibility=default \
+       $(GLIB_CFLAGS)
+
+libgudev_1_0_la_LIBADD = \
+       libudev.la \
+       $(GLIB_LIBS)
+
+libgudev_1_0_la_LDFLAGS = \
+       -version-info $(LIBGUDEV_CURRENT):$(LIBGUDEV_REVISION):$(LIBGUDEV_AGE) \
+       -export-dynamic -no-undefined \
+       -export-symbols-regex '^g_udev_.*'
+
+EXTRA_DIST += \
+       src/udev/gudev/gudevmarshal.list \
+       src/udev/gudev/gudevenumtypes.h.template \
+       src/udev/gudev/gudevenumtypes.c.template \
+       src/udev/gudev/gjs-example.js \
+       src/udev/gudev/seed-example-enum.js \
+       src/udev/gudev/seed-example.js
+
+CLEANFILES += \
+       $(nodist_libgudev_1_0_la_SOURCES)
+
+src/udev/gudev/gudevmarshal.h: src/udev/gudev/gudevmarshal.list
+       $(AM_V_GEN)glib-genmarshal $< --prefix=g_udev_marshal --header > $@
+
+src/udev/gudev/gudevmarshal.c: src/udev/gudev/gudevmarshal.list
+       $(AM_V_GEN)echo "#include \"gudevmarshal.h\"" > $@ && \
+       glib-genmarshal $< --prefix=g_udev_marshal --body >> $@
+
+src/udev/gudev/gudevenumtypes.h: src/udev/gudev/gudevenumtypes.h.template src/udev/gudev/gudevenums.h
+       $(AM_V_GEN)glib-mkenums --template $^ > \
+           $@.tmp && mv $@.tmp $@
+
+src/udev/gudev/gudevenumtypes.c: src/udev/gudev/gudevenumtypes.c.template src/udev/gudev/gudevenums.h
+       $(AM_V_GEN)glib-mkenums --template $^ > \
+           $@.tmp && mv $@.tmp $@
+
+if ENABLE_INTROSPECTION
+src/udev/gudev/GUdev-1.0.gir: libgudev-1.0.la $(G_IR_SCANNER)
+       $(AM_V_GEN)$(G_IR_SCANNER) -v \
+               --warn-all \
+               --namespace GUdev \
+               --nsversion=1.0 \
+               --include=GObject-2.0 \
+               --library=gudev-1.0 \
+               --library-path=$(top_builddir)/src/udev \
+               --library-path=$(top_builddir)/src/udev/gudev \
+               --output $@ \
+               --pkg=glib-2.0 \
+               --pkg=gobject-2.0 \
+               --pkg-export=gudev-1.0 \
+               --c-include=gudev/gudev.h \
+               -I$(top_srcdir)/src/udev \
+               -I$(top_builddir)/src/udev \
+               -D_GUDEV_COMPILATION \
+               -D_GUDEV_WORK_AROUND_DEV_T_BUG \
+               $(top_srcdir)/src/udev/gudev/gudev.h \
+               $(top_srcdir)/src/udev/gudev/gudevtypes.h \
+               $(top_srcdir)/src/udev/gudev/gudevenums.h \
+               $(or $(wildcard $(top_builddir)/src/udev/gudev/gudevenumtypes.h),$(top_srcdir)/src/udev/gudev/gudevenumtypes.h) \
+               $(top_srcdir)/src/udev/gudev/gudevclient.h \
+               $(top_srcdir)/src/udev/gudev/gudevdevice.h \
+               $(top_srcdir)/src/udev/gudev/gudevenumerator.h \
+               $(top_srcdir)/src/udev/gudev/gudevclient.c \
+               $(top_srcdir)/src/udev/gudev/gudevdevice.c \
+               $(top_srcdir)/src/udev/gudev/gudevenumerator.c
+
+src/udev/gudev/GUdev-1.0.typelib: src/udev/gudev/GUdev-1.0.gir $(G_IR_COMPILER)
+       $(AM_V_GEN)g-ir-compiler $< -o $@
+
+girdir = $(GIRDIR)
+gir_DATA = \
+       src/udev/gudev/GUdev-1.0.gir
+
+typelibsdir = $(GIRTYPELIBDIR)
+typelibs_DATA = \
+       src/udev/gudev/GUdev-1.0.typelib
+
+CLEANFILES += $(gir_DATA) $(typelibs_DATA)
+endif # ENABLE_INTROSPECTION
+
+# move lib from $(libdir) to $(rootlibdir) and update devel link, if needed
+libgudev-install-move-hook:
+       if test "$(libdir)" != "$(rootlibdir)"; then \
+               mkdir -p $(DESTDIR)$(rootlibdir) && \
+               so_img_name=$$(readlink $(DESTDIR)$(libdir)/libgudev-1.0.so) && \
+               so_img_rel_target_prefix=$$(echo $(libdir) | sed 's,\(^/\|\)[^/][^/]*,..,g') && \
+               ln -sf $$so_img_rel_target_prefix$(rootlibdir)/$$so_img_name $(DESTDIR)$(libdir)/libgudev-1.0.so && \
+               mv $(DESTDIR)$(libdir)/libgudev-1.0.so.* $(DESTDIR)$(rootlibdir); \
+       fi
+
+libgudev-uninstall-move-hook:
+       rm -f $(DESTDIR)$(rootlibdir)/libgudev-1.0.so*
+
+INSTALL_EXEC_HOOKS += libgudev-install-move-hook
+UNINSTALL_EXEC_HOOKS += libgudev-uninstall-move-hook
+endif
+
+# ------------------------------------------------------------------------------
+if ENABLE_KEYMAP
+keymap_SOURCES = \
+       src/udev/keymap/keymap.c
+
+keymap_CPPFLAGS = \
+       $(AM_CPPFLAGS) -I src/udev/keymap
+
+nodist_keymap_SOURCES = \
+       src/udev/keymap/keys-from-name.h \
+       src/udev/keymap/keys-to-name.h
+
+BUILT_SOURCES += \
+       $(nodist_keymap_SOURCES)
+
+udevlibexec_PROGRAMS += \
+       keymap
+
+dist_doc_DATA += \
+       src/udev/keymap/README.keymap.txt
+
+dist_udevrules_DATA += \
+       src/udev/keymap/95-keymap.rules \
+       src/udev/keymap/95-keyboard-force-release.rules
+
+dist_udevhome_SCRIPTS += \
+       src/udev/keymap/findkeyboards
+
+udevhome_SCRIPTS += \
+       src/udev/keymap/keyboard-force-release.sh
+
+EXTRA_DIST += \
+       src/udev/keymap/check-keymaps.sh \
+       src/udev/keymap/keyboard-force-release.sh.in
+
+CLEANFILES += \
+       $(nodist_keymap_SOURCES) \
+       src/udev/keymap/keys.txt \
+       src/udev/keymap/keys-from-name.gperf \
+       src/udev/keymap/keyboard-force-release.sh
+
+udevkeymapdir = $(libexecdir)/udev/keymaps
+dist_udevkeymap_DATA = \
+       src/udev/keymap/keymaps/acer \
+       src/udev/keymap/keymaps/acer-aspire_5720 \
+       src/udev/keymap/keymaps/acer-aspire_8930 \
+       src/udev/keymap/keymaps/acer-aspire_5920g \
+       src/udev/keymap/keymaps/acer-aspire_6920 \
+       src/udev/keymap/keymaps/acer-travelmate_c300 \
+       src/udev/keymap/keymaps/asus \
+       src/udev/keymap/keymaps/compaq-e_evo \
+       src/udev/keymap/keymaps/dell \
+       src/udev/keymap/keymaps/dell-latitude-xt2 \
+       src/udev/keymap/keymaps/everex-xt5000 \
+       src/udev/keymap/keymaps/fujitsu-amilo_li_2732 \
+       src/udev/keymap/keymaps/fujitsu-amilo_pa_2548 \
+       src/udev/keymap/keymaps/fujitsu-amilo_pro_edition_v3505 \
+       src/udev/keymap/keymaps/fujitsu-amilo_pro_v3205 \
+       src/udev/keymap/keymaps/fujitsu-amilo_si_1520 \
+       src/udev/keymap/keymaps/fujitsu-esprimo_mobile_v5 \
+       src/udev/keymap/keymaps/fujitsu-esprimo_mobile_v6 \
+       src/udev/keymap/keymaps/genius-slimstar-320 \
+       src/udev/keymap/keymaps/hewlett-packard \
+       src/udev/keymap/keymaps/hewlett-packard-2510p_2530p \
+       src/udev/keymap/keymaps/hewlett-packard-compaq_elitebook \
+       src/udev/keymap/keymaps/hewlett-packard-pavilion \
+       src/udev/keymap/keymaps/hewlett-packard-presario-2100 \
+       src/udev/keymap/keymaps/hewlett-packard-tablet \
+       src/udev/keymap/keymaps/hewlett-packard-tx2 \
+       src/udev/keymap/keymaps/ibm-thinkpad-usb-keyboard-trackpoint \
+       src/udev/keymap/keymaps/inventec-symphony_6.0_7.0 \
+       src/udev/keymap/keymaps/lenovo-3000 \
+       src/udev/keymap/keymaps/lenovo-ideapad \
+       src/udev/keymap/keymaps/lenovo-thinkpad-usb-keyboard-trackpoint \
+       src/udev/keymap/keymaps/lenovo-thinkpad_x6_tablet \
+       src/udev/keymap/keymaps/lenovo-thinkpad_x200_tablet \
+       src/udev/keymap/keymaps/lg-x110 \
+       src/udev/keymap/keymaps/logitech-wave \
+       src/udev/keymap/keymaps/logitech-wave-cordless \
+       src/udev/keymap/keymaps/logitech-wave-pro-cordless \
+       src/udev/keymap/keymaps/maxdata-pro_7000 \
+       src/udev/keymap/keymaps/medion-fid2060 \
+       src/udev/keymap/keymaps/medionnb-a555 \
+       src/udev/keymap/keymaps/micro-star \
+       src/udev/keymap/keymaps/module-asus-w3j \
+       src/udev/keymap/keymaps/module-ibm \
+       src/udev/keymap/keymaps/module-lenovo \
+       src/udev/keymap/keymaps/module-sony \
+       src/udev/keymap/keymaps/module-sony-old \
+       src/udev/keymap/keymaps/module-sony-vgn \
+       src/udev/keymap/keymaps/olpc-xo \
+       src/udev/keymap/keymaps/onkyo \
+       src/udev/keymap/keymaps/oqo-model2 \
+       src/udev/keymap/keymaps/samsung-other \
+       src/udev/keymap/keymaps/samsung-90x3a \
+       src/udev/keymap/keymaps/samsung-sq1us \
+       src/udev/keymap/keymaps/samsung-sx20s \
+       src/udev/keymap/keymaps/toshiba-satellite_a100 \
+       src/udev/keymap/keymaps/toshiba-satellite_a110 \
+       src/udev/keymap/keymaps/toshiba-satellite_m30x \
+       src/udev/keymap/keymaps/zepto-znote
+
+udevkeymapforcereldir = $(libexecdir)/udev/keymaps/force-release
+dist_udevkeymapforcerel_DATA = \
+       src/udev/keymap/force-release-maps/dell-touchpad \
+       src/udev/keymap/force-release-maps/hp-other \
+       src/udev/keymap/force-release-maps/samsung-other \
+       src/udev/keymap/force-release-maps/samsung-90x3a \
+       src/udev/keymap/force-release-maps/common-volume-keys
+
+src/udev/keymap/keys.txt: $(INCLUDE_PREFIX)/linux/input.h
+       $(AM_V_at)mkdir -p src/keymap
+       $(AM_V_GEN)$(AWK) '/^#define.*KEY_[^ ]+[ \t]+[0-9]/ { if ($$2 != "KEY_MAX") { print $$2 } }' < $< | sed 's/^KEY_COFFEE$$/KEY_SCREENLOCK/' > $@
+
+src/udev/keymap/keys-from-name.gperf: src/udev/keymap/keys.txt
+       $(AM_V_GEN)$(AWK) 'BEGIN{ print "struct key { const char* name; unsigned short id; };"; print "%null-strings"; print "%%";} { print $$1 ", " $$1 }' < $< > $@
+
+src/udev/keymap/keys-from-name.h: src/udev/keymap/keys-from-name.gperf Makefile
+       $(AM_V_GEN)$(GPERF) -L ANSI-C -t --ignore-case -N lookup_key -H hash_key_name -p -C < $< > $@
+
+src/udev/keymap/keys-to-name.h: src/udev/keymap/keys.txt Makefile
+       $(AM_V_GEN)$(AWK) 'BEGIN{ print "const char* const key_names[KEY_CNT] = { "} { print "[" $$1 "] = \"" $$1 "\"," } END{print "};"}' < $< > $@
+
+keymaps-distcheck-hook: src/udev/keymap/keys.txt
+       $(top_srcdir)/src/udev/keymap/check-keymaps.sh $(top_srcdir) $^
+DISTCHECK_HOOKS += keymaps-distcheck-hook
+endif
+
+# ------------------------------------------------------------------------------
+mtd_probe_SOURCES =  \
+       src/udev/mtd_probe/mtd_probe.c \
+       src/udev/mtd_probe/mtd_probe.h \
+       src/udev/mtd_probe/probe_smartmedia.c
+
+mtd_probe_CPPFLAGS = \
+       $(AM_CPPFLAGS)
+
+dist_udevrules_DATA += \
+       src/udev/mtd_probe/75-probe_mtd.rules
+
+udevlibexec_PROGRAMS += \
+       mtd_probe
+
 # ------------------------------------------------------------------------------
 libsystemd_id128_la_SOURCES = \
        src/sd-id128.c
@@ -1467,24 +2099,16 @@ systemd_readahead_collect_SOURCES = \
 systemd_readahead_collect_LDADD = \
        libsystemd-basic.la \
        libsystemd-daemon.la \
-       $(UDEV_LIBS)
-
-systemd_readahead_collect_CFLAGS = \
-       $(AM_CFLAGS) \
-       $(UDEV_CFLAGS)
+       libudev.la
 
 systemd_readahead_replay_SOURCES = \
        src/readahead/readahead-replay.c \
        src/readahead/readahead-common.c
 
-systemd_readahead_replay_CFLAGS = \
-       $(AM_CFLAGS) \
-       $(UDEV_CFLAGS)
-
 systemd_readahead_replay_LDADD = \
        libsystemd-basic.la \
        libsystemd-daemon.la \
-       $(UDEV_LIBS)
+       libudev.la
 
 rootlibexec_PROGRAMS += \
        systemd-readahead-collect \
@@ -1579,12 +2203,11 @@ systemd_cryptsetup_SOURCES = \
 
 systemd_cryptsetup_CFLAGS = \
        $(AM_CFLAGS) \
-       $(LIBCRYPTSETUP_CFLAGS) \
-       $(UDEV_CFLAGS)
+       $(LIBCRYPTSETUP_CFLAGS)
 
 systemd_cryptsetup_LDADD = \
        $(LIBCRYPTSETUP_LIBS) \
-       $(UDEV_LIBS) \
+       libudev.la \
        libsystemd-basic.la
 
 systemd_cryptsetup_generator_SOURCES = \
@@ -1797,14 +2420,13 @@ endif
 systemd_logind_CFLAGS = \
        $(AM_CFLAGS) \
        $(DBUS_CFLAGS) \
-       $(UDEV_CFLAGS) \
        $(ACL_CFLAGS)
 
 systemd_logind_LDADD = \
        libsystemd-basic.la \
        libsystemd-daemon.la \
+       libudev.la \
        $(DBUS_LIBS) \
-       $(UDEV_LIBS) \
        $(ACL_LIBS)
 
 systemd_user_sessions_SOURCES = \
@@ -1828,13 +2450,12 @@ loginctl_SOURCES = \
 
 loginctl_CFLAGS = \
        $(AM_CFLAGS) \
-       $(DBUS_CFLAGS) \
-       $(UDEV_CFLAGS)
+       $(DBUS_CFLAGS)
 
 loginctl_LDADD = \
        libsystemd-basic.la \
-       $(DBUS_LIBS) \
-       $(UDEV_LIBS)
+       libudev.la \
+       $(DBUS_LIBS)
 
 rootbin_PROGRAMS += \
        loginctl
@@ -1955,13 +2576,9 @@ INSTALL_DATA_HOOKS += \
 systemd_multi_seat_x_SOURCES = \
        src/login/multi-seat-x.c
 
-systemd_multi_seat_x_CFLAGS = \
-       $(AM_CFLAGS) \
-       $(UDEV_CFLAGS)
-
 systemd_multi_seat_x_LDADD = \
        libsystemd-basic.la \
-       $(UDEV_LIBS)
+       libudev.la
 
 rootlibexec_PROGRAMS += \
        systemd-multi-seat-x
@@ -1977,14 +2594,13 @@ endif
 
 systemd_uaccess_CFLAGS = \
        $(AM_CFLAGS) \
-       $(UDEV_CFLAGS) \
        $(ACL_CFLAGS)
 
 systemd_uaccess_LDADD = \
        libsystemd-basic.la \
        libsystemd-daemon.la \
        libsystemd-login.la \
-       $(UDEV_LIBS) \
+       libudev.la \
        $(ACL_LIBS)
 
 rootlibexec_PROGRAMS += \
@@ -2088,6 +2704,9 @@ SED_PROCESS = \
                -e 's,@exec_prefix\@,$(exec_prefix),g' \
                -e 's,@libdir\@,$(libdir),g' \
                -e 's,@includedir\@,$(includedir),g' \
+               -e 's,@VERSION\@,$(VERSION),g' \
+               -e 's,@rootprefix\@,$(rootprefix),g' \
+               -e 's,@udevlibexecdir\@,$(libexecdir)/udev,g' \
                < $< > $@ || rm $@
 
 units/%: units/%.in Makefile
@@ -2105,9 +2724,13 @@ sysctl.d/%: sysctl.d/%.in Makefile
 src/%.policy.in: src/%.policy.in.in Makefile
        $(SED_PROCESS)
 
-src/%.rules: src/%.rules.in Makefile
+%.rules: %.rules.in Makefile
        $(SED_PROCESS)
 
+%.sh: %.sh.in Makefile
+       $(SED_PROCESS)
+       $(AM_V_GEN)chmod +x $@
+
 src/%.c: src/%.gperf
        $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \
        $(GPERF) < $< > $@
@@ -2143,8 +2766,7 @@ CLEANFILES += \
        $(nodist_polkitpolicy_DATA) \
        src/load-fragment-gperf.gperf \
        src/load-fragment-gperf.c \
-       src/load-fragment-gperf-nulstr.c \
-       src/99-systemd.rules
+       src/load-fragment-gperf-nulstr.c
 
 if HAVE_XSLTPROC
 XSLTPROC_FLAGS = \
@@ -2424,15 +3046,19 @@ uninstall-hook: $(UNINSTALL_EXEC_HOOKS)
 
 install-data-hook: systemd-install-data-hook $(INSTALL_DATA_HOOKS)
 
+distcheck-hook: $(DISTCHECK_HOOKS)
+
+distclean-local: $(DISTCLEAN_LOCAL_HOOKS)
+
 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-pamlibdir=$$dc_install_base/$(pamlibdir) \
-        --with-rootprefix=$$dc_install_base \
-        --disable-split-usr
+       --with-rootprefix=$$dc_install_base \
+       --disable-split-usr \
+       --enable-gtk-doc
 
 upload: all distcheck
        cp -v systemd-$(VERSION).tar.xz /home/lennart/git.fedora/systemd/
diff --git a/TODO b/TODO
index 4f3b157040c0515152fe1ea979f3c7151241fdc3..c12190e58c20c77de42062da23ce5273b3f046aa 100644 (file)
--- a/TODO
+++ b/TODO
@@ -342,3 +342,28 @@ Regularly:
 * pahole
 
 * set_put(), hashmap_put() return values check. i.e. == 0 doesn't free()!
+
+udev:
+ - find a way to tell udev to not cancel firmware
+   requests in initramfs
+
+ - scsi_id -> sg3_utils?
+
+ - make gtk-doc optional like kmod
+
+ - move /usr/lib/udev/devices/ to tmpfiles
+
+ - trigger --subsystem-match=usb/usb_device
+
+ - kill rules_generator
+
+ - have a $attrs{} ?
+
+ - remove RUN+="socket:"
+
+ - libudev.so.1
+     - symbol versioning
+     - return object with *_unref()
+     - udev_monitor_from_socket()
+     - udev_queue_get_failed_list_entry()
+
index 9ca53772a4dd8cebb92712635c1cc481f0701274..fba3dc08b84666f04d916b5d3464db50ff086bfb 100755 (executable)
@@ -21,6 +21,7 @@ if [ -f .git/hooks/pre-commit.sample -a ! -f .git/hooks/pre-commit ] ; then
     echo "Activated pre-commit hook."
 fi
 
+gtkdocize
 intltoolize --force --automake
 autoreconf --force --install --symlink
 
@@ -32,7 +33,8 @@ args="\
 --sysconfdir=/etc \
 --localstatedir=/var \
 --libdir=$(libdir /usr/lib) \
---libexecdir=/usr/lib"
+--libexecdir=/usr/lib \
+--enable-gtk-doc"
 
 if [ ! -L /bin ]; then
 args="$args \
index 9a9a7892355442b040c3cdab23a43795aaf52ab0..9baebef1cf1d51f500eec5d1424eb98ebb479465 100644 (file)
@@ -1,6 +1,7 @@
 #  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
@@ -18,6 +19,7 @@
 AC_PREREQ(2.63)
 
 AC_INIT([systemd],[44],[systemd-devel@lists.freedesktop.org])
+AC_SUBST(PACKAGE_URL, [http://www.freedesktop.org/wiki/Software/systemd])
 AC_CONFIG_SRCDIR([src/main.c])
 AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_HEADERS([config.h])
@@ -25,16 +27,15 @@ AC_USE_SYSTEM_EXTENSIONS
 AC_SYS_LARGEFILE
 AC_PREFIX_DEFAULT([/usr])
 AM_INIT_AUTOMAKE([foreign 1.11 -Wall -Wno-portability silent-rules tar-pax no-dist-gzip dist-xz subdir-objects check-news])
-
-AC_SUBST(PACKAGE_URL, [http://www.freedesktop.org/wiki/Software/systemd])
-
+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])
+LT_PREREQ(2.2)
+LT_INIT
 
 # i18n stuff for the PolicyKit policy files
 IT_PROG_INTLTOOL([0.40.0])
@@ -53,6 +54,9 @@ AC_PROG_CC_C99
 AM_PROG_CC_C_O
 AC_PROG_GCC_TRADITIONAL
 
+AC_PATH_PROG([M4], [m4])
+GTK_DOC_CHECK(1.10)
+
 AC_CHECK_TOOL(OBJCOPY, objcopy)
 AC_CHECK_TOOL(STRINGS, strings)
 AC_CHECK_TOOL(GPERF, gperf)
@@ -110,9 +114,6 @@ CC_CHECK_FLAGS_APPEND([with_ldflags], [LDFLAGS], [\
         -Wl,--gc-sections])
 AC_SUBST([GCLDFLAGS], $with_ldflags)
 
-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])])
 
@@ -127,10 +128,11 @@ AC_SUBST(CAP_LIBS)
 # 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 >= 172 ])
-PKG_CHECK_MODULES(DBUS, [ dbus-1 >= 1.3.2 ])
-PKG_CHECK_MODULES(KMOD, [ libkmod >= 5 ])
+PKG_CHECK_MODULES(DBUS, [dbus-1 >= 1.3.2])
+PKG_CHECK_MODULES(KMOD, [libkmod >= 5])
+PKG_CHECK_MODULES(BLKID,[blkid >= 2.20])
 
+# ------------------------------------------------------------------------------
 have_ima=yes
 AC_ARG_ENABLE([ima], AS_HELP_STRING([--disable-ima],[Disable optional IMA support]),
                 [case "${enableval}" in
@@ -144,6 +146,7 @@ if test "x${have_ima}" != xno ; then
         AC_DEFINE(HAVE_IMA, 1, [Define if IMA 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
@@ -155,6 +158,7 @@ if test "x$enable_selinux" != "xno"; then
 fi
 AM_CONDITIONAL(HAVE_SELINUX, [test "$have_selinux" = "yes"])
 
+# ------------------------------------------------------------------------------
 have_xz=no
 AC_ARG_ENABLE(xz, AS_HELP_STRING([--disable-xz], [Disable optional XZ support]))
 if test "x$enable_xz" != "xno"; then
@@ -166,6 +170,7 @@ if test "x$enable_xz" != "xno"; then
 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
@@ -190,6 +195,7 @@ else
 fi
 AC_SUBST(LIBWRAP_LIBS)
 
+# ------------------------------------------------------------------------------
 AC_ARG_ENABLE([pam],
         AS_HELP_STRING([--disable-pam],[Disable optional PAM support]),
                 [case "${enableval}" in
@@ -227,6 +233,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
@@ -264,6 +271,7 @@ fi
 AC_SUBST(ACL_LIBS)
 AM_CONDITIONAL([HAVE_ACL], [test "x$have_acl" != xno])
 
+# ------------------------------------------------------------------------------
 AC_ARG_ENABLE([audit],
         AS_HELP_STRING([--disable-audit],[Disable optional AUDIT support]),
                 [case "${enableval}" in
@@ -300,6 +308,7 @@ 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
@@ -311,6 +320,7 @@ if test "x$enable_libcryptsetup" != "xno"; then
 fi
 AM_CONDITIONAL(HAVE_LIBCRYPTSETUP, [test "$have_libcryptsetup" = "yes"])
 
+# ------------------------------------------------------------------------------
 have_binfmt=no
 AC_ARG_ENABLE(binfmt, AS_HELP_STRING([--disable-binfmt], [disable binfmt tool]))
 if test "x$enable_binfmt" != "xno"; then
@@ -318,6 +328,7 @@ if test "x$enable_binfmt" != "xno"; then
 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
@@ -325,6 +336,7 @@ if test "x$enable_vconsole" != "xno"; then
 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
@@ -332,6 +344,7 @@ if test "x$enable_readahead" != "xno"; then
 fi
 AM_CONDITIONAL(ENABLE_READAHEAD, [test "$have_readahead" = "yes"])
 
+# ------------------------------------------------------------------------------
 have_quotacheck=no
 AC_ARG_ENABLE(quotacheck, AS_HELP_STRING([--disable-quotacheck], [disable quotacheck tools]))
 if test "x$enable_quotacheck" != "xno"; then
@@ -339,6 +352,7 @@ if test "x$enable_quotacheck" != "xno"; then
 fi
 AM_CONDITIONAL(ENABLE_QUOTACHECK, [test "$have_quotacheck" = "yes"])
 
+# ------------------------------------------------------------------------------
 have_randomseed=no
 AC_ARG_ENABLE(randomseed, AS_HELP_STRING([--disable-randomseed], [disable randomseed tools]))
 if test "x$enable_randomseed" != "xno"; then
@@ -346,6 +360,7 @@ if test "x$enable_randomseed" != "xno"; then
 fi
 AM_CONDITIONAL(ENABLE_RANDOMSEED, [test "$have_randomseed" = "yes"])
 
+# ------------------------------------------------------------------------------
 have_logind=no
 AC_ARG_ENABLE(logind, AS_HELP_STRING([--disable-logind], [disable login daemon]))
 if test "x$enable_logind" != "xno"; then
@@ -354,6 +369,7 @@ fi
 AM_CONDITIONAL(ENABLE_LOGIND, [test "$have_logind" = "yes"])
 AS_IF([test "$have_logind" = "yes"], [ AC_DEFINE(HAVE_LOGIND, [1], [Logind support available]) ])
 
+# ------------------------------------------------------------------------------
 have_hostnamed=no
 AC_ARG_ENABLE(hostnamed, AS_HELP_STRING([--disable-hostnamed], [disable hostname daemon]))
 if test "x$enable_hostnamed" != "xno"; then
@@ -361,6 +377,7 @@ if test "x$enable_hostnamed" != "xno"; then
 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
@@ -368,6 +385,7 @@ if test "x$enable_timedated" != "xno"; then
 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
@@ -375,6 +393,7 @@ if test "x$enable_localed" != "xno"; then
 fi
 AM_CONDITIONAL(ENABLE_LOCALED, [test "$have_localed" = "yes"])
 
+# ------------------------------------------------------------------------------
 have_coredump=no
 AC_ARG_ENABLE(coredump, AS_HELP_STRING([--disable-coredump], [disable coredump hook]))
 if test "x$enable_coredump" != "xno"; then
@@ -382,6 +401,92 @@ if test "x$enable_coredump" != "xno"; then
 fi
 AM_CONDITIONAL(ENABLE_COREDUMP, [test "$have_coredump" = "yes"])
 
+# ------------------------------------------------------------------------------
+if test "x$cross_compiling" = "xno" ; then
+       AC_CHECK_FILES([/usr/share/pci.ids], [pciids=/usr/share/pci.ids])
+       AC_CHECK_FILES([/usr/share/hwdata/pci.ids], [pciids=/usr/share/hwdata/pci.ids])
+       AC_CHECK_FILES([/usr/share/misc/pci.ids], [pciids=/usr/share/misc/pci.ids])
+fi
+
+AC_ARG_WITH(usb-ids-path,
+       [AS_HELP_STRING([--with-usb-ids-path=DIR], [Path to usb.ids file])],
+       [USB_DATABASE=${withval}],
+       [if test -n "$usbids" ; then
+              USB_DATABASE="$usbids"
+       else
+              PKG_CHECK_MODULES(USBUTILS, usbutils >= 0.82)
+              AC_SUBST([USB_DATABASE], [$($PKG_CONFIG --variable=usbids usbutils)])
+       fi])
+AC_MSG_CHECKING([for USB database location])
+AC_MSG_RESULT([$USB_DATABASE])
+AC_SUBST(USB_DATABASE)
+
+AC_ARG_WITH(pci-ids-path,
+       [AS_HELP_STRING([--with-pci-ids-path=DIR], [Path to pci.ids file])],
+       [PCI_DATABASE=${withval}],
+       [if test -n "$pciids" ; then
+              PCI_DATABASE="$pciids"
+       else
+              AC_MSG_ERROR([pci.ids not found, try --with-pci-ids-path=])
+       fi])
+AC_MSG_CHECKING([for PCI database location])
+AC_MSG_RESULT([$PCI_DATABASE])
+AC_SUBST(PCI_DATABASE)
+
+# ------------------------------------------------------------------------------
+AC_ARG_WITH(firmware-path,
+       AS_HELP_STRING([--with-firmware-path=DIR[[[:DIR[...]]]]],
+          [Firmware search path (default=ROOTPREFIX/lib/firmware/updates:ROOTPREFIX/lib/firmware)]),
+       [], [with_firmware_path="$rootprefix/lib/firmware/updates:$rootprefix/lib/firmware"])
+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], [$FIRMWARE_PATH])
+
+# ------------------------------------------------------------------------------
+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]) ])
+
+AC_ARG_ENABLE([introspection],
+       AS_HELP_STRING([--disable-introspection], [disable GObject introspection @<:@default=enabled@:>@]),
+       [], [enable_introspection=yes])
+AS_IF([test "x$enable_introspection" = "xyes"], [
+       PKG_CHECK_MODULES([INTROSPECTION], [gobject-introspection-1.0 >= 0.6.2])
+       AC_DEFINE([ENABLE_INTROSPECTION], [1], [enable GObject introspection support])
+       AC_SUBST([G_IR_SCANNER], [$($PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0)])
+       AC_SUBST([G_IR_COMPILER], [$($PKG_CONFIG --variable=g_ir_compiler gobject-introspection-1.0)])
+       AC_SUBST([G_IR_GENERATE], [$($PKG_CONFIG --variable=g_ir_generate gobject-introspection-1.0)])
+       AC_SUBST([GIRDIR], [$($PKG_CONFIG --define-variable=datadir=${datadir} --variable=girdir gobject-introspection-1.0)])
+       AC_SUBST([GIRTYPELIBDIR], [$($PKG_CONFIG --define-variable=libdir=${libdir} --variable=typelibdir gobject-introspection-1.0)])
+])
+AM_CONDITIONAL([ENABLE_INTROSPECTION], [test "x$enable_introspection" = "xyes"])
+AM_CONDITIONAL([ENABLE_GUDEV], [test "x$enable_gudev" = "xyes"])
+
+# ------------------------------------------------------------------------------
+AC_ARG_ENABLE([keymap],
+       AS_HELP_STRING([--disable-keymap], [disable keymap fixup support @<:@default=enabled@:>@]),
+       [], [enable_keymap=yes])
+AS_IF([test "x$enable_keymap" = "xyes"], [
+       AC_PATH_PROG([GPERF], [gperf])
+       if test -z "$GPERF"; then
+              AC_MSG_ERROR([gperf is needed])
+       fi
+
+       AC_CHECK_HEADER([linux/input.h], [:], AC_MSG_ERROR([kernel headers not found]))
+       AC_SUBST([INCLUDE_PREFIX], [$(echo '#include <linux/input.h>' | eval $ac_cpp -E - | sed -n '/linux\/input.h/ {s:.*"\(.*\)/linux/input.h".*:\1:; p; q}')])
+])
+AM_CONDITIONAL([ENABLE_KEYMAP], [test "x$enable_keymap" = "xyes"])
+
+# ------------------------------------------------------------------------------
 have_manpages=no
 AC_ARG_ENABLE(manpages, AS_HELP_STRING([--disable-manpages], [disable manpages]))
 if test "x$enable_manpages" != "xno"; then
@@ -389,11 +494,10 @@ if test "x$enable_manpages" != "xno"; then
 fi
 AM_CONDITIONAL(ENABLE_MANPAGES, [test "$have_manpages" = "yes"])
 
+# ------------------------------------------------------------------------------
 AC_PATH_PROG([XSLTPROC], [xsltproc])
 AM_CONDITIONAL(HAVE_XSLTPROC, test x"$XSLTPROC" != x)
 
-AC_PATH_PROG([M4], [m4])
-
 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, mandriva, meego, mageia, angstrom or other]))
 if test "z$with_distro" = "z"; then
         if test "$cross_compiling" = yes; then
@@ -572,11 +676,6 @@ AC_ARG_WITH([dbusinterfacedir],
         [],
         [with_dbusinterfacedir=`pkg-config --variable=session_bus_services_dir dbus-1`/../interfaces])
 
-AC_ARG_WITH([udevrulesdir],
-        AS_HELP_STRING([--with-udevrulesdir=DIR], [Directory for udev rules]),
-        [],
-        [with_udevrulesdir=`pkg-config --variable=udevdir udev`/rules.d])
-
 AC_ARG_WITH([rootprefix],
         AS_HELP_STRING([--with-rootprefix=DIR], [rootfs directory prefix for config files and kernel modules]),
         [], [with_rootprefix=${ac_default_prefix}])
@@ -608,12 +707,18 @@ 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([pamlibdir], [$with_pamlibdir])
 AC_SUBST([rootprefix], [$with_rootprefix])
 AC_SUBST([rootlibdir], [$with_rootlibdir])
 
-AC_CONFIG_FILES([Makefile po/Makefile.in])
+AC_CONFIG_FILES([
+        Makefile po/Makefile.in
+        src/udev/docs/Makefile
+        src/udev/docs/version.xml
+        src/udev/gudev/docs/Makefile
+        src/udev/gudev/docs/version.xml
+])
+
 AC_OUTPUT
 AC_MSG_RESULT([
         $PACKAGE_NAME $VERSION
@@ -641,13 +746,23 @@ AC_MSG_RESULT([
         localed:                 ${have_localed}
         coredump:                ${have_coredump}
         plymouth:                ${have_plymouth}
+        firmware path:           ${FIRMWARE_PATH}
+        usb.ids:                 ${USB_DATABASE}
+        pci.ids:                 ${PCI_DATABASE}
+        gudev:                   ${enable_gudev}
+        gintrospection:          ${enable_introspection}
+        keymap:                  ${enable_keymap}
+
         prefix:                  ${prefix}
         rootprefix:              ${with_rootprefix}
+        sysconf dir:             ${sysconfdir}
+        datarootdir:             ${datarootdir}
+        includedir:              ${includedir}
+        include_prefix:          ${INCLUDE_PREFIX}
         libexec dir:             ${libexecdir}
         lib dir:                 ${libdir}
         rootlib dir:             ${with_rootlibdir}
         PAM modules dir:         ${with_pamlibdir}
-        udev rules dir:          ${with_udevrulesdir}
         D-Bus policy dir:        ${with_dbuspolicydir}
         D-Bus session dir:       ${with_dbussessionservicedir}
         D-Bus system dir:        ${with_dbussystemservicedir}
index 55eaa803a1b3a698c8703828dc8ddc6545d360c0..cf35a86e88329b6ee74c2c2132a1e3282fc4df74 100644 (file)
@@ -4,3 +4,4 @@ ltoptions.m4
 ltsugar.m4
 ltversion.m4
 lt~obsolete.m4
+gtk-doc.m4
diff --git a/man/udev.xml b/man/udev.xml
new file mode 100644 (file)
index 0000000..8eb583a
--- /dev/null
@@ -0,0 +1,695 @@
+<?xml version='1.0'?>
+<?xml-stylesheet type="text/xsl" href="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<refentry id="udev">
+  <refentryinfo>
+    <title>udev</title>
+    <productname>udev</productname>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>udev</refentrytitle>
+    <manvolnum>7</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>udev</refname>
+    <refpurpose>Linux dynamic device management</refpurpose>
+  </refnamediv>
+
+  <refsect1><title>Description</title>
+    <para>udev supplies the system software with device events, manages permissions
+    of device nodes and may create additional symlinks in the <filename>/dev</filename>
+    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.</para>
+
+    <para>The udev daemon, <citerefentry><refentrytitle>udevd</refentrytitle>
+    <manvolnum>8</manvolnum></citerefentry>, 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.</para>
+
+    <para>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.</para>
+  </refsect1>
+
+  <refsect1><title>Configuration</title>
+    <para>udev configuration files are placed in <filename>/etc/udev</filename>
+    and <filename>/usr/lib/udev</filename>. All empty lines or lines beginning with
+    '#' are ignored.</para>
+
+    <refsect2><title>Configuration file</title>
+      <para>udev expects its main configuration file at <filename>/etc/udev/udev.conf</filename>.
+      It consists of a set of variables allowing the user to override default udev values.
+      The following variables can be set:</para>
+      <variablelist>
+        <varlistentry>
+          <term><option>udev_root</option></term>
+          <listitem>
+            <para>Specifies where to place the device nodes in the filesystem.
+            The default value is <filename>/dev</filename>.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>udev_log</option></term>
+          <listitem>
+            <para>The logging priority. Valid values are the numerical syslog priorities
+            or their textual representations: <option>err</option>, <option>info</option>
+            and <option>debug</option>.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2><title>Rules files</title>
+      <para>The udev rules are read from the files located in the
+      system rules directory <filename>/usr/lib/udev/rules.d</filename>,
+      the volatile runtime directory <filename>/run/udev/rules.d</filename>
+      and the local administration directory <filename>/etc/udev/rules.d</filename>.
+      All rules files are collectively sorted and processed in lexical order,
+      regardless of the directories in which they live. However, files with
+      identical file names replace each other. Files in <filename>/etc</filename>
+      have the highest priority, files in <filename>/run</filename> take precedence
+      over files with the same name in <filename>/lib</filename>. This can be
+      used to override a system-supplied rules file with a local file if needed;
+      a symlink in <filename>/etc</filename> with the same name as a rules file in
+      <filename>/lib</filename>, pointing to <filename>/dev/null</filename>,
+      disables the rules file entirely.</para>
+
+      <para>Rule files must have the extension <filename>.rules</filename>; other
+      extensions are ignored.</para>
+
+      <para>Every line in the rules file contains at least one key-value pair.
+      There are two kind of keys: match and assignment.
+      If all match keys are matching against its value, the rule gets applied and the
+      assignment keys get the specified value assigned.</para>
+
+      <para>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.</para>
+
+      <para>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:</para>
+      <variablelist>
+        <varlistentry>
+          <term><option>==</option></term>
+          <listitem>
+            <para>Compare for equality.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>!=</option></term>
+          <listitem>
+            <para>Compare for inequality.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>=</option></term>
+          <listitem>
+            <para>Assign a value to a key. Keys that represent a list are reset
+            and only this single value is assigned.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>+=</option></term>
+          <listitem>
+            <para>Add the value to a key that holds a list of entries.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>:=</option></term>
+          <listitem>
+            <para>Assign  a  value  to  a key finally; disallow any later changes.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+
+      <para>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.</para>
+      <variablelist>
+        <varlistentry>
+          <term><option>ACTION</option></term>
+          <listitem>
+            <para>Match the name of the event action.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>DEVPATH</option></term>
+          <listitem>
+            <para>Match the devpath of the event device.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>KERNEL</option></term>
+          <listitem>
+            <para>Match the name of the event device.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>NAME</option></term>
+          <listitem>
+            <para>Match the name of a network interface. It can be used once the
+            NAME key has been set in one of the preceding rules.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>SYMLINK</option></term>
+          <listitem>
+            <para>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.
+            </para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>SUBSYSTEM</option></term>
+          <listitem>
+            <para>Match the subsystem of the event device.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>DRIVER</option></term>
+          <listitem>
+            <para>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.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>ATTR{<replaceable>filename</replaceable>}</option></term>
+          <listitem>
+            <para>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.
+            </para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>KERNELS</option></term>
+          <listitem>
+            <para>Search the devpath upwards for a matching device name.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>SUBSYSTEMS</option></term>
+          <listitem>
+            <para>Search the devpath upwards for a matching device subsystem name.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>DRIVERS</option></term>
+          <listitem>
+            <para>Search the devpath upwards for a matching device driver name.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>ATTRS{<replaceable>filename</replaceable>}</option></term>
+          <listitem>
+            <para>Search the devpath upwards for a device with matching sysfs attribute values.
+            If multiple <option>ATTRS</option> 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.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>TAGS</option></term>
+          <listitem>
+            <para>Search the devpath upwards for a device with matching tag.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>ENV{<replaceable>key</replaceable>}</option></term>
+          <listitem>
+            <para>Match against a device property value.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>TAG</option></term>
+          <listitem>
+            <para>Match against a device tag.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>TEST{<replaceable>octal mode mask</replaceable>}</option></term>
+          <listitem>
+            <para>Test the existence of a file. An octal mode mask can be specified
+            if needed.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>PROGRAM</option></term>
+          <listitem>
+            <para>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 stdout
+            is available in the RESULT key.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>RESULT</option></term>
+          <listitem>
+            <para>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.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+
+      <para>Most of the fields support shell-style pattern matching. The following
+      pattern characters are supported:</para>
+      <variablelist>
+        <varlistentry>
+          <term><option>*</option></term>
+          <listitem>
+            <para>Matches zero or more characters.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>?</option></term>
+          <listitem>
+            <para>Matches any single character.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>[]</option></term>
+          <listitem>
+            <para>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.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+
+      <para>The following keys can get values assigned:</para>
+      <variablelist>
+        <varlistentry>
+          <term><option>NAME</option></term>
+          <listitem>
+            <para>The name to use for a network interface. The name of a device node
+            can not be changed by udev, only additional symlinks can be created.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>SYMLINK</option></term>
+          <listitem>
+            <para>The name of a symlink targeting the node. Every matching rule adds
+            this value to the list of symlinks to be created. 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. Also, symlink names must
+            never conflict with the kernel's default device node names, as that would
+            result in unpredictable behavior.
+            </para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>OWNER, GROUP, MODE</option></term>
+          <listitem>
+            <para>The permissions for the device node. Every specified value overrides
+            the compiled-in default value.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>ATTR{<replaceable>key</replaceable>}</option></term>
+          <listitem>
+            <para>The value that should be written to a sysfs attribute of the
+            event device.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>ENV{<replaceable>key</replaceable>}</option></term>
+          <listitem>
+            <para>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, say, the PROGRAM match key).</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>TAG</option></term>
+          <listitem>
+            <para>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.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>RUN</option></term>
+          <listitem>
+            <para>Add a program to the list of programs to be executed for a specific
+            device.</para>
+            <para>If no absolute path is given, the program is expected to live in
+            /usr/lib/udev, otherwise the absolute path must be specified. The program
+            name and following arguments are separated by spaces. Single quotes can
+            be used to specify arguments with spaces.</para>
+            <para>This can only be used for very short running 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.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>LABEL</option></term>
+          <listitem>
+            <para>A named label to which a GOTO may jump.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>GOTO</option></term>
+          <listitem>
+            <para>Jumps to the next LABEL with a matching name.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>IMPORT{<replaceable>type</replaceable>}</option></term>
+          <listitem>
+            <para>Import a set of variables as device properties,
+            depending on <replaceable>type</replaceable>:</para>
+            <variablelist>
+              <varlistentry>
+                <term><option>program</option></term>
+                <listitem>
+                  <para>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 <option>RUN</option>.</para>
+                </listitem>
+              </varlistentry>
+              <varlistentry>
+                <term><option>file</option></term>
+                <listitem>
+                  <para>Import a text file specified as the assigned value, the content
+                  of which must be in environment key format.</para>
+                </listitem>
+              </varlistentry>
+              <varlistentry>
+                <term><option>db</option></term>
+                <listitem>
+                  <para>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.</para>
+                </listitem>
+              </varlistentry>
+              <varlistentry>
+                <term><option>cmdline</option></term>
+                <listitem>
+                  <para>Import a single property from the kernel command line. For simple flags
+                  the value of the property is set to '1'.</para>
+                </listitem>
+              </varlistentry>
+              <varlistentry>
+                <term><option>parent</option></term>
+                <listitem>
+                  <para>Import the stored keys from the parent device by reading
+                  the database entry of the parent device. The value assigned to
+                  <option>IMPORT{parent}</option> is used as a filter of key names
+                  to import (with the same shell-style pattern matching used for
+                  comparisons).</para>
+                </listitem>
+              </varlistentry>
+            </variablelist>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>WAIT_FOR</option></term>
+          <listitem>
+            <para>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.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>OPTIONS</option></term>
+          <listitem>
+            <para>Rule and device options:</para>
+            <variablelist>
+              <varlistentry>
+                <term><option>link_priority=<replaceable>value</replaceable></option></term>
+                <listitem>
+                  <para>Specify the priority of the created symlinks. Devices with higher
+                  priorities overwrite existing symlinks of other devices. The default is 0.</para>
+                </listitem>
+              </varlistentry>
+              <varlistentry>
+                <term><option>event_timeout=</option></term>
+                <listitem>
+                  <para>Number of seconds an event waits for operations to finish before
+                  giving up and terminating itself.</para>
+                </listitem>
+              </varlistentry>
+              <varlistentry>
+                <term><option>string_escape=<replaceable>none|replace</replaceable></option></term>
+                <listitem>
+                  <para>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.</para>
+                </listitem>
+              </varlistentry>
+              <varlistentry>
+                <term><option>static_node=</option></term>
+                <listitem>
+                  <para>Apply the permissions specified in this rule to the static device node with
+                  the specified name. Static device nodes might be provided by kernel modules
+                  or copied from <filename>/usr/lib/udev/devices</filename>. These nodes might not have
+                  a corresponding kernel device at the time udevd is started; they can trigger
+                  automatic kernel module loading.</para>
+                </listitem>
+              </varlistentry>
+              <varlistentry>
+                <term><option>watch</option></term>
+                <listitem>
+                  <para>Watch the device node with inotify; when the node is closed after being opened for
+                  writing, a change uevent is synthesized.</para>
+                </listitem>
+              </varlistentry>
+              <varlistentry>
+                <term><option>nowatch</option></term>
+                <listitem>
+                  <para>Disable the watching of a device node with inotify.</para>
+                </listitem>
+              </varlistentry>
+            </variablelist>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+
+      <para>The <option>NAME</option>, <option>SYMLINK</option>, <option>PROGRAM</option>,
+      <option>OWNER</option>, <option>GROUP</option>, <option>MODE</option>  and  <option>RUN</option>
+      fields support simple string substitutions. The <option>RUN</option>
+      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:</para>
+      <variablelist>
+        <varlistentry>
+          <term><option>$kernel</option>, <option>%k</option></term>
+          <listitem>
+            <para>The kernel name for this device.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>$number</option>, <option>%n</option></term>
+          <listitem>
+            <para>The kernel number for this device. For example, 'sda3' has
+            kernel number of '3'</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>$devpath</option>, <option>%p</option></term>
+          <listitem>
+            <para>The devpath of the device.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>$id</option>, <option>%b</option></term>
+          <listitem>
+            <para>The name of the device matched while searching the devpath upwards for
+              <option>SUBSYSTEMS</option>, <option>KERNELS</option>, <option>DRIVERS</option> and <option>ATTRS</option>.
+            </para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>$driver</option></term>
+          <listitem>
+            <para>The driver name of the device matched while searching the devpath upwards for
+              <option>SUBSYSTEMS</option>, <option>KERNELS</option>, <option>DRIVERS</option> and <option>ATTRS</option>.
+            </para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>$attr{<replaceable>file</replaceable>}</option>, <option>%s{<replaceable>file</replaceable>}</option></term>
+          <listitem>
+            <para>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 KERNELS, SUBSYSTEMS, DRIVERS, or
+            ATTRS test selected a parent device, then the attribute from that
+            parent device is used.</para>
+            <para>If the attribute is a symlink, the last element of the symlink target is
+            returned as the value.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>$env{<replaceable>key</replaceable>}</option>, <option>%E{<replaceable>key</replaceable>}</option></term>
+          <listitem>
+            <para>A device property value.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>$major</option>, <option>%M</option></term>
+          <listitem>
+            <para>The kernel major number for the device.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>$minor</option>, <option>%m</option></term>
+          <listitem>
+            <para>The kernel minor number for the device.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>$result</option>, <option>%c</option></term>
+          <listitem>
+            <para>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: <option>%c{N}</option>.
+            If the number is followed by the '+' character, this part plus all remaining parts
+            of the result string are substituted: <option>%c{N+}</option></para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>$parent</option>, <option>%P</option></term>
+          <listitem>
+            <para>The node name of the parent device.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>$name</option></term>
+          <listitem>
+            <para>The current name of the device. If not changed by a rule, it is the
+            name of the kernel device.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>$links</option></term>
+          <listitem>
+            <para>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.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>$root</option>, <option>%r</option></term>
+          <listitem>
+            <para>The udev_root value.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>$sys</option>, <option>%S</option></term>
+          <listitem>
+            <para>The sysfs mount point.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>$devnode</option>, <option>%N</option></term>
+          <listitem>
+            <para>The name of the device node.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>%%</option></term>
+          <listitem>
+          <para>The '%' character itself.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><option>$$</option></term>
+          <listitem>
+          <para>The '$' character itself.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+  </refsect1>
+
+  <refsect1><title>Author</title>
+    <para>Written by Greg Kroah-Hartman <email>greg@kroah.com</email> and
+    Kay Sievers <email>kay.sievers@vrfy.org</email>. With much help from
+    Dan Stekloff and many others.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>See Also</title>
+    <para><citerefentry>
+        <refentrytitle>udevd</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>udevadm</refentrytitle><manvolnum>8</manvolnum>
+    </citerefentry></para>
+  </refsect1>
+</refentry>
diff --git a/man/udevadm.xml b/man/udevadm.xml
new file mode 100644 (file)
index 0000000..455ce80
--- /dev/null
@@ -0,0 +1,472 @@
+<?xml version='1.0'?>
+<?xml-stylesheet type="text/xsl" href="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<refentry id="udevadm">
+  <refentryinfo>
+    <title>udevadm</title>
+    <productname>udev</productname>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>udevadm</refentrytitle>
+    <manvolnum>8</manvolnum>
+    <refmiscinfo class="version"></refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>udevadm</refname><refpurpose>udev management tool</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>udevadm</command>
+        <arg><option>--debug</option></arg>
+        <arg><option>--version</option></arg>
+        <arg><option>--help</option></arg>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>udevadm info <replaceable>options</replaceable></command>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>udevadm trigger <optional>options</optional></command>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>udevadm settle <optional>options</optional></command>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>udevadm control <replaceable>command</replaceable></command>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>udevadm monitor <optional>options</optional></command>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>udevadm test <optional>options</optional> <replaceable>devpath</replaceable></command>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>udevadm test-builtin <optional>options</optional> <replaceable>command</replaceable> <replaceable>devpath</replaceable></command>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1><title>Description</title>
+    <para>udevadm expects a command and command specific options.  It
+    controls the runtime behavior of udev, requests kernel events,
+    manages the event queue, and provides simple debugging mechanisms.</para>
+  </refsect1>
+
+  <refsect1><title>OPTIONS</title>
+    <variablelist>
+      <varlistentry>
+        <term><option>--debug</option></term>
+        <listitem>
+          <para>Print debug messages to stderr.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--version</option></term>
+        <listitem>
+          <para>Print version number.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--help</option></term>
+        <listitem>
+          <para>Print help text.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+
+    <refsect2><title>udevadm info <replaceable>options</replaceable></title>
+      <para>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.</para>
+      <variablelist>
+        <varlistentry>
+          <term><option>--query=<replaceable>type</replaceable></option></term>
+          <listitem>
+            <para>Query the database for specified type of device data. It needs the
+            <option>--path</option> or <option>--name</option> to identify the specified
+            device. Valid queries are:
+            <command>name</command>, <command>symlink</command>, <command>path</command>,
+            <command>property</command>, <command>all</command>.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--path=<replaceable>devpath</replaceable></option></term>
+          <listitem>
+            <para>The devpath of the device to query.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--name=<replaceable>file</replaceable></option></term>
+          <listitem>
+            <para>The name of the device node or a symlink to query</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--root</option></term>
+          <listitem>
+            <para>The udev root directory: <filename>/dev</filename>. If used in conjunction
+            with a <command>name</command> or <command>symlink</command> query, the
+            query returns the absolute path including the root directory.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--run</option></term>
+          <listitem>
+            <para>The udev runtime directory: <filename>/run/udev</filename>.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--attribute-walk</option></term>
+          <listitem>
+            <para>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.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--export</option></term>
+          <listitem>
+            <para>Print output as key/value pairs. Values are enclosed in single quotes.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--export-prefix=<replaceable>name</replaceable></option></term>
+          <listitem>
+            <para>Add a prefix to the key name of exported values.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--device-id-of-file=<replaceable>file</replaceable></option></term>
+          <listitem>
+            <para>Print major/minor numbers of the underlying device, where the file
+            lives on.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--export-db</option></term>
+          <listitem>
+            <para>Export the content of the udev database.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--cleanup-db</option></term>
+          <listitem>
+            <para>Cleanup the udev database.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--version</option></term>
+          <listitem>
+            <para>Print version.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--help</option></term>
+          <listitem>
+            <para>Print help text.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2><title>udevadm trigger <optional>options</optional></title>
+      <para>Request device events from the kernel. Primarily used to replay events at system coldplug time.</para>
+      <variablelist>
+        <varlistentry>
+          <term><option>--verbose</option></term>
+          <listitem>
+            <para>Print the list of devices which will be triggered.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--dry-run</option></term>
+          <listitem>
+            <para>Do not actually trigger the event.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--type=<replaceable>type</replaceable></option></term>
+          <listitem>
+            <para>Trigger a specific type of devices. Valid types are:
+            <command>devices</command>, <command>subsystems</command>.
+            The default value is <command>devices</command>.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--action=<replaceable>action</replaceable></option></term>
+          <listitem>
+            <para>Type of event to be triggered. The default value is <command>change</command>.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--subsystem-match=<replaceable>subsystem</replaceable></option></term>
+          <listitem>
+            <para>Trigger events for devices which belong to a matching subsystem. This option
+            can be specified multiple times and supports shell style pattern matching.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--subsystem-nomatch=<replaceable>subsystem</replaceable></option></term>
+          <listitem>
+            <para>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.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--attr-match=<replaceable>attribute</replaceable>=<replaceable>value</replaceable></option></term>
+          <listitem>
+            <para>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.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--attr-nomatch=<replaceable>attribute</replaceable>=<replaceable>value</replaceable></option></term>
+          <listitem>
+            <para>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.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--property-match=<replaceable>property</replaceable>=<replaceable>value</replaceable></option></term>
+          <listitem>
+            <para>Trigger events for devices with a matching property value. This option can be
+            specified multiple times and supports shell style pattern matching.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--tag-match=<replaceable>property</replaceable></option></term>
+          <listitem>
+            <para>Trigger events for devices with a matching tag. This option can be
+            specified multiple times.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--sysname-match=<replaceable>name</replaceable></option></term>
+          <listitem>
+            <para>Trigger events for devices with a matching sys device name. This option can be
+            specified multiple times and supports shell style pattern matching.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--parent-match=<replaceable>syspath</replaceable></option></term>
+          <listitem>
+            <para>Trigger events for all children of a given device.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2><title>udevadm settle <optional>options</optional></title>
+      <para>Watches the udev event queue, and exits if all current events are handled.</para>
+      <variablelist>
+        <varlistentry>
+          <term><option>--timeout=<replaceable>seconds</replaceable></option></term>
+          <listitem>
+            <para>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.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--seq-start=<replaceable>seqnum</replaceable></option></term>
+          <listitem>
+            <para>Wait only for events after the given sequence number.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--seq-end=<replaceable>seqnum</replaceable></option></term>
+          <listitem>
+            <para>Wait only for events before the given sequence number.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--exit-if-exists=<replaceable>file</replaceable></option></term>
+          <listitem>
+            <para>Stop waiting if file exists.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--quiet</option></term>
+          <listitem>
+            <para>Do not print any output, like the remaining queue entries when reaching the timeout.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--help</option></term>
+          <listitem>
+            <para>Print help text.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2><title>udevadm control <replaceable>command</replaceable></title>
+      <para>Modify the internal state of the running udev daemon.</para>
+      <variablelist>
+        <varlistentry>
+          <term><option>--exit</option></term>
+          <listitem>
+            <para>Signal and wait for udevd to exit.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--log-priority=<replaceable>value</replaceable></option></term>
+          <listitem>
+            <para>Set the internal log level of udevd. Valid values are the numerical
+            syslog priorities or their textual representations: <option>err</option>,
+            <option>info</option> and <option>debug</option>.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--stop-exec-queue</option></term>
+          <listitem>
+            <para>Signal udevd to stop executing new events. Incoming events
+            will be queued.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--start-exec-queue</option></term>
+          <listitem>
+            <para>Signal udevd to enable the execution of events.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--reload</option></term>
+          <listitem>
+            <para>Signal 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.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--property=<replaceable>KEY</replaceable>=<replaceable>value</replaceable></option></term>
+          <listitem>
+            <para>Set a global property for all events.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--children-max=</option><replaceable>value</replaceable></term>
+          <listitem>
+            <para>Set the maximum number of events, udevd will handle at the
+            same time.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--timeout=</option><replaceable>seconds</replaceable></term>
+          <listitem>
+            <para>The maximum number seconds to wait for a reply from udevd.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--help</option></term>
+          <listitem>
+            <para>Print help text.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2><title>udevadm monitor <optional>options</optional></title>
+      <para>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.
+      </para>
+      <variablelist>
+        <varlistentry>
+          <term><option>--kernel</option></term>
+          <listitem>
+            <para>Print the kernel uevents.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--udev</option></term>
+          <listitem>
+            <para>Print the udev event after the rule processing.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--property</option></term>
+          <listitem>
+            <para>Also print the properties of the event.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--subsystem-match=<replaceable>string[/string]</replaceable></option></term>
+          <listitem>
+            <para>Filter events by subsystem[/devtype]. Only udev events with a matching subsystem value will pass.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--tag-match=<replaceable>string</replaceable></option></term>
+          <listitem>
+            <para>Filter events by property. Only udev events with a given tag attached will pass.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--help</option></term>
+          <listitem>
+            <para>Print help text.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2><title>udevadm test <optional>options</optional> <replaceable>devpath</replaceable></title>
+      <para>Simulate a udev event run for the given device, and print debug output.</para>
+      <variablelist>
+        <varlistentry>
+          <term><option>--action=<replaceable>string</replaceable></option></term>
+          <listitem>
+            <para>The action string.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--subsystem=<replaceable>string</replaceable></option></term>
+          <listitem>
+            <para>The subsystem string.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><option>--help</option></term>
+          <listitem>
+            <para>Print help text.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2><title>udevadm test-builtin <optional>options</optional> <replaceable>command</replaceable> <replaceable>devpath</replaceable></title>
+      <para>Run a built-in command for the given device, and print debug output.</para>
+      <variablelist>
+        <varlistentry>
+          <term><option>--help</option></term>
+          <listitem>
+            <para>Print help text.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+  </refsect1>
+
+  <refsect1><title>Author</title>
+    <para>Written by Kay Sievers <email>kay.sievers@vrfy.org</email>.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>See Also</title>
+    <para><citerefentry>
+        <refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum>
+    </citerefentry>
+    <citerefentry>
+        <refentrytitle>udevd</refentrytitle><manvolnum>8</manvolnum>
+    </citerefentry></para>
+  </refsect1>
+</refentry>
diff --git a/man/udevd.xml b/man/udevd.xml
new file mode 100644 (file)
index 0000000..c516eb9
--- /dev/null
@@ -0,0 +1,151 @@
+<?xml version='1.0'?>
+<?xml-stylesheet type="text/xsl" href="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<refentry id="udevd">
+  <refentryinfo>
+    <title>udevd</title>
+    <productname>udev</productname>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>udevd</refentrytitle>
+    <manvolnum>8</manvolnum>
+    <refmiscinfo class="version"></refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>udevd</refname><refpurpose>event managing daemon</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>udevd</command>
+      <arg><option>--daemon</option></arg>
+      <arg><option>--debug</option></arg>
+      <arg><option>--children-max=</option></arg>
+      <arg><option>--exec-delay=</option></arg>
+      <arg><option>--resolve-names=early|late|never</option></arg>
+      <arg><option>--version</option></arg>
+      <arg><option>--help</option></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1><title>Description</title>
+    <para>udevd listens to kernel uevents. For every event, udevd executes matching
+    instructions specified in udev rules. See <citerefentry>
+        <refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum>
+      </citerefentry>.</para>
+    <para>On startup the content of the directory <filename>/usr/lib/udev/devices</filename>
+    is copied to <filename>/dev</filename>. If kernel modules specify static device
+    nodes, these nodes are created even without a corresponding kernel device, to
+    allow on-demand loading of kernel modules. Matching permissions specified in udev
+    rules are applied to these static device nodes.</para>
+    <para>The behavior of the running daemon can be changed with
+    <command>udevadm control</command>.</para>
+  </refsect1>
+
+  <refsect1><title>Options</title>
+    <variablelist>
+      <varlistentry>
+        <term><option>--daemon</option></term>
+        <listitem>
+          <para>Detach and run in the background.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--debug</option></term>
+        <listitem>
+          <para>Print debug messages to stderr.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--children-max=</option></term>
+        <listitem>
+          <para>Limit the number of parallel executed events.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--exec-delay=</option></term>
+        <listitem>
+          <para>Number of seconds to delay the execution of RUN instructions.
+          This might be useful when debugging system crashes during coldplug
+          cause by loading non-working kernel modules.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--resolve-names=</option></term>
+        <listitem>
+          <para>Specify when udevd should resolve names of users and groups.
+          When set to <option>early</option> (the default) names will be
+          resolved when the rules are parsed.  When set to
+          <option>late</option> names will be resolved for every event.
+          When set to <option>never</option> names will never be resolved
+          and all devices will be owned by root.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--version</option></term>
+        <listitem>
+          <para>Print version number.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--help</option></term>
+        <listitem>
+          <para>Print help text.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1><title>Environment</title>
+    <variablelist>
+      <varlistentry>
+        <term><varname>UDEV_LOG=</varname></term>
+        <listitem>
+          <para>Set the logging priority.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+ </refsect1>
+
+  <refsect1><title>Kernel command line</title>
+    <variablelist>
+      <varlistentry>
+        <term><varname>udev.log-priority=</varname></term>
+        <listitem>
+          <para>Set the logging priority.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>udev.children-max=</varname></term>
+        <listitem>
+          <para>Limit the number of parallel executed events.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>udev.exec-delay=</varname></term>
+        <listitem>
+          <para>Number of seconds to delay the execution of RUN instructions.
+          This might be useful when debugging system crashes during coldplug
+          cause by loading non-working kernel modules.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+ </refsect1>
+
+  <refsect1><title>Author</title>
+    <para>Written by Kay Sievers <email>kay.sievers@vrfy.org</email>.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>See Also</title>
+    <para><citerefentry>
+        <refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>udevadm</refentrytitle><manvolnum>8</manvolnum>
+    </citerefentry></para>
+  </refsect1>
+</refentry>
diff --git a/rules/.gitignore b/rules/.gitignore
new file mode 100644 (file)
index 0000000..93a50dd
--- /dev/null
@@ -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 (file)
index 0000000..d5d5897
--- /dev/null
@@ -0,0 +1,49 @@
+#
+# 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"
+
+#
+# Enable autosuspend for KVM and iLO usb hid devices. These are
+# effectively self-powered (despite what some claim in their USB
+# profiles) and so it's safe to do so.
+#
+
+# AMI 046b:ff10
+ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="046b", ATTR{idProduct}=="ff10", 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"
+
+# Hewlett Packard iLO
+ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="03f0", ATTR{idProduct}=="7029", TEST=="power/control", ATTR{power/control}="auto"
+ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="03f0", ATTR{idProduct}=="1027", 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", ATTR{bInterfaceClass}=="03", ATTRS{removable}=="fixed", TEST=="../power/control", ATTR{../power/control}="auto"
diff --git a/rules/50-udev-default.rules b/rules/50-udev-default.rules
new file mode 100644 (file)
index 0000000..5ad787f
--- /dev/null
@@ -0,0 +1,107 @@
+# do not edit this file, it will be overwritten on update
+
+KERNEL=="pty[pqrstuvwxyzabcdef][0123456789abcdef]", GROUP="tty", MODE="0660"
+KERNEL=="tty[pqrstuvwxyzabcdef][0123456789abcdef]", GROUP="tty", MODE="0660"
+KERNEL=="ptmx", GROUP="tty", MODE="0666"
+KERNEL=="tty", GROUP="tty", MODE="0666"
+KERNEL=="tty[0-9]*", GROUP="tty", MODE="0620"
+KERNEL=="vcs|vcs[0-9]*|vcsa|vcsa[0-9]*", GROUP="tty"
+
+# serial
+KERNEL=="tty[A-Z]*[0-9]|pppox[0-9]*|ircomm[0-9]*|noz[0-9]*|rfcomm[0-9]*", GROUP="dialout"
+KERNEL=="mwave", GROUP="dialout"
+KERNEL=="hvc*|hvsi*", GROUP="dialout"
+
+# virtio serial / console ports
+KERNEL=="vport*", ATTR{name}=="?*", SYMLINK+="virtio-ports/$attr{name}"
+
+# mem
+KERNEL=="null|zero|full|random|urandom", MODE="0666"
+KERNEL=="mem|kmem|port|nvram", GROUP="kmem", MODE="0640"
+
+# input
+SUBSYSTEM=="input", ENV{ID_INPUT}=="", IMPORT{builtin}="input_id"
+KERNEL=="mouse*|mice|event*", MODE="0640"
+KERNEL=="ts[0-9]*|uinput", MODE="0640"
+KERNEL=="js[0-9]*", MODE="0644"
+
+# video4linux
+SUBSYSTEM=="video4linux", GROUP="video"
+KERNEL=="vttuner*", GROUP="video"
+KERNEL=="vtx*|vbi*", GROUP="video"
+KERNEL=="winradio*", GROUP="video"
+
+# graphics
+KERNEL=="agpgart", GROUP="video"
+KERNEL=="pmu", GROUP="video"
+KERNEL=="nvidia*|nvidiactl*", GROUP="video"
+SUBSYSTEM=="graphics", GROUP="video"
+SUBSYSTEM=="drm", GROUP="video"
+
+# sound
+SUBSYSTEM=="sound", GROUP="audio", \
+  OPTIONS+="static_node=snd/seq", OPTIONS+="static_node=snd/timer"
+
+# DVB (video)
+SUBSYSTEM=="dvb", GROUP="video"
+
+# FireWire (firewire-core driver: IIDC devices, AV/C devices)
+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"
+
+# 'libusb' device nodes
+SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", MODE="0664"
+SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", IMPORT{builtin}="usb_id"
+
+# printer
+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"
+
+# block
+SUBSYSTEM=="block", GROUP="disk"
+
+# floppy
+SUBSYSTEM=="block", KERNEL=="fd[0-9]", GROUP="floppy"
+
+# cdrom
+SUBSYSTEM=="block", KERNEL=="sr[0-9]*", GROUP="cdrom"
+SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="4|5", GROUP="cdrom"
+KERNEL=="pktcdvd[0-9]*", GROUP="cdrom"
+KERNEL=="pktcdvd", GROUP="cdrom"
+
+# tape
+KERNEL=="ht[0-9]*|nht[0-9]*", GROUP="tape"
+KERNEL=="pt[0-9]*|npt[0-9]*|pht[0-9]*", GROUP="tape"
+SUBSYSTEM=="scsi_generic|scsi_tape", SUBSYSTEMS=="scsi", ATTRS{type}=="1|8", GROUP="tape"
+
+# block-related
+KERNEL=="sch[0-9]*", GROUP="disk"
+SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="0", GROUP="disk"
+KERNEL=="pg[0-9]*", 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"
+
+# network
+KERNEL=="tun", MODE="0666", OPTIONS+="static_node=net/tun"
+KERNEL=="rfkill", MODE="0644"
+
+# CPU
+KERNEL=="cpu[0-9]*", MODE="0444"
+
+KERNEL=="fuse", ACTION=="add", MODE="0666", OPTIONS+="static_node=fuse"
+
+SUBSYSTEM=="rtc", ATTR{hctosys}=="1", SYMLINK+="rtc"
+KERNEL=="mmtimer", MODE="0644"
+KERNEL=="rflash[0-9]*", MODE="0400"
+KERNEL=="rrom[0-9]*", MODE="0400"
+
+SUBSYSTEM=="firmware", ACTION=="add", IMPORT{builtin}="firmware"
diff --git a/rules/60-persistent-alsa.rules b/rules/60-persistent-alsa.rules
new file mode 100644 (file)
index 0000000..8154e2d
--- /dev/null
@@ -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 (file)
index 0000000..fb798dd
--- /dev/null
@@ -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}=="?*", 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}=="?*", 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 (file)
index 0000000..2948200
--- /dev/null
@@ -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 (file)
index 0000000..f2eabd9
--- /dev/null
@@ -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 (file)
index 0000000..b74821e
--- /dev/null
@@ -0,0 +1,89 @@
+# 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 <hare@suse.de>
+
+# 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*", 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 with their own "ata" kernel subsystem
+KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="ata", IMPORT{program}="ata_id --export $devnode"
+# 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/75-net-description.rules b/rules/75-net-description.rules
new file mode 100644 (file)
index 0000000..ce57d48
--- /dev/null
@@ -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"
+
+SUBSYSTEMS=="usb", ENV{ID_MODEL}=="", IMPORT{builtin}="usb_id"
+SUBSYSTEMS=="usb", IMPORT{builtin}="usb-db"
+SUBSYSTEMS=="usb", ATTRS{idVendor}!="", ATTRS{idProduct}!="", ENV{ID_VENDOR_ID}="$attr{idVendor}", ENV{ID_MODEL_ID}="$attr{idProduct}"
+SUBSYSTEMS=="usb", GOTO="net_end"
+
+SUBSYSTEMS=="pci", IMPORT{builtin}="pci-db"
+SUBSYSTEMS=="pci", ENV{ID_BUS}="pci", ENV{ID_VENDOR_ID}="$attr{vendor}", ENV{ID_MODEL_ID}="$attr{device}"
+
+LABEL="net_end"
diff --git a/rules/75-tty-description.rules b/rules/75-tty-description.rules
new file mode 100644 (file)
index 0000000..2e63e14
--- /dev/null
@@ -0,0 +1,14 @@
+# do not edit this file, it will be overwritten on update
+
+ACTION=="remove", GOTO="tty_end"
+SUBSYSTEM!="tty", GOTO="tty_end"
+
+SUBSYSTEMS=="usb", ENV{ID_MODEL}=="", IMPORT{builtin}="usb_id"
+SUBSYSTEMS=="usb", IMPORT{builtin}="usb-db"
+SUBSYSTEMS=="usb", ATTRS{idVendor}!="", ATTRS{idProduct}!="", ENV{ID_VENDOR_ID}="$attr{idVendor}", ENV{ID_MODEL_ID}="$attr{idProduct}"
+SUBSYSTEMS=="usb", GOTO="tty_end"
+
+SUBSYSTEMS=="pci", IMPORT{builtin}="pci-db"
+SUBSYSTEMS=="pci", ENV{ID_BUS}="pci", ENV{ID_VENDOR_ID}="$attr{vendor}", ENV{ID_MODEL_ID}="$attr{device}"
+
+LABEL="tty_end"
diff --git a/rules/78-sound-card.rules b/rules/78-sound-card.rules
new file mode 100644 (file)
index 0000000..e564441
--- /dev/null
@@ -0,0 +1,89 @@
+# 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"
+
+SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id"
+SUBSYSTEMS=="usb", IMPORT{builtin}="usb-db"
+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", IMPORT{builtin}="pci-db"
+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 (file)
index 0000000..38ebfeb
--- /dev/null
@@ -0,0 +1,12 @@
+# do not edit this file, it will be overwritten on update
+
+ACTION=="remove", GOTO="drivers_end"
+
+DRIVER!="?*", ENV{MODALIAS}=="?*", IMPORT{builtin}="kmod load $env{MODALIAS}"
+SUBSYSTEM=="tifm", ENV{TIFM_CARD_TYPE}=="SD", IMPORT{builtin}="kmod load tifm_sd"
+SUBSYSTEM=="tifm", ENV{TIFM_CARD_TYPE}=="MS", IMPORT{builtin}="kmod load tifm_ms"
+SUBSYSTEM=="memstick", IMPORT{builtin}="kmod load ms_block mspro_block"
+SUBSYSTEM=="i2o", IMPORT{builtin}="kmod load i2o_block"
+SUBSYSTEM=="module", KERNEL=="parport_pc", IMPORT{builtin}="kmod load ppdev"
+
+LABEL="drivers_end"
diff --git a/rules/95-udev-late.rules b/rules/95-udev-late.rules
new file mode 100644 (file)
index 0000000..eca0faa
--- /dev/null
@@ -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 (file)
index 0000000..d306f71
--- /dev/null
@@ -0,0 +1,55 @@
+#  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[a-zA-Z]*|hvc*|xvc*|hvsi*", 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", 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"
+
+# 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/99-systemd.rules.in b/src/99-systemd.rules.in
deleted file mode 100644 (file)
index d306f71..0000000
+++ /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[a-zA-Z]*|hvc*|xvc*|hvsi*", 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", 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"
-
-# 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"
index fa3500ba963fe1b7f09f50f51aaf9719749f7ada..e697a57ec3b04a712fffb9def2f4ad6cd64d5e33 100644 (file)
@@ -1,31 +1,4 @@
-*~
-*.o
-*.a
-*.lo
-*.la
-.libs
-.deps
-.dirstamp
-Makefile
-Makefile.in
-/aclocal.m4
-/autom4te.cache
-/config.h
-/config.h.in
-/config.log
-/config.status
-/config.guess
-/config.sub
-/libtool
-/ltmain.sh
-/install-sh
-/missing
-/configure
-/stamp-h1
-/depcomp
 /gtk-doc.make
-/build-aux
-/udev-test-install
 /udevd
 /udevadm
 /test-udev
@@ -38,3 +11,8 @@ Makefile.in
 /v4l_id
 /keymap
 /scsi_id
+*.[78]
+*.html
+udev.pc
+libudev.pc
+udev*.service
diff --git a/src/udev/COPYING b/src/udev/COPYING
deleted file mode 100644 (file)
index d159169..0000000
+++ /dev/null
@@ -1,339 +0,0 @@
-                    GNU GENERAL PUBLIC LICENSE
-                       Version 2, June 1991
-
- Copyright (C) 1989, 1991 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.
-
-                            Preamble
-
-  The licenses for most software are designed to take away your
-freedom to share and change it.  By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users.  This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it.  (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.)  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, 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 or use pieces of it
-in new free programs; and that you know you can do these things.
-
-  To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have.  You must make sure that they, too, receive or can get the
-source code.  And you must show them these terms so they know their
-rights.
-
-  We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
-  Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software.  If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
-  Finally, any free program is threatened constantly by software
-patents.  We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary.  To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-
-                    GNU GENERAL PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License.  The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language.  (Hereinafter, translation is included without limitation in
-the term "modification".)  Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope.  The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
-  1. You may copy and distribute verbatim copies of the Program's
-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 give any other recipients of the Program a copy of this License
-along with the Program.
-
-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 Program or any portion
-of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
-    stating that you changed the files and the date of any change.
-
-    b) You must cause any work that you distribute or publish, that in
-    whole or in part contains or is derived from the Program or any
-    part thereof, to be licensed as a whole at no charge to all third
-    parties under the terms of this License.
-
-    c) If the modified program normally reads commands interactively
-    when run, you must cause it, when started running for such
-    interactive use in the most ordinary way, to print or display an
-    announcement including an appropriate copyright notice and a
-    notice that there is no warranty (or else, saying that you provide
-    a warranty) and that users may redistribute the program under
-    these conditions, and telling the user how to view a copy of this
-    License.  (Exception: if the Program itself is interactive but
-    does not normally print such an announcement, your work based on
-    the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole.  If
-identifiable sections of that work are not derived from the Program,
-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 Program, 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 Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
-  3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
-    a) 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; or,
-
-    b) Accompany it with a written offer, valid for at least three
-    years, to give any third party, for a charge no more than your
-    cost of physically performing source distribution, a complete
-    machine-readable copy of the corresponding source code, to be
-    distributed under the terms of Sections 1 and 2 above on a medium
-    customarily used for software interchange; or,
-
-    c) Accompany it with the information you received as to the offer
-    to distribute corresponding source code.  (This alternative is
-    allowed only for noncommercial distribution and only if you
-    received the program in object code or executable form with such
-    an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it.  For an executable work, 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 executable.  However, as a
-special exception, the source code 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.
-
-If distribution of executable or 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 counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
-  4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License.  Any attempt
-otherwise to copy, modify, sublicense or distribute the Program 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.
-
-  5. 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 Program or its derivative works.  These actions are
-prohibited by law if you do not accept this License.  Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
-  6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program 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 to
-this License.
-
-  7. 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 Program at all.  For example, if a patent
-license would not permit royalty-free redistribution of the Program 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 Program.
-
-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.
-
-  8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program 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.
-
-  9. The Free Software Foundation may publish revised and/or new versions
-of the 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 Program
-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 Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
-  10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, 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
-
-  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU.  SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
-  12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), 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 Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
-  To do so, attach the following notices to the program.  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.
-
-    <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) <year>  <name of author>
-
-    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.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
-    Gnomovision version 69, Copyright (C) year name of author
-    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
-  `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
-  <signature of Ty Coon>, 1 April 1989
-  Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs.  If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library.  If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
diff --git a/src/udev/ChangeLog b/src/udev/ChangeLog
deleted file mode 100644 (file)
index dd58138..0000000
+++ /dev/null
@@ -1,6387 +0,0 @@
-Summary of changes from v181 to v182
-============================================
-
-Kay Sievers (22):
-      build-sys: unpack test sysfs only for 'make check'
-      build-sys: add --disable-manpages
-      update sd-daemon files
-      test: remove outdated key attributes
-      update TOO
-      builtin: path_id - remove dead cciss code
-      rules: do not create by-id/scsi-* links for ATA devices
-      remove udev-acl
-      udev.conf - do not set any value by default
-      move src/extras subdirectories to src/
-      rules: delete outdated 30-kernel-compat.rules
-      rules: move 42-qemu-usb.rules to rules/ dir
-      remove edd_id extra
-      build-sys: remove empty directory
-      rules: delete s390 rules, they will move to s390utils
-      update TODO
-      rules: move all rules to top level rules/ dir
-      extras: path_id - skip ATA transport class devices
-      extras: path_id - add comment about readdir() rebase logic
-      extras: ata_id - do not log error if HDIO_GET_IDENTITY fails
-      rules sort order: /lib, /run, /etc
-      build-sys: place build binaries in the root
-
-Matthew Garrett (1):
-      rules: Enable USB autosuspend on more USB HID devices
-
-
-Summary of changes from v180 to v181
-============================================
-
-Andreas Schwab (1):
-      ata_id: fix identify string fixup
-
-Bruno Redondi (1):
-      keymap: Add Fujitsu Siemens Amilo Li 2732
-
-James M. Leddy (1):
-      keymap: Fix touchpad toggle button on Lenovo Ideapad
-
-Kay Sievers (4):
-      configure: show ROOTPREFIX in firmware path option help text
-      extras: cdrom_id -  create /dev/cdrom and conditionally /dev/dvd for sr0
-      extras: cdrom_id -  create only /dev/cdrom
-      ata_id: whitespace fixes
-
-Lucas De Marchi (1):
-      builtin: kmod - depend on libkmod >= 5
-
-
-Summary of changes from v179 to v180
-============================================
-
-Kay Sievers (4):
-      Makefile: update kernel.org hooks
-      build-sys: we need to install shipped man pages without xsltproc installed
-      builtin: blkid - add missing ID_ prefix for PART_ENTRY_* keys
-      do not stop rule processing when device node is no longer around
-
-
-Summary of changes from v178 to v179
-============================================
-
-Kay Sievers (8):
-      fix some fallout from tab removal
-      use devnode() for $name not sysname(), device nodes might be in a subdirectory
-      print warning when rules try to rename kernel device nodes
-      move variable inside condition
-      update TODO
-      build-sys: enable everything for 'make distcheck'
-      use sysname() for devices without a device node
-      fix path to extras
-
-
-Summary of changes from v177 to v178
-============================================
-
-Evan Nemerson (1):
-      gudev: several minor introspection fixes
-
-Kay Sievers (7):
-      Makefile: update kernel.org doc hooks for kup
-      builtin: blkid - add missing ID_ prefix
-      udevd: kill hanging event processes after 30 seconds
-      Makefile: switch from .asc to .sign
-      rules: rtc - point /dev/rtc symlink to 'hctosys' device
-      warn about deprecated RUN+="socket:" use
-      libudev: do not set DEVNAME= twice
-
-Martin Pitt (4):
-      keymap: Fix rfkill button on Hewlett-Packard HP ProBook
-      keymap: Fix eject button on Samsung 700Z series
-      keymap: Fix keyboard brightness keys on Samsung 700Z series
-      keymap: Add Alienware M14xR1
-
-
-Summary of changes from v176 to v177
-============================================
-
-Kay Sievers (3):
-      Makefile: update kernel.org sign and upload hook
-      rule_generator: fix to install rules in rules.d/
-      rule_generator: use += for dist_udevhome_DATA
-
-
-Summary of changes from v175 to v176
-============================================
-
-Alan Stern (1):
-      [PATCH[ udev: ata_id: Fix length of INQUIRY command
-
-Kay Sievers (61):
-      libudev: print log_fn address instead of ctx when setting logging function
-      do not ship autogen.sh in the tarball
-      man: clarify 'config file stack'
-      rename 'init' directory to 'systemd'
-      systemd: use PassCred=yes
-      use libexecdir, bindir, sbindir, switch to /usr/lib/udev in documentation
-      configure: fix typo
-      make: do not (mis-)use the config file generator, create .xz tarball
-      prepare builtins for blkid and kmod
-      add builtin load/unload initializers
-      build argv[] for builtin commands
-      update blkid builtin
-      rules: switch to built-in blkid
-      rules: do not preprocess 60-persistent-storage.rules
-      buildsys: disable tar.gz
-      builtin: blkid - add missing newline
-      builtin: blkid - add missing ID_FS_USAGE
-      builtin: kmod - switch modprobe to builtin
-      rules: do not preprocess 80-drivers.rules + 75-probe_mtd.rules
-      builtin: apply format string
-      remove last sbindir use
-      update NEWS
-      autogen.sh: moce CFLAGS from to configure.ac; print common ./configure options
-      builtin: kmod - link against libkmod
-      add copyright
-      builtin: kmod - reload index when rules are reloaded
-      builtin: rename load()/unload() to init()/exit()
-      invalidate rules and kmod index with 'udevadm control --reload'
-      update NEWS
-      builtin: firmware - move 'firmware' tool to builtins
-      builtin: firmware - add missing file
-      builtin: kmod - hook up udev main logging to libkmod
-      make: introduce --with-rootprefix=
-      update NEWS
-      move rules dirs to udev context; replace inotify with time-controlled stat()
-      udevd: always create runtime dir
-      builtin: move usb-db, pci-db to builtins
-      builtin: kmod - switch to kmod_module_probe_insert_module()
-      udevd: remove TIMEOUT= handling
-      update README
-      systemd: rename PassCred= to PsssCredentials=
-      remove mknod() logic and rely on 'devtmpfs'
-      builtin: kmod - hook up kmod_validate_resources()
-      build-sys: use use ${ac_default_prefix}
-      require kmod >= 3
-      build-sys: use --libexecdir=/usr/lib instead of /usr/lib/udev
-      autogen.sh: enable git pre-commit
-      merge udev/, libudev/, systemd/ files in src/; move extras/ to src/
-      replace unpacked sysfs test tree 'test/sys/' with packed tarball
-      rules: delete arch specific rules
-      doc: fix out of tree build (copy from libkmod)
-      autogen.sh: add CFLAGS and print entire line, so that mouse copy/paste works
-      build-sys: try to build without installed xsltproc
-      add test/src to .gitignore
-      tabs are as useful as a hole in the head
-      autogen.sh: makedev() misteriously breaks with -O0 here, use -O1 for now
-      fix debug message
-      add .vimrc
-      cdrom_id: int -> bool
-      fix compiler warning
-      man: mention that no daemons should be started by udev
-
-Lucas De Marchi (1):
-      builtin: kmod - log if modules are blacklisted
-
-Luis Felipe Strano Moraes (1):
-      Switch spawn_read to void and remove useless stores there.
-
-Martin Pitt (1):
-      75-persistent-net-generator.rules: Add Xen
-
-Mike Frysinger (1):
-      hwdb: drop useless line freeing
-
-Sjoerd Simons (1):
-      keymap: Add Lenovo Thinkpad X220 Tablet
-
-Ville Skyttä (1):
-      man: spelling fix
-
-
-Summary of changes from v174 to v175
-============================================
-
-David Zeuthen (2):
-      gudev: Use strtoul to parse unsigned 64-bit integers
-      gudev: Use g_ascii_strtoull() instead of strtoul()
-
-Harald Hoyer (1):
-      extras/keymap/findkeyboards: beautify shell code and get rid of grep
-
-Jerone Young (1):
-      keymap: Fix micmute remap for Lenovo Thinkpads
-
-Kay Sievers (7):
-      make: add gpg signing bits
-      ignore entire rules line if unknown keys are used
-      do not skip /dev/{disk,char}/M:m removal when the device node is already gone
-      replace AC_DISABLE_STATIC with LT_INIT([disable-static])
-      make: tweak some autofoo according to Flameeyes' recommendations for libabc
-      rules: restore rule to set cdrom group for optical drives
-      rules: fix typo
-
-Martin Pitt (8):
-      check-keymaps.sh: Allow running separately
-      extras/keymap/findkeyboards: Filter out non-event devices
-      findkeyboards: Consistently use spaces instead of tabs
-      keymap: Fix stuck keys on GIGABYTE i1520M
-      keymap: More Asus module variants
-      keymap: Fix "internet" key on HP G62
-      keymap: Fix bluetooth key on Acer TravelMate 7720
-      keymap: Fix stuck keys on BenQ nScreen
-
-
-Summary of changes from v173 to v174
-============================================
-
-David Zeuthen (1):
-      ata_id: Check for Compact Flash card
-
-Jerone Young (1):
-      Add mic mute keycode support for Lenovo Thinkpad USB keyboard
-
-Kay Sievers (34):
-      gtk-doc: delete empty files
-      libudev: list - use binary search for list lookup
-      rules: move input_id to default rules
-      implement path_id, usb_id, input_id as built-in command
-      do not remove static nodes on module unload
-      rules: remove legacy rules for cdrom and usb printer
-      update TODO
-      preserve 'sticky bit' on 'add/change' events
-      libudev: util_get_sys_(subsystem,driver}() -> util_get_sys_core_link_value()
-      export USEC_INITIALIZED= and take timestamp on message receive time
-      libudev: udev_device_get_sysattr_value() return syspath of custom links
-      libudev: list - properly sort linked list not only the index
-      mknod: do not complain about existing node
-      update README
-      libudev: fix typo in documentation
-      rules: fuse: do not mount fusectl from udev rules
-      keymap: add genius keymap to Makefile
-      update NEWS
-      usb_id: can't use global variables when used as built-in
-      remove 'udevadm trigger --type=failed' and SYSFS, ID, BUS keys
-      libudev: export udev_util_encode_string()
-      update TODO
-      systemd: no not start udev in a container
-      systemd: no not start udev in a container
-      delete left-over files in extras/
-      systemd: update drop-in sd-daemon files
-      udevadm: control - use /run/udev/control socket instead of abstract namespace one
-      udevd: control - no not delete socket file when --daemon is used
-      udev_ctrl_cleanup()- accept NULL as argument
-      update NEWS
-      udevd: install into /lib/udev instead of /sbin
-      udevd: add missing braces
-      systemd: use ConditionCapability=CAP_MKNOD instead of ConditionVirtualization=!container
-      rules: do not load sg module
-
-Kir Kolyshkin (1):
-      keymap: add Genius SlimStar 320
-
-Martin Pitt (1):
-      keymap: Update Acer Aspire 5920g
-
-Matthias Clasen (1):
-      make: allow to pass ${ACLOCAL_FLAGS}
-
-Paul Fox (1):
-      keymap: update the OLPC keymap for correct function key behavior
-
-Petr Uzel (1):
-      udevadm: settle - return failure if unknown option is given
-
-Steve Langasek (1):
-      udevd: exit - process events before signals in worker
-
-Thomas Hood (2):
-      keymap: Support keymap overrides in /etc/udev/keymaps
-      keymap: Support for microphone mute button on ThinkPad X220 et al
-
-
-Summary of changes from v172 to v173
-============================================
-
-Allin Cottrell (1):
-      configure: allow to disable mtd_probe
-
-Kay Sievers (15):
-      make: fix 'make tar-sync'
-      udevd: use 'uptime' in debug timestamp
-      udevd: fix (recently) broken static node permission setting
-      rules: mount fuse filesystem only 'add'
-      udevadm: move udevadm command descriptions into their files
-      udev-acl: skip ACLs when systemd is running, disable by default
-      do not delete database when renaming netif, the db name does not change anymore
-      do not allow kernel properties to be set by udev rules
-      configure: reorder options
-      rules: input - do not create (broken) links for bluetooth devices
-      rules: serial - do not export ID_PORT, use ID_USB_INTERFACE_NUM
-      rules: sound - instead of ID_IFACE use standard ID_USB_INTERFACE_NUM
-      keymap: do not run usb_id for bluetooth devices
-      udevadm: trigger --type=failed - log deprecation warning
-      udevd: debug - put timestamp in []
-
-Martin Pitt (4):
-      gudev: Ship JavaScript examples
-      scsi_id: Ship README
-      Remove obsolete extras/scsi_id/scsi_id.config
-      keymap: Only run on key devices
-
-
-Summary of changes from v171 to v172
-============================================
-
-Bastien Nocera (3):
-      accelerometer: add orientation property
-      udev-acl: fix memleak
-      accelerometer: add documentation
-
-Harald Hoyer (2):
-      udevadm-*.c: return != 0, if unknown option given
-      udev/udevadm-monitor.c: fixed misplaced brace
-
-Kay Sievers (33):
-      rules: apply 'audio' group of the static snd/{seq,timer} nodes
-      Makefile: add tar-sync
-      rules: static_node - use 0660 if group is given to get the cigar
-      rule-syntax-check.py: use print()
-      make: use 'git tag'
-      rules: run input_id for main input devices too
-      update TODO
-      configure: add AC_CONFIG_AUX_DIR, AC_CONFIG_SRCDIR
-      cdrom_id: add tray lock and eject handling
-      rules: enable in-kernel media-presence polling
-      update TODO
-      delete mobile-action-modeswitch which has moved to usb_modeswitch
-      libudev: enumerate - scan /sys/module
-      rules: move polling rule above 'block' match
-      libudev: monitor - update doc
-      rules: set polling value only if it is disabled
-      libudev: device - fix udev_device_get_tags_list_entry() to always load database
-      rules: remove redundant MODE="0664" from lp rules
-      rules: fix wrong wildcard match, we always need a ':*' at the end
-      libudev: device - export udev_device_has_tag()
-      path_id: add missing '-' to tape suffix
-      path_id: add ID_PATH_TAG= to be used in udev tags
-      enforce valid TAG+= names
-      update TODO
-      libudev: device - add udev_device_has_tag() to libudev.h and gtk-doc
-      libudev: enumerate - add udev_enumerate_add_match_parent()
-      libudev: enumerate - include parent device itself with match_parent()
-      libudev: enumerate - clarify documentation
-      path_id: recognize ACPI parent devices
-      rules: input - call path_id for ACPI devices
-      udevadm: monitor - use uptime to match the kernel's timestamp
-      libudev: ctrl - move code to udev directory
-      update sd-daemon.[ch]
-
-Keshav P.R (1):
-      rules: support for gpt partition uuid/label
-
-Lee, Chun-Yi (1):
-      Support more MSI notebook by using asterisk on dmi vendor name
-
-Marco d'Itri (1):
-      Add missing commas to 95-keymap.rules
-
-Martin Pitt (3):
-      keymap: Add Microsoft Natural Keyboard
-      keymap: Add force-release quirk for Hannspree SN10.
-      keymap: Add slight name variations of Toshiba Satellites
-
-Peter Jones (1):
-      ata_id: show the error message when HDIO_GET_IDENTITY fails
-
-
-Summary of changes from v170 to v171
-============================================
-
-Kay Sievers (17):
-      libudev: export symbols explicitely and individually from C code not from separate file or prefix match
-      libudev: device - make a bunch of symbols static
-      systemd: Replace Requires= with Wants=, run trigger in parallel
-      systemd: sort trigger after socket
-      systemd: trigger - run after udev.service (for now)
-      systemd: set socket buffer size to 128 MB like udev has
-      update TODO
-      update TODO
-      libudev: monitor - use SOCK_NONBLOCK
-      systemd: split socket file
-      systemd: add missing socket files
-      rules: fix whitespace
-      rules: implement TAGS== match
-      libudev: enumerate - do not ignore other matches when add_match_tag() is used
-      rules: support substitutions in TAG=
-      path_id: allow to be asked about usb_devices not only usb_interfaces
-      systemd: run udev.service and udev-trigger.service in parallel
-
-Scott James Remnant (1):
-      configure: allow usb.ids location to be specified
-
-
-Summary of changes from v169 to v170
-============================================
-
-Kay Sievers (1):
-      libudev: ctrl - properly wait for incoming message after connect
-
-Michal Soltys (1):
-      configure.ac: fixes for rule_generator and modeswitch
-
-
-Summary of changes from v168 to v169
-============================================
-
-Kay Sievers (26):
-      simplify rules file overwrite logic
-      libudev: list - use bit flags for 'sort' and 'unique'
-      libudev: queue - _unref() should return the object
-      remove dead fstab_import files
-      hid2hci: prepare move to bluez package
-      set event timeout to 60 sec and settle timeout to 120
-      udevd: improve error message in case exec() fails
-      configure: allow to enable/disable extras individually
-      delete hid2hci which moved to the bluez tree
-      update TODO/NEWS
-      bump requirement to Linux kernel 2.6.32 and ARM 2.6.36
-      libudev: ctrl - log accept4() errors
-      update NEWS
-      update INSTALL, NEWS, configure comment, queue doc
-      update TODO
-      udevd: create queue file before daemonizing to reliably block 'settle'
-      udevd: remove left-over SIGALRM
-      gudev: silent gtk-doc warnings
-      cdrom_id: remove unused --export switch to silent gcc
-      libudev: queue - always rebuild queue file when nothing is queued anymore
-      libudev: device - use DEVMODE from kernel as the default mode
-      update TODO
-      Merge branch 'docs/udev.xml' of git://github.com/mfwitten/udev
-      udate TODO, NEWS, INSTALL
-      build: use --gc-sections, -fvisibility=hidden
-      udevadm: settle: wake up more often if --seq-start= or --exit-if-exists= is used
-
-Koen Kooi (1):
-      configure: reintroduce introspection flags to fix crosscompilation
-
-Michael Witten (36):
-      Docs: udev.xml: Offset daemon name with commas
-      Docs: udev.xml: Remove commas (and unnecessary repetition)
-      Docs: udev.xml: `are' -> `is'; the subject is `Access'
-      Docs: udev.xml: Use present tense
-      Docs: udev.xml: Clarification through proper wording
-      Docs: udev.xml: `,' -> `;'
-      Docs: udev.xml: `key value' -> `key-value'
-      Docs: udev.xml: `,' -> `:'
-      Docs: udev.xml: Use `assignment' consistently
-      Docs: udev.xml: `comma-separated' is a better description
-      Docs: udev.xml: Remove unnecessary repitition
-      Docs: udev.xml: Add a few more words for context
-      Docs: udev.xml: Use `unless' for clarity
-      Docs: udev.xml: Clarify PROGRAM key
-      Docs: udev.xml: `a shell style' -> `shell-style'
-      Docs: udev.xml: Clean `*' description
-      Docs: udev.xml: Clean character range description
-      Docs: udev.xml: Clean up description of NAME assignment key
-      Docs: udev.xml: Clean up description of SYMLINK assignment key
-      Docs: udev.xml: Clean up description of ENV assignment key
-      Docs: udev.xml: Clean up description of RUN assignment key
-      Docs: udev.xml: Clean up description of LABEL assignment key
-      Docs: udev.xml: Add missing `.'
-      Docs: udev.xml: `which' -> `content of which'
-      Docs: udev.xml: `commandline' -> `command line'
-      Docs: udev.xml: Clean up WAIT_FOR description
-      Docs: udev.xml: `a' -> `the'
-      Docs: udev.xml: Clean up introduction to substitutions.
-      Docs: udev.xml: Use normal sentence structure
-      Docs: udev.xml: Actually make a separate paragraph
-      Docs: udev.xml: Add comma
-      Docs: udev.xml: `char' -> `character'
-      Docs: udev.xml: `comma-separated' is a better description
-      Docs: udev.xml: Clarify through a change in word ordering
-      Docs: udev.xml: Improved word order
-      Docs: udev.xml: Fix dangling modifier
-
-Nix (1):
-      libudev: queue - accept NULL passed into udev_queue_export_cleanup()
-
-
-Summary of changes from v167 to v168
-============================================
-
-David Zeuthen (1):
-      Run ata_id on non-removable USB devices
-
-Harald Hoyer (1):
-      udevd: clarify worker exit status
-
-Kay Sievers (35):
-      version bump
-      systemd: let settle depend on trigger, do not block basic with trigger
-      selinux: do not label files in runtime dir
-      selinux: firmware - do not label files in runtime dir
-      udevadm: control - add --exit
-      trivial cleanups
-      udevd: log warning if /run is not writable
-      libudev: ctrl - fix refcounting in connection handling
-      udevadm: settle - watch queue file
-      libudev: bump revision
-      udevadm: info --cleanup-db
-      udevd: do not nice processes
-      "db_persist=" -> "db_persist"
-      udevd: move OOM disable into --daemon option
-      systemd: add OOMScoreAdjust=-1000
-      require explicit "db_persist" to exclude device info from --db-cleanup
-      udevd: get netlink socket from systemd
-      fix more warnings
-      libudev: ctrl, monitor - use SOCK_NONBLOCK
-      systemd: socket -> sockets
-      udevadm: monitor - use epoll
-      libudev: test - use epoll
-      udevadm:  test - use printf() instead of info() for non-debug output
-      use 'else if' in epoll event array loop
-      libudev: run_program() - select() -> epoll
-      udevd: ppoll() -> epoll + signalfd
-      Merge branch 'docs/README' of git://github.com/mfwitten/udev
-      timeout handling without alarm()
-      udevadm: settle - kill alarm()
-      udevd: netif rename - use ifindex for temporary name
-      udevd: always use udevd[] log prefix
-      udevd: rules files - accept empty or /dev/null links
-      udevd: log signal number when spawned processes fail
-      systemd: Reqires= -> Wants=udev.socket
-      udevd, udev-event: sync waitpid() error handling
-
-Lee, Chun-Yi (1):
-      Add rule for Acer Aspire One ZG8 to use acer-aspire_5720 keymap
-
-Leonid Antonenkov (1):
-      rule-generator: net - ignore Hyper-V virtual interfaces
-
-Martin Pitt (3):
-      Revert "Do not build extras with --disable-extras"
-      Avoid spinning up CD on pressing eject button
-      keymap: Another ID for Logitech Wave keyboard
-
-Michael Reed (1):
-      path_id: rework SAS device handling
-
-Michael Witten (12):
-      Docs: README: `to replace' -> `replacing'
-      Docs: README: `,' -> `;'
-      Docs: README: Clean up a sentence
-      Docs: README: Use present tense
-      Docs: README: Add missing `and'
-      Docs: README: Remove commas and use subjective mood
-      Docs: README: Clean up `udev extras' requirements
-      Docs: README: Clarify configuration of existing devices
-      Docs: README: `does never apply' -> `never applies'
-      Docs: README: Flip sentence structure to improve wording
-      Docs: README: `set up' is the verb; `setup' is a noun
-      Docs: README: Add a comma to offset the modifier
-
-Seth Forshee (1):
-      keymap: Support Dell Latitude XT2 tablet-mode navigation keys
-
-Thomas Egerer (1):
-      udevd: add 'N:' to optstring in getopt_long
-
-
-Summary of changes from v166 to v167
-============================================
-
-Andrey Borzenkov (1):
-      udev-acl: add /dev/sgX nodes for CD-ROM
-
-David Zeuthen (1):
-      cdrom_id: Don't ignore profiles when there is no media available
-
-Harald Hoyer (2):
-      cdrom_id: cd_media_toc() extend toc size to 65536
-      udev-acl/70-acl.rules: tag ID_REMOTE_CONTROL with acl
-
-Kay Sievers (29):
-      version bump
-      Merge branch 'master' of git+ssh://master.kernel.org/pub/scm/linux/hotplug/udev
-      v4l_id: kill the v4l1 ioctl
-      v4l_id: remove left-over variable
-      update some comments
-      test-libudev: add short options
-      libudev: udev_device_get_sysattr_list_entry() update
-      libudev: resolve ifindex in udev_device_new_from_id_filename()
-      libudev: bump minor version
-      udev-acl: move sg rule to optical drive rule
-      move /dev/.udev/ to /dev/.run/udev/ and convert old udev database at udevd startup
-      NEWS: clarify /dev/.run/ requirements
-      input_id: silent gcc warnings
-      fstab_import: disable build
-      systemd: remove deprecated udev-retry.service
-      fstab_import: remove from configure
-      update sd-daemon.[ch]
-      udevd: use facility == LOG_DAEMON when writing to /dev/kmsg
-      udevd: initialize fds, for proper close() on exit
-      use /run/udev/ if possible and fall back to /dev/.udev/
-      rules: run ata_id only on SPC-3 or later optical drives
-      systemd: bind udev control socket in systemd and split udev.service
-      systemd: use sockets.target not socket.target
-      man: remove trigger --type=failed handling
-      libudev: export udev_get_run_path()
-      libudev: docs - add udev_get_run_path()
-      libudev: make valgrind happy
-      systemd: do not enable udev-settle.service by default
-      systemd: udev.socket - disable implicit dependencies
-
-Kei Tokunaga (1):
-      udevadm: enumerate - update prev pointer properly
-
-Lee, Chun-Yi (2):
-      Remap Acer WMI touchpad toggle key to F21 used by X
-      Remap MSI Laptop touchpad on/off key to F22 and F23
-
-Martin Pitt (12):
-      60-persistent-input.rules: Support multiple interfaces
-      Only build v4l_id if V4L1 header file is available
-      60-persistent-input.rules: Do not create duplicate links
-      Fix building with --disable-extras
-      Do not build extras with --disable-extras
-      v4l_id: Drop videodev.h check again
-      keymap: Fix Acer Aspire 5920G media key
-      input_id: Consistently use tabs for indentation
-      input_id: Add some debugging output
-      input_id: Avoid memory overflow with too long capability masks
-      input_id: Cover key devices which only have KEY_* > 255
-      input_id: Rewrite debug logging to use standard udev info()
-
-Seth Forshee (1):
-      keymap: continue reading keymap after invalid scancodes
-
-Thomas Egerer (3):
-      libudev: allow to get list of all available sysfs attrs for a device
-      libudev: use sysfs attr ilist interface for attribute walk
-      udevadm: info - make attribute array static and const
-
-
-Summary of changes from v165 to v166
-============================================
-
-Chris Bagwell (1):
-      Remap Eee PC touchpad toggle key to F21 used by X
-
-Gerd Hoffmann (1):
-      extras: add rules for qemu guests
-
-Jürgen Kaiser (1):
-      keymap: Add Acer Aspire 8930
-
-Kay Sievers (7):
-      version bump
-      man: generate html pages for www.kernel.org
-      man: fix typo
-      make: fix qemu rules file name
-      extras: qemu - fix typo
-      ata_id: do not print empty serial numbers to avoid unwanted trailing '_'
-      update gitignore
-
-Martin Pitt (6):
-      keymap: Add Acer TravelMate C310
-      keymap: Update README.keymap.txt
-      keymap: Add Lenovo ThinkPad X201 tablet
-      keymap: Move reading of event in separate function
-      keymap: More robust state machine
-      keymap: Explain how to end the program
-
-Matthew Garrett (1):
-      keymap: Remove wlan from Dell
-
-
-Summary of changes from v164 to v165
-============================================
-
-Andy Whitcroft (1):
-      keymap: Add release quirks for two Zepto Znote models and AMILO Xi 2428
-
-Bastien Nocera (2):
-      keymap: Add force release for HP touchpad off
-      extras/keymap: Make touchpad buttons consistent
-
-David Henningsson (1):
-      Add ACLs for FFADO supported sound cards
-
-David Zeuthen (6):
-      ata_id: Support SG_IO version 4 interface
-      Run scsi_id and ata_id on the scsi_device object
-      Use ata_id, not scsi_id, on ATAPI devices
-      Add GUdevEnumerator type and Device.get_tags() method
-      Add g_udev_device_get_is_initialized() method
-      gudev: Add Device.get_usec_since_initialized
-
-Harald Hoyer (2):
-      udev-rules.c: change import property buffer to 16384 bytes
-      70-acl.rules: add ACLs for ID_PDA devices
-
-Jakub Wilk (1):
-      man: udev - workaraound -> workaround
-
-Jan Drzewiecki (1):
-      cdrom_id: Fix media state for unreadable DVDs
-
-Kay Sievers (19):
-      version bump
-      rules: 78-sound-card - remove specific hardware matches, they do not belong here
-      rules: drop OSS audio rule
-      rules: drop alsa jack-plug input devices
-      rules: revert bsg use until the event ordering problem is sorted out
-      libudev: do not overwrite path with readlink() call
-      udevadm: info - honor --export and --export-prefix for property query
-      udevadm: info - honor --export, --export-prefix=
-      udevd: use dev_t or netif ifindex as database key
-      udevd: always create /dev/{char,block}/$major:$minor
-      udevd: simplify udev database and fix DEVNAME handling
-      udevd: switch to common id_filename functions
-      udevd: write full database file for (unsupported) renamed device nodes
-      check ifindex > 0 instead of subsystem == "net"
-      libudev: enumerate - allow to filter-out not-already-initialized devices
-      libudev: fix renamed device nodes detection logic
-      libudev: record and export "age" of device record
-      gudev: bump minor version
-      update NEWS
-
-Martin Pitt (5):
-      keymap: Add Sony Vaio VGN71
-      keymap: Add some more Sony Vaio VGN-* models
-      Add ACL for media player USB devices
-      keymap: Fix struck Touchpad key on Dell Latitude E series
-      keymap: Fix struck Touchpad key on Dell Precision M series
-
-Michal Soltys (1):
-      udevd: create static nodes before /dev/null is needed
-
-
-Summary of changes from v163 to v164
-============================================
-
-David Zeuthen (1):
-      Install libgudev-1.0.so in prefix / instead of prefix /usr
-
-Harald Hoyer (1):
-      cdrom_id: request the drive profile features with a dynamic length
-
-Kay Sievers (4):
-      version bump
-      udevd: do not wrongly delay events for devices with swapped names
-      return proper error code in rename_netif()
-      libudev: return kernel provided devnode when asked before we handled any rules
-
-Martin Pitt (2):
-      keymap: Apply force-release rules to all Samsung models.
-      keymap: Add Toshiba Satellite U500
-
-
-Summary of changes from v162 to v163
-============================================
-
-David Zeuthen (2):
-      gudev: Deliver ::uevent signal in the thread-default main loop
-      Bump required GLib version to 2.22
-
-Hannes Reinecke (1):
-      scsi_id: export target port group
-
-Kay Sievers (5):
-      version bump
-      scsi_id: fix compiler warnings
-      systemd: hook into basic.target instead of sysinit.target
-      systemd: sort before basic.target
-      udevd: add sd-daemon.c
-
-Lee, Chun-Yi (1):
-      keymap: Add alternate MSI vendor name
-
-Martin Pitt (8):
-      keymap: Add Lenovo Y550
-      Clarify WAIT_FOR documentation
-      fix various syntax errors in rules
-      Add automatic rules syntax check
-      cdrom_id: Try reading the medium if all MMC commands fail
-      Revert "cdrom_id: Try reading the medium if all MMC commands fail"
-      cdrom_id: Fall back to CDROM_DRIVE_STATUS if all MMC commands fail
-      cdrom_id: Don't read beyond "last track" in TOC
-
-Torsten Schoenfeld (1):
-      gudev: add a few annotations that newer gobject-introspection versions demand
-
-
-Summary of changes from v161 to v162
-============================================
-
-David Woodhouse (1):
-      Add keymap for Lenovo IdeaPad S10-3
-
-Jan Drzewiecki (2):
-      cdrom_id: Drop MEDIA_SESSION_NEXT for DVD-RW-RO
-      cdrom_id: Fix DVD blank detection for sloppy firmware
-
-Kay Sievers (10):
-      init: update systemd service files
-      init: update systemd service files
-      init: add 'udev -' to description in systemd service files
-      udevd: add pid to kmsg logs
-      init: edit systemd service descriptions
-      version bump
-      udevd: remove unneeded credential passing from init_notify()
-      set SELinux context on 'add' but not on 'change' events
-      systemd: enable all udev services unconditionally
-      Revert "Add alternative KVM MAC address blacklist"
-
-Luca Tettamanti (1):
-      Add support for oom_score_adj
-
-Marco d'Itri (2):
-      udev-acl: do not mistake all SCSI "processor" devices for scanner
-      do not create persistent name rules for KVM network interfaces
-
-Martin Pitt (12):
-      cdrom_id: Add media status debugging
-      udev(7): Point out required extension, and remove some confusion
-      keymap: Add Onkyo PC
-      keymap: Add HP G60
-      keymap: Fix Sony VAIO VGN-SZ2HP/B
-      udev(7) manpage: Fix description of $attr
-      gudev: fix crash if netlink is not available
-      keymap: Fix Acer TravelMate 4720
-      cdrom_id: Fix DVD-RW media detection
-      Fix KVM MAC address range
-      do not create persistent name rules for VMWare network interfaces
-      Add alternative KVM MAC address blacklist
-
-Michael Forney (1):
-      Don't install systemd scripts with --without-systemdsystemunitdir
-
-Michal Soltys (1):
-      ChangeLog fix
-
-
-Summary of changes from v160 to v161
-============================================
-
-Fortunato Ventre (1):
-      keymap: Add force-release quirks for a lot more Samsung models
-
-Harald Hoyer (3):
-      udev-event.c: rename interface to <src>-<dest>, if <dest> taken
-      rule_generator/write_net_rules: prevent interface to be named "eth"
-      cdrom_id: READ TOC before READ DISC INFORMATION fixes qemu
-
-Jan Drzewiecki (5):
-      cdrom_id: Fix detection of reblanked DVD+RW and DVD-RAM
-      cdrom_id: Handle pre-MMC2 drives
-      cdrom_id: Also apply format check to DVD-RW
-      cdrom_id: No "next session" for "other" media state
-      cdrom_id: Fix state for fresh DVD-RW
-
-Jerone Young (1):
-      Fix volume keys not releasing on Mivvy G310
-
-Kay Sievers (12):
-      version bump
-      rules: remove firewire rules for deprecated drivers
-      udev-acl: update firewire matches to recent rule changes
-      libudev: bump minor so version after adding symbols
-      call util_delete_path() only when we actually deleted stuff
-      udev-acl: properly handle CK change events for root user
-      udev-acl: remove specific device matches from the rules file
-      fix broken "compile warning fix"
-      always log error when renaming a network interface fails
-      do not rename the database on device rename
-      cdrom_id: whitespace fix
-      cdrom_id: do not bail out when we can not read the TOC like for empty CDRW
-
-Marco d'Itri (3):
-      hid2hci: fix Logitech diNovo, MX5500 and other keyboards
-      log an error when a message from the wrong version of udevadm is ignored
-      hid2hci: fix for Logitech diNovo Edge keyboard
-
-Martin Pitt (1):
-      keymap: Generalize Samsung keymaps
-
-Michal Schmidt (1):
-      udev-acl: really fix ACL assignment in CK events
-
-Richard Hughes (1):
-      udev-acl: add DDC_DEVICE to the types that are managed
-
-Stefan Richter (1):
-      rules: add more FireWire IDs: Point Grey IIDC; AV/C + vendor unique
-
-Yin Kangkai (7):
-      udevadm: fix short options in getopt()
-      udevd: fix some memory leaks in error path
-      malloc()+memset() -> calloc()
-      udevd: fix short options in getopt()
-      udevd: fix unref'ing of device in error path
-      udevd: create static device links only when the target exists
-      udev: fix compile warning
-
-
-Summary of changes from v159 to v160
-============================================
-
-Harald Hoyer (2):
-      60-persistent-storage-tape: s/path_id.sh/path_id/
-      60-persistent-storage-tape.rules: make own by-path symlink for nst tapes
-
-Kay Sievers (4):
-      version bump
-      rules: tape - remove WAIT_FOR instruction and don't export BSG_DEV
-      allow final assignment for OPTIONS:="nowatch"
-      udevd: init_notify() fix abstract namespace name handling
-
-Lennart Poettering (1):
-      systemd: make service files readable by GKeyFile
-
-Martin Pitt (2):
-      keymap: Find alternate Lenovo module
-      keymap: Add Lenovo ThinkPad SL Series extra buttons
-
-
-Summary of changes from v158 to v159
-============================================
-
-Jerone Young (1):
-      Fix stuck volume key presses for Toshiba Satellite U300 & U305models
-
-Kay Sievers (5):
-      version bump
-      add systemd service files
-      make: pre-process and install systemd service files when needed
-      make: fix 'make distcheck'
-      switch a few left-over from GPLv2 to GPLv2 or later
-
-Lennart Poettering (1):
-      systemd: update service files for newly introduced DefaultDependencies= option
-
-Martin Pitt (1):
-      keymap: Add Logitech Cordless Wave Pro
-
-Matthew Garrett (1):
-      keymap: Add support for IBM-branded USB devices
-
-Michael Meeks (1):
-      gudev: respect possibly given LD_LIBRARY_PATH
-
-Ryan Harper (2):
-      Add virtio-blk support to path_id
-      Add virtio-blk by-id rules based on 'serial' attribute
-
-
-Summary of changes from v157 to v158
-============================================
-
-Harald Hoyer (1):
-      extras/keymap: add Samsung N210 to keymap rules
-
-Kay Sievers (7):
-      version bump
-      libudev: fix fd leak in udev_enumerate_scan_devices() when tags are searched
-      udevd: in case we don't daemonize, send READY message to /sbin/init
-      delete last distro specific rules
-      remove a few comments in file headers
-      mtd_probe: add needed include, modprobe blacklist flag, and change some whitespace
-      rules: remove unused subdir
-
-Martin Pitt (4):
-      Fix hid2hci rules harder
-      add Vala vapi for gudev-1.0
-      Revert "add Vala vapi for gudev-1.0"
-      Fix usb printer rule for multiple USB interfaces
-
-Maxim Levitsky (1):
-      mtd_probe: add autodetection for xD cards
-
-Paul Bender (1):
-      configure.ac: fix cross compilation
-
-
-Summary of changes from v156 to v157
-============================================
-
-Harald Hoyer (1):
-      40-redhat.rules: removed file
-
-Jerone Young (3):
-      Fix wlan key on Inspirion 1210
-      Fix wlan key on Inspiron 910
-      Fix wlan key on Inspiron 1010 & 1110
-
-Kay Sievers (25):
-      configure.ac: version bump
-      Makefile.am: silent build mkdir
-      rules: mount fuse control filesystem
-      fix compilation with --enable-debug
-      while (1) -> for (;;)
-      childs -> children
-      udevd: replace --debug-trace with --children-max
-      udevd: fix comments
-      rules: add -v to modprobe calls to be able see what will be loaded
-      udevd:  read debug settings from kernel commandline
-      update NEWS
-      rules: delete pilot rules and remove redhat directory
-      man: add static device nodes and udevd debug options
-      man: add kernel command line parameters
-      man: udevd - update intro
-      rules: rename packages -> arch
-      rules: SUSE - move last distro rule to package
-      rules: add misc/30-kernel-compat.rules
-      make: mkdir /lib/udev/devices/
-      make: fix rules/ subdir names
-      udevd: set umask before creating files/directories
-      add IMPORT{cmdline}
-      IMPORT{cmdline}: start at first char after '='
-      libudev: doc - fix typo
-      update NEWS
-
-
-Summary of changes from v155 to v156
-============================================
-
-Bryan Kadzban (1):
-      udevd: fix typo /proc/fd -> /proc/self/fd
-
-Kay Sievers (4):
-      configure.ac: version bump
-      cdrom_id: do not export ID_CDROM_MEDIA_SESSION_LAST_OFFSET= for single session media
-      rules: optical drives - use ID_CDROM_MEDIA_TRACK_COUNT_DATA
-      libudev: fix udev_queue_get_seqnum_sequence_is_finished() with empty queue file
-
-
-Summary of changes from v154 to v155
-============================================
-
-Kay Sievers (11):
-      reset process priority before executing RUN+=
-      configure.ac: version bump
-      rules: SUSE - delete device-mapper rules
-      libudev: add O_CLOEXEC
-      use default mode of 0600 for nodes if gid == 0
-      udevd: create standard symlinks and handle /lib/udev/devices
-      update NEWS README
-      fix tests and allow MODE=000
-      create static nodes provided by kernel modules to allow module autoloading
-      update NEWS
-      man: directly use 'refentry'
-
-
-Summary of changes from v153 to v154
-============================================
-
-Harald Hoyer (2):
-      Makefile.am: add LGPL COPYING file to EXTRA_DIST
-      cdrom_id: only mark sr[0-9]* as ID_CDROM
-
-Jerone Young (1):
-      Fix volume keys not releasing for Pegatron platform
-
-Kay Sievers (23):
-      configure.ac: version bump
-      more readlink buffer size handling
-      remove left-over from ignore_remove and all_partitions
-      fix previous commit
-      udevadm: info --export-db -- remove watch handle export
-      add TAG= to improve event filtering and device enumeration
-      all to match against a given TAG==
-      udev-acl: use a tag instead of a property to mark devices
-      fix logic on-demand loading logic for db and uevent
-      use the usual TAG+=, TAG= logic
-      delete old tags when configuration changes
-      libudev: accept NULL in udev_device_get_tags_list_entry()
-      export tag functions
-      export udev_device_get_tags_list_entry()
-      udevd: always try to find an idle worker instead of forking a new one
-      remove unused parameter from udev_node_mknod()
-      remove debug output during rules parsing
-      warn when renaming kernel-provided nodes instead of adding symlinks
-      man: udevadm trigger - the default is "change" not "add"
-      update README regarding kernel version and default rules
-      add info message when empty NAME is given
-      libudev: add documentation for recently added functions
-      udevd: reload config only for *.rules files
-
-Martin Pitt (1):
-      keymap: Fix Bluetooth key on Acer TravelMate 4720
-
-Mathias Nyman (1):
-      remove buffer-overrun risk in readlink call
-
-Matthias Schwarzott (1):
-      rules: Gentoo - remove old devfs compat rules
-
-Michael Thayer (1):
-      fix device node deletion
-
-Robby Workman (1):
-      configure.ac: move firmware-path setting out of extras section
-
-Yin Kangkai (2):
-      keymap: Add keymap and force-release quirk for Samsung N128
-      keymap: Add keymap quirk of WebCam key for MSI netbooks.
-
-
-Summary of changes from v152 to v153
-============================================
-
-Kay Sievers (1):
-      configure.ac: version bump
-
-Robby Workman (1):
-      configure.ac: fix broken firmware search path in configure.ac
-
-
-Summary of changes from v151 to v152
-============================================
-
-Adrian Bunk (1):
-      udev needs automake 1.10
-
-Amit Shah (2):
-      Fix virtio-ports rule to use $attr instead of $ATTR
-      rules: virtio - fix is to check if the 'name' attribute is present
-
-Andy Whitcroft (2):
-      keymap: Add Samsung Q210/P210 force-release quirk
-      keymap: Add Fujitsu Amilo 1848+u  force-release quirk
-
-Dan Williams (1):
-      modeswitch: morph into tool that only switches Mobile Action cables
-
-David Zeuthen (3):
-      Decrease buffer size when advancing past NUL byte
-      Use UTIL_LINE_SIZE, not UTIL_PATH_SIZE to truncate properties
-      Increase UTIL_LINE_SIZE from 2048 to 16384
-
-Harald Hoyer (1):
-      cdrom_id: remove debugging code
-
-Jerone Young (6):
-      Force key release for volume keys on Dell Studio 1557
-      Fix Keymapping for upcoming Dell Laptops
-      Add new Dell touchpad keycode
-      Revert special casing 0xD8 to latitude XT only
-      Fix Dell Studio 1558 volume keys not releasing
-      Add support for another Dell touchpad toggle key
-
-Kamal Mostafa (3):
-      keymap: Unite laptop models needing common volume-key release quirk
-      keymap: Add force-release quirk for Coolbox QBook 270-02
-      keymap: Add force-release quirk for Mitac 8050QDA
-
-Kay Sievers (43):
-      libudev: bump minor version
-      udevadm: fix untested and broken commit to set buffer size
-      configure.ac: version bump
-      udev-acl: no not encourage use of ACL_MANAGE outside of rules file
-      replace utimes() with utimensat()
-      libbudev-private: rename udev_list_entry_get_flag()
-      udevadm: monitor - use / as separator in --subsystem-match=subsystem[/devtype]
-      use major:minor as entries in symlink stack instead of devpath
-      use major:minor as entries in watch directory
-      libudev: docs - .gitignore backup files
-      firmware: fix possible segfault when firmware device goes away while loading
-      do not reset SELinux context when the node was not touched
-      libudev: add udev_device_new_from_environment()
-      add LGPL COPYING to libudev and GUdev
-      cdrom_id: open non-mounted optical media with O_EXCL
-      libudev: update documentation
-      extras: mobile-action-modeswitch - update gitignore
-      scsi_id: add rand() in retry loop
-      cdrom_id: retry to open the device, if EBUSY
-      cdrom_id: check mount state in retry loop
-      cdrom_id: always set ID_CDROM regardless if we can run cdrom_id
-      rules: delete outdated packagees rules
-      rules: we do not have static devices which are renamed
-      unify/cleanup event handling
-      allow IMPORT{db}="KEY"
-      usb-db: remove double '/'
-      replace "add|change" with "!remove"
-      update NEWS
-      log info only if we actually delete the node
-      udevadm: trigger - switch default action from "add" to "change"
-      remove "all_partitions" option
-      rules: call modprobe on all events but "remove"
-      remove "ignore_remove" option
-      update NEWS
-      cdrom_id: rework feature/profiles buffer parsing
-      cdrom_id: print more debug messages
-      cdrom_id: debug - print feature values in hex
-      cdrom_id: debug - print feature values in hex
-      cdrom_id: set ID_CDROM_MEDIA=1 only for known media
-      Revert "Fix switching Logitech bluetooth adapters into hci mode."
-      add O_NOFOLLOW when creating files in link stack
-      delete only device nodes, not symlinks when deleting a devtmpfs node
-      doc: add section about how *not* to rename device nodes
-
-Marco d'Itri (3):
-      rules: input - create by-path/ links for pci devices
-      Fix switching Logitech bluetooth adapters into hci mode.
-      doc: document the WAIT_FOR timeout
-
-Martin Pitt (12):
-      keymap: Add Dell Inspiron 1011 (Mini 10)
-      Fix brightness keys on MSI Wind U-100
-      keymap: Fix LG X110
-      keymap: Add Toshiba Satellite M30X
-      udev-acl: Correctly handle ENV{ACL_MANAGE}==0
-      input_id: Fix linking
-      keymap: Add Acer TravelMate 6593G and Acer Aspire 1640
-      keymap: Fix another key for Acer TravelMate 6593
-      cdrom_id: Fix uninitialized variables
-      cdrom_id: Fix uninitialized buffers
-      cdrom_id: Do not ignore errors from scsi_cmd_run()
-      cdrom_id: Swap media state and TOC info probing
-
-Mike Brudevold (1):
-      cdrom_id: add missing profiles to feature_profiles
-
-Robert Hooker (1):
-      keymap: Add support for Gateway AOA110/AOA150 clones.
-
-Scott James Remnant (2):
-      libudev: export udev_monitor_set_receive_buffer_size()
-      udevadm monitor: increase netlink buffer size
-
-Thomas Bächler (1):
-      firmware: fix error reporting on missing firmware files
-
-Yury G. Kudryashov (3):
-      configure.ac - fix typo in --with-pci-ids-path option
-      hid2hci: include linux/types.h for __u32
-      configure.ac: ddd --with-firmware-path option
-
-
-Summary of changes from v150 to v151
-============================================
-
-Amit Shah (1):
-      rules: Add symlink rule for virtio ports
-
-Bryan Kadzban (1):
-      Fix reverted floppy-device permissions
-
-Egbert Eich (1):
-      rulews: suse - add do-not-load-KMS-modules rules
-
-Frederic Crozat (1):
-      rules: acl - add COLOR_MEASUREMENT_DEVICE match
-
-Kay Sievers (11):
-      configure.ac: version bump
-      udevd: inotify - do not parse rules at create but at close
-      do not remove device nodes of active kernel devices
-      libudev: device - create db file atomically
-      clarify message about not removed device node
-      input_id: include limits.h
-      keymap: include linux/limits.h
-      keymap: linux/input.h - get absolute include path from gcc
-      delete outdated and unmaintained writing_udev_rules
-      update README and NEWS
-      update tests
-
-Marco d'Itri (2):
-      writing_udev_rules: update rules files names
-      keymap: support for the Samsung N140 keyboard
-
-Martin Pitt (4):
-      add ACL rule for Garmin GPSMap 60
-      keymap: move force-release directory
-      extras/keymap/check-keymaps.sh: Ignore comment-only lines
-      keymap: Fix invalid map line
-
-
-Summary of changes from v149 to v150
-============================================
-
-Clemens Buchacher (2):
-      add Samsung R70/R71 keymap
-      keymap: Samsung R70/R71 force-release quirk
-
-Daniel Drake (2):
-      keymap: Add OLPC XO key mappings
-      keymap: Fix typo in compal rules
-
-Daniel Elstner (1):
-      libudev: wrap in extern "C" block for C++
-
-David Zeuthen (1):
-      Export ID_WWN_VENDOR_EXTENSION and ID_WWN_WITH_EXTENSION
-
-Jerone Young (1):
-      keymap: Lenovo Thinkpad USB Keyboard with Tracepoint
-
-Johannes Stezenbach (2):
-      keymap: add Samsung N130
-      keymap: handle atkbd force_release quirk
-
-Kay Sievers (15):
-      util_unlink_secure(): chmod() before chown()
-      floppy: fix rule to create additional floppy device nodes
-      configure.ac: version bump
-      remove remaining support for CONFIG_SYSFS_DEPRECATED
-      cdrom_id: remove deprecated device matches
-      rules: add "block" match to floppy rule
-      update mtime of nodes and links when we re-use them
-      udevadm: info - fix info --root --query=name --path= for device without a device node
-      remove remaining support for CONFIG_SYSFS_DEPRECATED
-      fix typo in log message priority handling
-      remove UDEV_RUN environment variable
-      udevadm: logging - copy va_list and do not use it twice
-      libudev: doc - add symbols to sections.txt
-      work around gtk-doc which breaks distcheck
-      gobject-introspection: use $datadir instead of $prefix
-
-Marco d'Itri (2):
-      build: keymap - create subdir
-      rules: udev-acl - add firewire video devices
-
-Martin Pitt (12):
-      keymap: Add Acer Aspire 1810T
-      95-keymap.rules: Run on change events, too
-      keymap: fix findkeyboards
-      Speed up udev_enumerate_scan_*
-      keymap: Add hotkey quirk for Acer Aspire One (AO531h/AO751h)
-      Clarify RUN/IMPORT documentation
-      keymap: Add Logitech S510 USB keyboard
-      keymap: add Acer TravelMate 8471
-      keymap: Add Acer Aspire 1810TZ
-      keymap: Add LG X110
-      keymap: Add Fujitsu Amilo Li 1718
-      keymap: Document force-release
-
-Piter PUNK (1):
-      firmware: convert shell script to C
-
-Scott James Remnant (1):
-      70-acl.rules: ACL manage Android G1 dev phones
-
-Thomas de Grenier de Latour (1):
-      libudev: enumerate - fix move_later logic
-
-
-Summary of changes from v148 to v149
-============================================
-
-Daniel Elstner (1):
-      really fix both in-tree and out-of-tree builds
-
-Dmitry Torokhov (1):
-      input-id: identify touchscreens
-
-Kay Sievers (4):
-      libudev: doc - use #NULL
-      configure.ac: version bump
-      really really fix both in-tree and out-of-tree builds
-      fix both in-tree and out-of-tree builds
-
-Martin Pitt (6):
-      input_id: Fix endless loop for non-input devices
-      input_id: Do not tag non-input devices with ID_INPUT
-      input_id: small optimization
-      input_id: check event mask
-      input_id: Check mouse button for ID_INPUT_MOUSE
-      udev_device_get_parent_with_subsystem_devtype(): Clarify documentation
-
-
-Summary of changes from v147 to v148
-============================================
-
-Dan Williams (3):
-      Revert "modem-modeswitch: add a device"
-      Revert "extras/modem-modeswitch: Add Huawei E1550 GSM modem"
-      modem-modeswitch: 61-option-modem-modeswitch.rules is only for Option NV devices
-
-Daniel Mierswa (1):
-      Fix typo in NEWS, ConsoleKit-0.4.11 -> 0.4.1
-
-David Zeuthen (4):
-      cdrom_id: Still check profiles even if there is no media
-      scsi_id: Export WWN and Unit Serial Number
-      Create /dev/disk/by-id/wwn-0x... symlinks
-      Also create /dev/disk/by-id/wwn-0x..-part%n symlinks for partitions
-
-Dmitry Torokhov (1):
-      extras/input_id: Correctly identify touchpads
-
-Harald Hoyer (1):
-      modem-modeswitch: add a device
-
-Kay Sievers (8):
-      rules: set mode of floppy device nodes to 0660
-      remove "ignore_device"
-      print warning for BUS=, SYSFS{}=, ID=
-      test-udev: remove "ignore_device" code
-      udev-test.pl: catch-up with recent changes
-      rules: remove support for IDE (hd*) devices
-      ata_id: skip ATA commands if we find an optical drive
-      Revert "Fix out-of-tree builds"
-
-Martin Pitt (5):
-      README.keymap.txt: small clarification
-      extras: Add input_id
-      70-acl.rules: Use new-style input properties
-      input: Deprecate ENV{ID_CLASS}
-      input_id: code cleanup
-
-Scott James Remnant (1):
-      Fix out-of-tree builds
-
-
-Summary of changes from v146 to v147
-============================================
-
-Alan Jenkins (1):
-      udevd: queue-export - remove retry loop
-
-Andrew Church (1):
-      fix wrong parameter size on ioctl FIONREAD
-
-Daniel Mierswa (2):
-      don't compare a non-existing function with NULL
-      use nanosleep() instead of usleep()
-
-David Zeuthen (4):
-      gudev: remove G_UDEV_API_IS_SUBJECT_TO_CHANGE since API is now stable
-      ata_id: export more advanced ATA features
-      gudev: Fix up GUdevDeviceNumber
-      gudev: Remove LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE from priv header
-
-Florian Zumbiehl (10):
-      util_delete_path(): use util_strscpy()
-      util_lookup_group(): fix memory leak if realloc() fails
-      util_delete_path(): handle multiple leading slashes
-      util_create_path(): fix possible out of bounds array access
-      ude_rules.c: fix possible NULL pointer dereference in get_key()
-      util_resolve_sys_link(): fix possible buffer overflow
-      udev_util_encode_string(): fix possible buffer overflow
-      udev-rules.c: parse_file() - fix possible buffer overflow
-      udev_queue_get_seqnum_sequence_is_finished(): fix possible file handle leak
-      util_run_program(): fix possible buffer overflow #2
-
-Harald Hoyer (2):
-      scsi_id: prevent buffer overflow in check_fill_0x83_prespc3()
-      rename interfaces to <iface>_rename if rename fails
-
-Jeremy Kerr (1):
-      util_run_program: restore signal mask before executing event RUN commands
-
-Kay Sievers (45):
-      make: sort Makefile.am per target/extra
-      configure.ac: version bump
-      udev-acl: allow to skip ACL handling
-      rules: rfkill has no group, so use 0644
-      rule_generator: net - fix MATCHDEVID
-      make: add comment
-      update NEWS
-      print warning for NAME="%k" - it breaks the kernel supplied DEVNAME
-      warn about non-readable or empty rules file
-      change database file names
-      assign errno for getgrnam_r()/getpwnam_r()
-      doc: udevadm test *does* create nodes and links these days
-      util_unlink_secure(): chmod() before chown()
-      util_create_path(): fix errno usage
-      inotify_add_watch(): do not store watch, if it failed
-      update TODO
-      update README
-      rules: suse - use NAME for mapper/control
-      libudev-util.c: get_sys_link() - return error for empty link target
-      udev-rules.c: remove 'first_token' variable
-      Revert "udev-rules.c: remove 'first_token' variable"
-      test: catch possible bug in GOTO resolving
-      udevadm: remove symlink support for old commands
-      util_run_program(): skip multiple spaces in argv creation
-      fix whitespace
-      require 2.6.27 for proper signalfd handling
-      fix randonm findings from llvm-clang-analyzer
-      simplify "symlink name stack"
-      reorder create_path() and node/link creation to be called in a direct sequence
-      put util_create_path() and file creastion in a retry loop
-      udevadm: control - remove compat code
-      scsi_id: delete copy of bsg.h
-      fix SYMLINK{} option parsing
-      rules: remove remaining NAME="%k"
-      rules: drop almost all NAME= keys
-      update TODO, NEWS
-      udevd: serialize events for with the same major/minor
-      break loops if util_create_path() returns error
-      remove "last_rule" option
-      use CLOEXEC flags instead of fcntl()
-      unblock signals we might want to handle
-      udevd: create /dev/.udev/rules.d/ before watching it wit inotify
-      gudev: fix pkg-config call to work with "make distcheck"
-      update NEWS
-      Revert "gudev: fix out-of-tree build"
-
-Lennart Poettering (5):
-      pci-db: make sure we actually read the pci.ids file instead of usb.ids
-      sound: recognize saa7134 TV card sound devices as TV cards
-      sound: include ALSA sound card id in ID_ID property
-      sound: include ALSA sound card id in /dev/snd/by-id/ links
-      Revert "sound: include ALSA sound card id in /dev/snd/by-id/ links"
-
-Marco d'Itri (6):
-      doc: writing_udev_rules updated for the new command names
-      rules: sound - do not use /usr/bin/env
-      udevadm: print all messages to stderr with priority higher or equal than LOG_ERR
-      udevadmi: control = exit with rc=2 if there is some system error
-      gudev: gir-scanner workaround for out of tree builds
-      gudev: fix out-of-tree build
-
-Mario Limonciello (1):
-      hid2hci: remove superfluous bmAttributes match
-
-Martin Pitt (24):
-      extras/keymap: Add Acer Aspire 6920
-      extras/modem-modeswitch: eject ZTE MF6xx fake CD-ROMs
-      extras/keymap: Fix hold key on Acer Aspire 6920
-      extras/keymap: Fix case matching for Micro-Star
-      Revert "extras/keymap: Fix case matching for Micro-Star"
-      make raw USB printer devices accessible for lp
-      modem-modeswitch rules: Match more devices
-      extras/keymap: fix hash table collisions
-      extras/keymap: Rename KEY_COFFEE to KEY_SCREENLOCK
-      fix single-session CD detection
-      fix previous commit for CD detection
-      make raw USB printer devices world-readable again
-      50-udev-default.rules: fix printer MODE
-      keymap: Add Logitech Wave USB
-      keymap: add missing map file
-      keymap: fix usb_id invocation
-      keymap: make USB keyboards really work
-      keymap: Add Logitech Wave cordless
-      keymap: add HP Pavillion dv6315ea
-      keymap: add HP 2230s
-      Makefile.am: fix build with mawk
-      extras/keymap/README.keymap.txt: Fix bug report link
-      fix major fd leak in link handling
-      modem-modeswitch: fix ZTE MF6xx rule
-
-Matthias Schwarzott (2):
-      rules: Gentoo update
-      rules: Gentoo update
-
-Maxim Levitsky (1):
-      keymap for Acer Aspire 5720
-
-Peter Rajnoha (1):
-      libudev: allow to store negative values in the udev database
-
-Scott James Remnant (1):
-      util_run_program: *really* restore signal mask before executing event RUN commands
-
-William Jon McCann (1):
-      udev-acl: catch up with ConsoleKit 0.4.1
-
-
-Summary of changes from v145 to v146
-============================================
-
-Alan Jenkins (3):
-      man: fix unused, inaccurate metadata
-      man: SYMLINK can be matched as well as assigned
-      fix spelling
-
-Anssi Hannula (2):
-      rules: exclude digitizers from joystick class
-      udev-acl: add joystick devices
-
-Diego Elio 'Flameeyes' Pettenò (21):
-      Merge libudev, udev, and the unconditional extras in a single Makefile.am.
-      Replace the custom test-run target with the standard make check.
-      Also merge into the top-level Makefile.am the simpler extras.
-      Change hook handling to be more portable.
-      Merge keymap building in the top-level Makefile.am.
-      Make keymap generation rules be silent (backward-compatible).
-      Move pkg-config docs and man pages before conditionals.
-      Finally, also merge gudev into the top-level Makefile.am.
-      Make sure to clean up all the built sources.
-      Make sure to use dependency/target variables.
-      Add silent-rule support for the gudev rules.
-      Fix building of introspection library on top-level Makefile.am.
-      Fix another relative path for the new working directory.
-      Include the correct directory for out-of-source builds.
-      Add tests to the distribution; this fixes "make distcheck".
-      Ask gperf to use ANSI-C for generation.
-      Merge in Makefile.am.inc into Makefile.am
-      Use the keymap check during “make distcheck” rather than “check”.
-      Fix building of documentation when doing out-of-source builds.
-      Fix “make distcheck” run outside of the source directory.
-      Use LT_INIT to explicit that udev needs libtool series 2.
-
-Eric W. Biederman (1):
-      fix util_lookup_group to handle large groups
-
-Erik Forsberg (1):
-      extras/modem-modeswitch: Add Huawei E1550 GSM modem
-
-Kay Sievers (18):
-      udevd: add timestamp to --debug output
-      v4l_id: exit with 0 when --help is given
-      configure.ac: version bump
-      hid2hci: remove hid structures and include kernel header
-      path_id: make global variable static
-      udevadm: trigger - add --sysname-match=
-      rules: serial - fix path_id call
-      path_id: fix typo in comment
-      format names are not case insensitive
-      hid2hci: rewrite (and break) rules and device handling
-      make: build internal tools against libudev-private.la
-      update a few years of copyright
-      libudev: silent gcc warning: may be used uninitialized in this function
-      make: suppress enter/leaving directory messages
-      re-enable failed event tracking
-      "record_failed" -> "fail_event_on_error"
-      udevd: block for 15 seconds after error when too old kernel is detected
-      make: fix issues from non-recursive conversion
-
-Lennart Poettering (1):
-      enumeration: move ALSA control devices to the end of the enumerated devices of each card
-
-Mario Limonciello (2):
-      hid2hci: support to hid2hci for recovering Dell BT devices after S3
-      hid2hci: install re-trigger for hid device when recovering from S3
-
-Martin Pitt (17):
-      add keymap for Clevo D410J laptop
-      extras/keymap: add Zepto ZNote
-      extras/keymap: add Everex Stepnote XT5000T
-      extras/keymap: add Compal Hel80i
-      keymap tool: improve help
-      keymap tool: support scancode/keycode pair arguments
-      keymap: inline one-line key maps
-      extras/keymap: fix check-keymaps.sh for inline mappings
-      extras/keymap: add recently added keymap files to Makefile.am
-      extras/keymap: Add HP Presario 2100
-      extras/keymap: cover more Compaq Evo models
-      extras/keymap: Add Fujitsu Amilo M
-      extras/keymap: teach findkeyboards about USB keyboards
-      extras/keymap: Add Samsung SX22S
-      extras/keymap: Fix crash for unknown keys
-      extras/keymap: Add Samsung NC20
-      extras/keymap: Fix Bluetooth key on Acer Aspire 6920
-
-
-Summary of changes from v144 to v145
-============================================
-
-Ian Campbell (1):
-      scsi_id: correct error handling in prepend_vendor_model
-
-Kay Sievers (10):
-      README: add CONFIG_BLK_DEV_BSG
-      use MIN() MAX() from param.h
-      configure.ac: version bump
-      libudev: device - free values before updating them
-      libudev: enumerate - sort with qsort()
-      udevd: detach event from worker if we kill a worker
-      udevadm: info - add space after R:, A:, W: on database export
-      udevd: make sure a worker finishes event handling before exiting
-      udevd: handle SIGCHLD before the worker event message
-      udevd: use bool
-
-
-Summary of changes from v143 to v144
-============================================
-
-Jon Masters (1):
-      firmware: search for third party or sysadmin supplied firmware updates
-
-Kay Sievers (19):
-      configure.ac: add AM_SILENT_RULES
-      configure.ac: version bump
-      TODO: add cleanup of ATA_COMPAT
-      libudev: queue - add comments for queue format
-      udev/.gitignore: add udev.pc
-      configure.ac: version bump
-      do not exports properties starting with a '.'
-      scsi_id: --reformat_serial - use udev_util_replace_whitespace()
-      ata_id: sync ID_SERIAL(_SHORT) with other *_id tools
-      rules: make ata_id properties the default for all ATA block devices
-      scsi_id: delete no longer needed config file
-      update NEWS
-      man: udev - add private properties like ENV{.FOO}="bar"
-      Merge branch 'firmware' of git://git.kernel.org/pub/scm/linux/kernel/git/jcm/udev-jcm
-      udevadm: test - print list of properties
-      build: do not delete .la files
-      libudev: monitor - handle kernel supplied DEVNAME properly
-      update NEWS
-      build: add *exec* to the internal rootlibdir name
-
-Martin Pitt (2):
-      hid2hci: narrow matches to real HCI devices
-      extras/udev-acl: add smartcard readers
-
-Stefan Richter (1):
-      rules: set group ownership of new firewire driver device files
-
-
-Summary of changes from v142 to v143
-============================================
-
-Alan Jenkins (5):
-      udevadm: settle - fix timeout
-      udevd: remove tiny bit of dead code
-      udevd: implement a more efficient queue file format
-      udev-selinux.c: remove libudev header
-      udevd: queue-export - fix crash
-
-Benjamin Gilbert (1):
-      test: check string substitutions in OWNER and GROUP
-
-Dan Williams (2):
-      rules: tty/net - move from udev-extras
-      extras/modem-modeswitch: move from udev-extras
-
-David Zeuthen (1):
-      gudev: move from udev-extras
-
-Kay Sievers (95):
-      version bump
-      rules: v4l do not mix vbi and video nodes
-      fix possible endless loop for GOTO to non-existent LABEL
-      Revert "rules: v4l do not mix vbi and video nodes"
-      rule-generator: cd - skip by-path links if we create by-id links
-      remove format char string truncation syntax
-      use more efficient string copying
-      edd_id: use openat()
-      use openat(), unlinkat(), fstatat()
-      update TODO
-      remove unused GL_FORMAT from rules parser
-      require key names in uppercase
-      keep the ifdef'd udevd testing/profiling hack
-      fix location of database files
-      udevadm: settle - make --timeout=0 working
-      update NEWS
-      rules: add SUBSYSTEM match to scsi rules
-      cdrom_id: suppress ID_CDROM_MEDIA_STATE=blank for plain non-writable CDROM media
-      udevadm: control - add comment to man page about --reload-rules
-      cdrom_id: add error message if open() fails
-      udevadm: settle - add --exit-if-exists=<file>
-      udevd: remove check for dev_t, DEVPATH_OLD takes care of that
-      str[sp]cpyl: add __attribute__ ((sentinel))
-      udevd: convert to event worker processes
-      udevd: close netlink socket in worker and set cloexec
-      rules: do not call path_id for virtual devices
-      udevd: use enum instead of char in struct declaration
-      allow format substitution in path of ATTR{<path>}=="<value>"
-      cleanup $attr{} substitution
-      path_id: implement in C using libudev
-      path_id: update SCSI handling
-      path_id: add comments
-      fix signed/unsigned warning
-      libudev: enumerate - allow multiple keys with the same name
-      udevadm: trigger - add --property-match=<key>:<value>
-      udevadm: info - accept --query without a value and print properties
-      udevadm: control - --env -> --property
-      udevadm: monitor --environment -> --property
-      path_id: handle fibre channel
-      path_id: add iscsi support
-      path_id: delete old shell script
-      udevd: print error if worker dies unexpectedly
-      path_id: rename scsi sub-fuctions
-      libudev: add comments to libudev.h
-      libudev: move to top-level directory
-      fix libudev include in Makefile.am.in
-      libudev: device_new() -> udev_device_new()
-      udevd: log info for created/killed workers
-      libudev: call log functions conditionally
-      move syslog wrapper to libudev
-      move common stuff from udev/ to private parts of libudev/
-      libudev: rename private files to *-private.c
-      rules: remove scsi ch module loading rule
-      update NEWS
-      udevadm: info -revert "accept --query without argument"
-      README: add kernel options
-      README: add INOTIFY and SIGNALFD
-      USE_LOG -> ENABLE_LOGGING, DEBUG -> ENABLE_DEBUG, USE_SELINUX -> WITH_SELINUX
-      libudev: add gtk-doc
-      libudev: update documentation
-      libudev: doc - add section headers
-      libudev: doc - add enumerate
-      libudev: doc - add queue
-      update TODO
-      libudev: doc - add namespace for index
-      libudev: move .so version to libudev Makefile
-      autogen.sh: simplify
-      TODO: update
-      libudev: remove prefix from .so version variables
-      libudev: doc - add empty libudev.types
-      udev-acl: move from udev-extras
-      INSTALL: add --enable-extras
-      udev-acl: handle missing action when called in CK mode
-      v4l_id: move from udev-extras
-      libudev: doc - libudev-docs.sgml -> libudev-doc.xml
-      gudev: fix typo in configure option
-      v4l_id: 70-v4l.rules -> 60-persistent-v4l.rules
-      configure: enable all extras by default, provide --disable-extras
-      autogen.sh: make "CFLAGS=-O0 ./autogen.sh" working
-      NEWS: add --disable-extras
-      cleanup ./configure installation directory options
-      rules: remove MMC rule, 2.6.30 has the modalias
-      configure.ac: print error if gperf is missing
-      libudev: install in $libdir and move later to $rootlibdir
-      extras/keymap: use LIBEXECDIR instead /lib/udev
-      README: add /lib/udev/ is private
-      rules: do not install usb-id/pci-id rules when --disable-extras is used
-      extras: delete man pages for private udev tools
-      README: update
-      extras/keymap: install findkeyboards in /lib/udev
-      INSTALL: use /sbin instead of %{sbindir}
-      NEWS: update
-      udev.pc: add
-      Merge branch 'master' of git+ssh://master.kernel.org/pub/scm/linux/hotplug/udev
-      docs: install writing_udev_rules
-
-Lennart Poettering (2):
-      rules: sound - move from udev-extra
-      usb-db: move from udev-extras
-
-Marcel Holtmann (1):
-      rules: make RFKILL control device world readable
-
-Mario Limonciello (1):
-      hid2hci: move from udev-extras
-
-Martin Pitt (5):
-      keymap: move from udev-extras
-      extras/keymap: Fix WLAN button on ThinkPads
-      keymap: Update findkeyboard path in docs
-      udev-acl: Manage hplip device permissions
-      extras/keymap: Update findkeyboards location
-
-Matthias Schwarzott (3):
-      rules: Gentoo update
-      rules: Gentoo update
-      rules: Gentoo update
-
-Scott James Remnant (1):
-      OWNER/GROUP: fix if logic
-
-
-Summary of changes from v141 to v142
-============================================
-
-Andre Przywara (1):
-      rules: create /dev/cpu/<n>/cpuid world readable
-
-Ian Campbell (1):
-      path_id: support identification of Xen virtual block devices
-
-John Wright (1):
-      edd_id: add cciss devices
-
-Kay Sievers (46):
-      version bump
-      libudev: path_encode - always return 0 if encoded string does not fit into size
-      libudev: monitor - clarify socket handling documentation
-      udevd: log error for too old kernels or CONFIG_SYSFS_DEPRECATED
-      rules: remove DVB shell script
-      update NEWS
-      cdrom_id: add Xen cdrom support
-      test-libudev: update monitor source
-      TODO: add packet filter
-      update NEWS
-      cdrom_id: add and use ID_CDROM_MEDIA to decide if we run vol_id
-      libudev: monitor - add client socket filter for subsystem value
-      udevadm: monitor - print error if we can not bind to socket
-      update TODO
-      udevadm monitor - add --subsystem-match=
-      libudev: monitor - use simpler hash
-      libudev: monitor - switch to filter_add_match_subsystem_devtype()
-      libudev: monitor - do not filter messages with wrong magic
-      udevadm: monitor - add <subsytem>:<devtype> support
-      libudev: monitor - add udev_monitor_filter_remove
-      libudev: queue - fix get_seqnum_is_finished()
-      cdrom_id: skip media tests if CDROM_DRIVE_STATUS != CDS_DISC_OK
-      libudev: queue - clarify comments
-      libudev: monitor - export filter_update()
-      update NEWS
-      drop "extern" keyword from non-static function
-      rule_generator: net - fix usb comment generation
-      rules: input - add links for USB/platform non-kbd/mouse devices
-      rules: input - fix comments
-      rules: add rfcomm* to group dialout
-      accept DEVNAME from the kernel as a hint for the node name
-      update TODO
-      build: use AC_MSG_RESULT
-      rules: add "event*" match
-      udevd: revert initial device node creation
-      rules: remove initramfs comment
-      handle devtmpfs nodes
-      oops, removed ppp entry from rules got committed
-      remove all PHYSDEVPATH handling and warning about
-      remove asmlinkage
-      rules: fix ieee1394 rules
-      add "static" back to the inline functions
-      update TODO
-      delete vol_id and require util-linux-ng's blkid
-      delete libvolume_id
-
-Lubomir Rintel (1):
-      rule-generator: net - whitelist NICs that violate MAC local scheme
-
-
-Summary of changes from v140 to v141
-============================================
-
-Adam Buchbinder (4):
-      usb_id: add manpage
-      cdrom_id: update manpage
-      create_floppy_devices: expand manpage
-      vol_id: fix language in manpage
-
-Alan Jenkins (1):
-      avoid leaking netlink socket fd to external programs
-
-Borislav Petkov (1):
-      rules: rename ide-floppy to ide-gd
-
-David Brownell (1):
-      rules: exclude mtd* from persistent disk links
-
-Kay Sievers (15):
-      rules: fix extra quote in 50-udev-default.rules
-      version bump
-      udevadm: test - handling trailing '/' in devpath
-      udevadm: monitor - clarify printed header
-      rules: remove ram* from persisten disk links blacklist
-      rules: serial - support ttyACM devices
-      rules: replace IDE driver with media match
-      usb_id: add ID_VENDOR_ID, ID_MODEL_ID, ID_USB_INTERFACE_NUM, ID_USB_DRIVER
-      libudev: GPL -> LGPL
-      usb_id: remove unused variable
-      send monitor events back to netlink socket
-      "UDEV_MONITOR_KERNEL/UDEV" -> "kernel/udev"
-      IMPORT: 2048 -> 4096 bytes buffer
-      path_encode: fix max length calculation
-      libudev: monitor - unify socket message handling
-
-Michal Soltys (1):
-      rules: md-raid.rules fix
-
-Robby Workman (1):
-      udevadm: trigger - add "--action" to --help
-
-Scott James Remnant (1):
-      libudev: monitor - ignore messages from unusual sources
-
-
-Summary of changes from v139 to v140
-============================================
-
-Harald Hoyer (1):
-      libvolume_id: bump age
-
-Kay Sievers (12):
-      version bump
-      update TODO
-      volume_id: ntfs - fix uuid setting
-      update TODO
-      rules: Fedora update
-      libudev: queue - use lstat() to check existence of symlink
-      udevadm: settle - add --seq-start= --seq-end=
-      udevd: switch watch symlinks to devpath
-      udevadm: add text for new options to command and man page
-      update TODO
-      libudev: ctrl - return error after sending ctrl message
-      udevadm: settle - use timeout signal, instead of loop counter
-
-Michael Prokop (1):
-      fix compile error in debug mode
-
-Scott James Remnant (1):
-      udevadm: settle - synchronise with the udev daemon
-
-
-Summary of changes from v138 to v139
-============================================
-
-Kay Sievers (11):
-      version bump
-      remove static local variable
-      use the event udev_device to disable the watch on "remove"
-      add "nowatch" to disable a default installed watch with a later rule
-      add m4/ subdir
-      use AC_USE_SYSTEM_EXTENSIONS instead of AC_GNU_SOURCE
-      usb_id: add ID_USB_INTERFACES=:0e0100:0e0200:010100:010200:
-      usb_id: return values if called directly for an usb_device
-      usb_id: fix NULL string usage
-      usb_id: fix comment
-      udevadm: info - export all devices with --export-db
-
-Scott James Remnant (10):
-      Don't add inotify watch until RUN rules processed.
-      Clear existing inotify watch before processing.
-      Cleanup a little.
-      Allow watch handle to be stored in the udevdb.
-      Store watch handle in db.
-      Use the udevdb to speed up watch clearing.
-      Put a log message in a more sensible place.
-      Output watch handle in udevadm info.
-      lookup the old watch handle; reload only if has a path
-      Look at more inotify events in the buffer than just the first.
-
-
-Summary of changes from v137 to v138
-============================================
-
-David Zeuthen (1):
-      *_id: add model/vendor enc strings
-
-Karel Zak (2):
-      vol_id: fix ddf version string
-      vol_id: add missing id->type to swap0
-
-Kay Sievers (13):
-      man: fix grammar
-      version bump
-      fix NAME="" logic
-      rules: dm - add escape for uuid links with whitespace
-      test: add test for empty and non-existent ATTR
-      rules: fix md "change"/"remove" handling
-      autogen.sh: add more warnings
-      fix NAME= and OPTION+="string_escape=..." logic
-      rules: move OPTIONS to separate rule
-      use global "reload_config" flag
-      rules: add "watch" option to dm and md rules
-      rules: include loop block devices in persistent links
-      release 138
-
-Matthias Schwarzott (1):
-      rules: Gentoo update
-
-Miklos Vajna (1):
-      doc: writing udev rules - refer to 'udevadm info' instead of 'udevinfo'
-
-Scott James Remnant (2):
-      udevd: optionally watch device nodes with inotify
-      rules: update persistent storage rules to use inotify watches
-
-
-Summary of changes from v136 to v137
-============================================
-
-Alan Jenkins (2):
-      man: typo fixes
-      remove stray initializer
-
-Kay Sievers (17):
-      version bump
-      rules: fix typo in ide cd rule
-      libudev: use 4096 bytes buffer for attribute reading
-      rules: add drm devices to group "video"
-      do not complain about a missing /etc/udev/rules.d/
-      udevadm: test - remove --force option
-      update NEWS
-      remove name from index if the node name has changed
-      cleanup old names before creating the new names
-      open-code pollfd setup
-      increase netif renaming timeout from 30 to 90 seconds
-      Merge commit '5f03ed8a56d308af72db8a48ab66ed68667af2c6'
-      Merge commit '9032f119f07ad3b5116b3d4858816d851d4127de'
-      split up long line
-      udevd: add back SA_RESTART
-      usb_id: handle ATAPI devices like SCSI devices
-      udevadm: settle - fix typo
-
-Lennart Poettering (1):
-      fix naming for tape nst devices in /dev/tape/by-path/
-
-Olaf Kirch (2):
-      udevd: use ppoll instead of signal pipes
-      reap children faster
-
-Scott James Remnant (2):
-      Allow user and group lookup to be disabled.
-      Expose delayed name resolution
-
-Sven Jost (1):
-      volume_id: support via raid version 2
-
-
-Summary of changes from v135 to v136
-============================================
-
-Adam Buchbinder (1):
-      extras: fix mis-spelling of "environment"
-
-Harald Hoyer (1):
-      rule_generator: fix enumeration for write_cd_rules
-
-Jeremy Higdon (1):
-      path_id: rework SAS persistent names
-
-Karel Zak (1):
-      volume_id: HPFS code clean up
-
-Kay Sievers (54):
-      rules: ATA_COMPAT do not try to match on sr*, it will never have vendor ATA
-      scsi_id: do not fail if no serial is found like for optical drives
-      update configure and NEWS
-      rules: fix isdn rules
-      rules: add persistent /dev/serial/{by-id,by-path} rules
-      make: install serial rules file
-      make: do not delete autotools generated file with distclean
-      udevadm: settle - allow --timeout=0 and --quiet
-      rules: move aoe rules to default rules file
-      volume_id: btrfs - update format
-      rules: add "do not edit header"
-      volume_id: support sub-uuid's and plug in btrfs device uuid
-      libudev: include <sys/types.h>
-      build: add -lsepol
-      build: just use autoreconf -i
-      rules: remove ide-scsi
-      rules: first simple step merging with Ubuntu rules
-      "'/sbin/modprobe abnormal' exit" - also print program options
-      rules: more changes toward Ubuntu rules merge
-      rules: more changes toward Ubuntu rules merge
-      rules: remove /dev/raw/raxctl symlink, it's a devfs leftover
-      rules: rtc - create rtc compat link only for cmos type rtc
-      rules: remove legacy symlinks
-      rules: do not put raw1394 in "video" group
-      rules: second round merging with Ubuntu rules
-      rules: remove /dev/dsp /dev/audio
-      rules: put alsa in group "audio"
-      rules: isdn - remove /dev/isdn/capi20 symlink
-      rules: provide /dev/raw/rawctl
-      if needed, store database entries also for devices which do not have a device node
-      build: use autoreconf --symlink
-      usb_id: add "image" class
-      require non-SYSFS_DEPRECATED 2.6.20+ kernel
-      build: default to --prefix=/usr --exec-prefix=""
-      libudev: enumerate - add lookup by property
-      rules: input - make sure needed variables are set
-      libudev: device - read "uevent" only if info is not already loaded
-      libudev: subsytem -> subsystem
-      libudev: bump revision
-      usb_id: use devtype lookup
-      require 2.6.22+ kernel
-      rules: Ubuntu merge - use group "cdrom"
-      rules: Ubuntu merge - use group "tape"
-      rules: replace DVB shell script rule
-      rules: Ubuntu merge - s/uucp/dialout/
-      update NEWS
-      update NEWS
-      enable skipping of "naming-only" rules
-      usb_id: s/image/media/
-      udevadm: s/udevinfo/udevadm info/
-      rules: reorder block rules
-      rules: zaptel - add "dialout" group
-      libudev: device - add udev_device_get_property_value()
-      libudev: test - add udev_device_get_property_value()
-
-Marcel Holtmann (3):
-      libudev: device - add devtype support
-      libudev: device - lookup subsystem and devtype together
-      libudev: device - remove udev_device_get_parent_with_subsystem
-
-Michal Soltys (1):
-      man: udev - update NAME assignment
-
-Ryan Thomas (1):
-      rules: add rules for AoE devices
-
-
-Summary of changes from v134 to v135
-============================================
-
-Kay Sievers (6):
-      usb_id: add "break" to currently unused case labels
-      rules: fix cciss disk/by-id/ links
-      rules: add infiniband rules
-      rules: infiniband.rules -> 40-infiniband.rules
-      fix network interface name swapping
-      update configure and NEWS
-
-Marcel Holtmann (1):
-      usb_id: fix switch statement for video type
-
-Piter PUNK (2):
-      rules: /dev/null -> X0R
-      rules: add usb device nodes
-
-
-Summary of changes from v133 to v134
-============================================
-
-Gabor Z. Papp (1):
-      include errno.h in sysdeps.h
-
-Harald Hoyer (1):
-      rules: add persistent rules for memory stick block devices
-
-Kay Sievers (19):
-      autogen.sh: fix -print-multi-os-directory usage
-      volume_id: update btrfs magic
-      bump version
-      rules: merge group "video" into default rules
-      rules: v4l - add by-id/ links for USB devices
-      libudev: accept NULL whitelist in util_replace_chars()
-      usb_id: replace chars in returned strings
-      ata_id: make sure, we do not have slashes in values
-      scsi_id: make sure, we do not have slashes in values
-      volume_id: remove unused usage types
-      vol_id: if regular files are probed, use stat() for the size value
-      volume_id: update btrfs
-      volume_id: clear probing result before probing and do not probe a second time, if not needed
-      path_id: fix fibre channel handling
-      update NEWS TODO
-      floppy: use ARRAY_SIZE()
-      fix handling of swapping node name with symlink name
-      silence PHYSDEV* warning for WAIT_FOR* rules
-      rules: exclude "btibm" devices from vol_id calls
-
-Matthias Schwarzott (1):
-      rules: Gentoo update
-
-Peter Breitenlohner (2):
-      man: fix typos
-      floppy: fix array bounds check and minor calculation
-
-
-Summary of changes from v132 to v133
-============================================
-
-Alan Jenkins (2):
-      udevd: de-duplicate strings in rules
-      scsi_id: we don't use DEVPATH env var anymore, update man page
-
-Karel Zak (1):
-      volume_id: fat - move check for msdos signature (0x55 0xaa)
-
-Kay Sievers (22):
-      silence "comparison between signed and unsigned"
-      string index - split nodes and childs to allow and unlimited number of childs
-      reserve child slot 0
-      merge trie nodes, childs and root into a single array
-      set errno = ENOSYS in inotify stub
-      udevadm: info - unify -V and --version
-      rules: remove DEVTYPE disk/partition
-      rules: remove pnp shell script, acpi loads these modules properly
-      update NEWS
-      configure: add linux-hotplug mail address
-      remove len == 0 check, the index root is always '\0'
-      volume_id: bump revision
-      volume_id: always check for all filesystem types and skip conflicting results
-      volume_id: fat - accept empty FAT32 fsinfo signature
-      fix spelling in comment
-      volume_id: ntfs - mark as no other fs must match
-      vol_id: clarify error message
-      libudev: device - handle disk "device" link for partitions in deprecated sysfs layout
-      limit $attr(<symlink>) magic to well-known links only
-      udevd: fix cleanup of /dev/.udev/uevent_seqnum
-      fix $links substitution for devices without any link
-      update NEWS
-
-Sergey Vlasov (1):
-      udevadm: fix option parsing breakage with klibc
-
-
-Summary of changes from v131 to v132
-============================================
-
-Kay Sievers (2):
-      fix size_t compiler warning on 32 bit platforms
-      convert debug string arrays to functions
-
-
-Summary of changes from v130 to v131
-============================================
-
-Alan Jenkins (17):
-      libudev: fix sysnum logic for digit-only device names
-      udevd: avoid overhead of calling rmdir on non-empty directories
-      use more appropriate alternatives to malloc()
-      libudev: util - optimize path_encode()
-      libudev: allocate udev_device->envp[] dynamically
-      replace strncpy() with strlcpy()
-      use re-entrant variants of getpwnam and getgrnam
-      udevd: fix memory leak
-      udevd: fix WAIT_FOR_SYSFS execution order
-      fix handling of string_escape option
-      udevd: use a tighter loop for compare_devpath()
-      udevd: avoid implicit memset in match_attr()
-      kerneldoc comment fixes
-      udevd: simplify rules execution loop
-      udevd: fix termination of rule execution
-      udevd: be more careful when matching against parents
-      udevd: shrink struct token to 12 bytes
-
-Kay Sievers (113):
-      remove outdated docs/README-gcov_for_udev
-      libudev: device - add device lookup by subsystem:sysname
-      libudev: also prefix non-exported functions with udev_*
-      libudev: add udev_monitor_send_device()
-      libudev: list - add flag
-      libudev: device - generate DEVNAME and DEVLINKS properties
-      vol_id: update README
-      libudev: handle ! in sysname, add sysnum, return allocated list_entry on add
-      delete simple-build-check.sh
-      test: move global ENV{ENV_KEY_TEST}="test" to local rule
-      libudev: monitor - fix send_device() property copying
-      libudev: device - add get_envp() to construct envp from property list
-      libudev: do not include ctrl in libudev.so
-      libudev: monitor - do not mangle DEVLINKS property
-      libudev: update DEVLINKS property when properties are read
-      libudev: device - lookup "subsystem" and "driver" only once
-      libudev: device - export properties when values are set
-      libudev: list - handle update of key with NULL value
-      libudev: ctrl - fix typo in set_env()
-      libudev: add global property list
-      libudev: device - copy global properties, unset empty properties
-      volume_id: btrfs - update magic to latest disk format
-      udevd: use libudev
-      move udev_device_db to libudev
-      rename udev source files
-      libudev: always add UDEV_LOG
-      libudev: monitor - export MAJOR/MINOR only if available
-      udev-node: name_list -> udev_list
-      udev-rules-parse: name_list -> udev_list
-      delete name_list, move common file functions
-      fix sorting of rules files
-      run_program: prevent empty last argv entry
-      update IMPORT= file/stdout property parsing
-      update rules file parsing
-      delete udev-util-file.c
-      libudev: list - prepend udev_* to all functions
-      libudev: add sysnum to test program
-      test: fix a few unintentially wrongly written rules which cause parse errors
-      libudev: monitor - add set_receive_buffer_size()
-      libudev: ctrl - change magic to integer
-      libudev: make list_node functions available
-      udevd: use udev_list_node
-      collect: use udev_list
-      delete list.h
-      merge udev-rules.c and udev-rules-parse.c
-      make struct udev_rules opaque
-      move run_program to util
-      udev_event_run() -> udev_event_execute_rules()
-      udev_rules_run() -> udev_event_execute_run();
-      move udev_rules_apply_format() to udev-event.c
-      udev_list_cleanup() -> udev_list_cleanup_entries()
-      selinux_init(udev) -> udev_selinux_init(udev)
-      prefix udev-util.c functions with util_*
-      pass make distcheck
-      libudev: device - get_attr_value() -> get_sysattr_value()
-      cdrom_id: remove ARRAY_SIZE() declaration
-      replace missing get_attr_value() -> get_sysattr_value()
-      add "root" == 0 shortcuts to lookup_user/group()
-      do not use the new work-in-progress parser rule matcher
-      libudev: device - 128 -> ENVP_SIZE
-      add util_resolve_subsys_kernel()
-      handle numerical owner/group string in lookup_user/group()
-      replace in-memory rules array with match/action token list
-      do not create temporary node ($tempnode) if node already exists
-      shrink struct udev_event
-      shrink struct udev_event
-      rule_generator: fix netif NAME= value extraction regex
-      skip SYMLINK rules for devices without a device node
-      rules: let empty strings added to buffer always return offset 0
-      fix uninitialized variable warnings
-      cache uid/gid during rule parsing
-      distinguish "match" from "assign" by (op < OP_MATCH_MAX)
-      determine at rule parse time if we need to call fnmatch()
-      special-case "?*" match to skip fnmatch()
-      libudev: monitor - replace far too expensive snprintf() with strlcpy()
-      libudev: monitor - cache result of monitor send buffer
-      fix "unused" warnings
-      remove debug printf
-      match KEY="A|B" without temporary string copy
-      match_attr() - copy attr value only when needed
-      do not init string arrays, just clear first byte
-      fix $attr{[<subsystem>/<sysname>]<attribute>} substitution
-      libudev: device - fill envp array while composing monitor buffer
-      test: add RUN+="socket: ..." to a test to run monitor code
-      libudev: device - allocate envp array only once
-      update NEWS
-      udevd: merge exec and run queue to minimize devpath string compares
-      ATTR{}== always fails if the attribute does not exist
-      rules: remove SCSI timeouts
-      rules: remove "add" match from usb device node rule
-      edd_id: add "change" event match
-      fstab_import: add "change" event match
-      write trace log to stderr
-      log rules file and line number when NAME, SYMLINK, OWNER, GROUP, MODE, RUN is applied
-      skip entire rule containing device naming keys, if no device can be named
-      fix udev_node_update_old_links() logic
-      move some info() to dbg()
-      add "devel" and "install" switches to autogen.sh
-      move debugging strings inside #ifdef DEBUG
-      firmware.sh: record missing files in /dev/.udev/firmware-missing/
-      fix list handling in enumerate and rules file sorting
-      volume_id: btrfs update
-      info() PROGRAM and IMPORT execution
-      fix $links substitution
-      fix cleanup of possible left-over symlinks
-      do not import the "uevent" file when we only read the db to get old symlinks
-      usb_id: MassStorage SubClass 6 is "scsi" not "disk"
-      unify string replacement
-      $links should be relative
-      fix indentation
-      rules: md - add mdadm 3 device naming
-      cleanup /dev/.udev/queue on startup and exit
-      udevadm: settle - exit if udevd exits
-
-Matthias Koenig (1):
-      volume_id: swap - larger PAGE_SIZE support
-
-Steven Whitehouse (1):
-      volume_id: support for GFS2 UUIDs
-
-
-Summary of changes from v129 to v130
-============================================
-
-Kay Sievers (26):
-      fix compile error with --disable-logging
-      libudev: enumerate - add_device() -> add_syspath()
-      volume_id: hpfs - read label and uuid
-      use no_argument, required_argument, optional_argument in longopts
-      libudev: get rid of selinux
-      libudev: device - add get_parent_with_subsystem()
-      usb_id: use libudev
-      udevadm: info - fix --query=all for devices without a device node
-      vol_id: add size= option
-      move selinux noops to udev.h
-      volume_id: add dbg() as noop to check for compile errors
-      vol_id: fix logging glue
-      vol_id: always use the safe string versions for unencoded label and uuid
-      volume_id: better DDF raid detection
-      volume_id: add btrfs
-      volume_id: use PRIu64i, PRIx64 macros
-      udevd: clarify deprecated sysfs layout warning
-      libudev: fix --enable-debug
-      don not print error if GOTO jumps just to next rule
-      volume_id: add more vfat debugging information
-      libudev: libudev.pc remove selinux
-      store node name and symlinks into db symlink target if they are small enough
-      volume_id: more fat debugging
-      libudev: fix typo in "multiple entries in symlink" handling
-      connect /sys and /dev with /sys/dev/{block,char}/<maj>:<min> and /dev/{block,char}/<maj>:<min>
-      replace spaces in dm and md name symlinks
-
-
-Summary of changes from v128 to v129
-============================================
-
-Alan Jenkins (7):
-      udev-test.pl: set non-zero exitcode if tests fail
-      scsi_id: compiler warning on 32-bit
-      trivial cleanup in udev_rules_iter
-      avoid repeated scans for goto targets (udev_iter_find_label)
-      replace strerror() usage with threadsafe "%m" format string
-      fix messages (inc. debug compile failure) introduced when optimizing "goto"
-      allow compiler to check dbg() arguments on non-debug builds
-
-Kay Sievers (46):
-      libudev: switch to "udev_device_get_parent"
-      libudev: udev_device - add attribute cache
-      libudev: handle "device" link as parent, handle "class" "block" as "subsystem"
-      udevadm: info - fix lookup-by-name
-      libudev: switch API from devpath to syspath
-      libudev: rename ctrl_msg to ctrl_msg_wire
-      vol_id: fix lib logging glue
-      fix broken symlink resolving
-      fix udevadm trigger
-      libudev: pass udev_device in enumerate
-      libudev: fix "subsystem" value
-      always include config.h from Makefile
-      libudev: udev_device_get_devname -> udev_device_get_devnode
-      libudev: add udev_device_new_from_devnum()
-      libudev: also import "uevent" file when reading udev database
-      libudev: add userdata pointer
-      libudev: replace awkward callback list interfaces with list iterators
-      libudev: get devnum from uevent file
-      libudev: enumerate_get_devices_list -> enumerate_get_list
-      libudev: initialize selinux only when needed
-      libudev: device - read database only when needed
-      libudev: rework list handling
-      libudev: more list rework
-      lubudev: accept more sys directories as devices, and parent devices
-      libudev: enumerate - accept list of subsystems to scan, or skip
-      libudev: enumerate "subsystem"
-      libudev: enumerate - scan /sys/block/ if needed
-      libudev: enumerate - split new() and scan()
-      test: replace ancient sysfs tree with recent one
-      test: add missing pci directory because of .gitignore *.7
-      gitignore: move *.8 to subdirs
-      test: replace last reference of "/class/*" devpath
-      fix dbg() callers
-      libudev: enumerate - scan devices and subsystems, add subsystem and attribute filter
-      udevadm: trigger: use libudev
-      fix segfault caused by wrong pointer used in dbg()
-      libudev: device_init() -> device_new()
-      udevadm: trigger fix long option --type=
-      libudev: add queue interface
-      udevadm: settle - use libudev queue
-      libudev: device - handle /sys/block/<disk-device-link>/<partition>
-      libudev: enumerate - ignore regular files while scanning
-      udevadm: trigger --type=failed - use libudev queue
-      rules: ieee1394 - create both, by-id/scsi-* and by-id/ieee-* links
-      build: include Makefile.am.inc in all Makefile.am
-      udevd: print warning if CONFIG_SYSFS_DEPRECATED is used
-
-
-Summary of changes from v127 to v128
-============================================
-
-Alan Jenkins (8):
-      fix uninitialized name_list error::ignore_error
-      do not needlessly declare some local variables in udev_rules_parse.c as static
-      remove deprecated envp[] in main()
-      fix name compare bug name_list_key_add()
-      remove redundant string copy in udev_rules_apply_format()
-      remove redundant "remove trailing newlines" in udevadm info
-      threadsafe rules iteration
-      fix off-by-one in pass_env_to_socket()
-
-Kay Sievers (53):
-      libudev: add monitor documentation
-      libudev: fix --disable-log
-      autogen.sh: add --with-selinux
-      volume_id: hfs - calculate proper uuid
-      fix dangling pointer returned by attr_get_by_subsys_id()
-      udev-test.pl: add --valgrind option
-      libudev: libudev.pc add Libs.private
-      volume_id: fail on undefined __BYTE_ORDER
-      remove FAQ
-      libudev: fix monitor documentation
-      libudev: add udev_device_get_syspath()
-      udev_device_init() remove statically allocated device support
-      udevadm: info - fix broken --device-id-of-file=
-      udevadm: control - use getopt_long()
-      udevadm: print warning to stderr if udevadm is called by symlink
-      udev-test.pl: remove left-over comment from --valgrind option
-      udevadm: rename source files
-      udevadm: rename internal functions to udevadm_*
-      udevadm: split out control functions
-      udevadm: move init from commands to udevadm
-      autogen.sh: add debug
-      use libudev code, unify logging, pass udev context around everywhere
-      volume_id: linux_raid - fix logic for volumes with size == 0
-      vol_id: add --debug option
-      udevadm: add --version --help options to man page, hide them as commands
-      move udev_ctrl to libudev-private
-      udev-test.pl: set udev_log="err"
-      test-udev: cleanup libudev context and overridden rules file string
-      test-udev: remove unused var
-      add a bunch of private device properties to udev_device
-      udevadm: monitor - use libudev for udev monitor
-      libudev: monitor - add event properties to udev_device
-      udevadm: log message if udevadm link is used
-      udevd: remove max_childs_running logic
-      libudev: monitor- add netlink uevent support
-      udevadm: monitor - use libudev code to retrieve device data
-      libudev: udev_device - read "driver" value
-      libudev: rename enumerate function
-      libudev: add selinux
-      libudev: initialize selinux after logging
-      volume_id: merge util.h in libvolume_id-private.h
-      update file headers
-      libudev: udev_device - add more properties
-      libudev: do not use udev_db.c
-      libudev: get rid of udev_sysfs.c
-      libudev: get rid of udev_utils.c
-      libudev: rename libudev-utils.c libudev-util.c
-      libudev: do not use any udev source file
-      extras: use libudev code
-      convert to libudev and delete udev_utils_string.c
-      get rid of udev_sysdeps.c
-      use size definitions from libudev
-      udevadm: info - use "udev_device"
-
-
-Summary of changes from v126 to v127
-============================================
-
-Karel Zak (2):
-      build-sys: don't duplicate file names
-      build-sys: remove non-POSIX variable names
-
-Kay Sievers (26):
-      add inotify dummy definitions if inotify is not available
-      build: remove autopoint check
-      udevadm: trigger - add missing attr filter to synthesized "subsystem" register events
-      ignore duplicated rules file names
-      fix .gitignore
-      rules: delete all distro rules which do not use default rules
-      rules: add nvram
-      rules: add isdn rules
-      rules: Gentoo update
-      add missing includes
-      add some warnings
-      update .gitignore
-      add missing 'v' for "make changelog"
-      build: fix "make dist"
-      vol_id: make the --offset= argument optional
-      rules: optical drives - probe at last session offset, do not probe for raid
-      libudev: add library to access udev information
-      libudev: split source files
-      update INSTALL
-      libudev: add udev event monitor API
-      volume_id: remove deprecated functions and bump major version
-      volume_id: remove left-over fd close()
-      split udev_device.c to leave out rules handling from libudev
-      libudev: link against selinux if needed
-      firmware.sh: lookup lookup kernel provided firmware directory
-      libudev: require LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
-
-Michal Soltys (1):
-      rules: fix md rules for partitioned devices
-
-
-Summary of changes from v125 to v126
-============================================
-
-Kay Sievers (9):
-      delete all Makefiles and move udev source to udev/
-      use autotools
-      rules: mode 0660 for group "disk"
-      rules: update Fedora rules
-      update ChangeLog
-      INSTALL: --enable-selinux not --with-selinux
-      volume_id: move static lib to $prefix
-      volume_id: create relative links
-      rules: run vol_id on opticals only if media is found
-
-Marco d'Itri (1):
-      rules: Debian update
-
-Thomas Koeller (1):
-      use proper directory lib/lib64 for libvolume_id
-
-
-Summary of changes from v124 to v125
-============================================
-
-John Huttley (1):
-      rules: tape rules - add nst to usb and 1394 links
-
-Karl O. Pinc (1):
-      man: clarify $attr{} parent searching
-
-Kay Sievers (14):
-      collect: fix size_t printf
-      path_id: suppress trailing '-' like 'ID_PATH=pci-0000:05:01.0-'
-      rules: add v4l persistent links
-      docs: update some docs and delete outdated stuff
-      scsi_id: fix fallback to sg v3 for sg nodes
-      rules: fix cciss rules for partition numbers > 9
-      udev.conf: udevcontrol -> udevadm control
-      rules: use consistently OPTIONS+=
-      scsi_id: the fallback fix broke error handling
-      man: rebuild from xml
-      do not touch node ownership and permissions, if already correct
-      rules: tape rules - add nst to by-path/ links
-      udevadm: info - add --export format to --device-id-of-file=
-      move default rules from /etc/udev/rules.d/ to /lib/udev/rules.d/
-
-Marco d'Itri (7):
-      rules_generator: net rules - do not print error if file is missing and ignore commented rules
-      man: add link_priority default value
-      scsi_id: man page fix
-      udevadm: settle - add verbose output when running into timeout
-      rules: Debian update
-      rules: Debian update
-      ignore rule with GOTO to a non-existent label
-
-Thomas Koeller (1):
-      scsi_id: include sys/stat.h
-
-Tobias Klauser (1):
-      collect: check realloc return value
-
-
-Summary of changes from v123 to v124
-============================================
-
-Kay Sievers (1):
-      cdrom_id: fix recognition of blank media
-
-
-Summary of changes from v122 to v123
-============================================
-
-Erik van Konijnenburg (3):
-      add substitution in MODE= field
-      Makefile: use udevdir in "make install"
-      volume_id: support for oracleasm
-
-Harald Hoyer (1):
-      scsi_id: retry open() on -EBUSY
-
-Karel Zak (2):
-      volume_id: remove unnecessary global variable
-      volume_id: enable GFS probing code, add LABEL support
-
-Kay Sievers (5):
-      edd_id: call it only for sd* and hd*
-      rename WAIT_FOR_SYSFS to WAIT_FOR and accept an absolute path
-      rules: tape rules - use bsg device nodes for SG_IO
-      rules: persistent net - handle "locally administered" ibmveth MAC addresses
-      cdrom_id: export ID_CDROM_MEDIA_TRACK_COUNT_AUDIO=, ID_CDROM_MEDIA_TRACK_COUNT_DATA=
-
-Michal Soltys (1):
-      man: add NAME== match entry
-
-Xinwei Hu (2):
-      collect: realloc buffer, if needed
-      udevd: export .udev/queue/$seqnum before .udev/uevent_seqnum
-
-
-Summary of changes from v121 to v122
-============================================
-
-Hannes Reinecke (2):
-      scsi_id: remove all sysfs dependencies
-      scsi_id: add SGv4 support
-
-Karel Zak (1):
-      volume_id: clean up linux_raid code
-
-Kay Sievers (8):
-      scsi_id:  update man page
-      scsi_id: remove bus_id option
-      scsi_id: add --sg-version= option
-      rules: adapt to new scsi_id
-      rules: adapt tape rules to new scsi_id
-      scsi_id: add bsg.h
-      volume_id: bump version
-      Makefile: do not create udevcontrol, udevtrigger symlinks
-
-MUNEDA Takahiro (2):
-      man: udevd- fix udev(8) reference
-      man: scsi_id
-
-Matthias Schwarzott (1):
-      cdrom_id: fix segfault
-
-
-Summary of changes from v120 to v121
-============================================
-
-Damjan Georgievski (1):
-      libvolume_id: recognize swap partitions with a tuxonice hibernate image
-
-Daniel Drake (1):
-      writing udev rules: fix rule typos
-
-David Woodhouse (1):
-      rules_generator: net rules - add "dev_id" value to generated rules
-
-Harald Hoyer (1):
-      selinux: more context settings
-
-Kay Sievers (21):
-      udevinfo: do not replace chars when printing ATTR== matches
-      vol_id: add --offset option
-      cdrom_id: replace with version which also exports media properties
-      udevd: at startup write message including version number to kernel log
-      rules_generator: net rules - always add KERNEL== match to generated rules
-      selinux: fix missing includes
-      allow setting of MODE="0000"
-      path_id: remove subsystem whitelist
-      logging: add trailing newline to all strings
-      scsi_id: initialize serial strings
-      persistent device naming: also read unpartitioned media
-      cdrom_id: add more help text
-      add $links substitution
-      fstab_import: add program to IMPORT matching fstab entry
-      add OPTIONS+="event_timeout=<seconds>"
-      write "event_timeout" to db
-      udevadm: trigger - add --env= option
-      udevadm: control - fix --env key to accept --env=<KEY>=<value>
-      udevadm: info - do not print ATTR{dev}==
-      persistent device naming: update tape rules
-      rules: update md rules
-
-
-Summary of changes from v119 to v120
-============================================
-
-Kay Sievers (9):
-      test: remove duplicated EXTRA entry
-      rules: remove last WAIT_FOR_SYSFS, load ppdev, switch scsi_device
-      udevadm: trigger - option to synthesize events and pass them to a socket
-      udevadm: info - resolve devpath if symlink is given
-      udevadm: remove old man page links and compat links for debugging tools
-      udevadm: trigger - fix broken socket option check
-      udevadm: trigger - fix --socket== + --verbose
-      also accept real socket files for RUN+="socket:<path>"
-      persistent device naming: cleanup storage rules
-
-Michael Kralka (1):
-      udevd: serialize events if they refer to the same major:minor number
-
-
-Summary of changes from v118 to v119
-============================================
-
-Anthony L. Awtrey (1):
-      do not skip RUN execution if device node removal fails
-
-Harald Hoyer (2):
-      rules: Fedora update
-      rules: do not set GROUP="disk" for scanners
-
-Jiri Slaby (1):
-      rules_generator: add missing write_net_rules unlock
-
-Karel Zak (2):
-      volume_id: fix UUID raw buffer usage
-      volume_id: fix typo in function documentation
-
-Kay Sievers (10):
-      switch mailing lists to linux-hotplug@vger.kernel.org
-      rules: remove tty rule which can never run because of an earlier "last_rule"
-      volume_id: update ext detection
-      selinux: set context for real file name not the temp name
-      hack to allow ATTR{block/*/uevent}="change"
-      rules_generator: add KERNEL=="<netifname>*" to generated rules
-      persistent device naming: also run on "change" event
-      test: add "subsystem" links to all devices
-      sysfs: depend on "subsystem" link
-      extend hack to allow TEST=="*/start"
-
-Matthias Schwarzott (1):
-      volume_id: respect LDFLAGS
-
-Neil Williams (1):
-      volume_id: add prefix=, exec_prefix=
-
-Roy Marples (1):
-      Makefile: do not require GNU install
-
-
-Summary of changes from v117 to v118
-============================================
-
-Daniel Drake (1):
-      doc: update "writing udev rules"
-
-Hannes Reinecke (1):
-      volume_id: LVM - add uuid
-
-Kay Sievers (9):
-      remove udevstart
-      rules_generator: do not create rules with insufficient matches
-      man: udevadm settle - mention 180 seconds default timeout
-      libvolume_id: squashfs - add endianess support for LZMA compression
-      rules: add AOE rule
-      volume_id: md - add metadata minor version
-      volume_id: run only once into a timeout for unreadable devices
-      create_floppy_devices: fix logic for more than one floppy device
-      volume_id: also add readable check to probe_all()
-
-Matthias Schwarzott (1):
-      rules: Gentoo update
-
-Michael Prokop (1):
-      libvolume_id: squashfs+LZMA compression detection
-
-
-Summary of changes from v116 to v117
-============================================
-
-Dan Nicholson (2):
-      extras: ignore built and generated files
-      volume_id: create relative symlink when $(libdir) = $(usrlibdir)
-
-Kay Sievers (15):
-      usb_id: fail if vendor/product can not be retrieved
-      rules: SUSE update
-      firmware: do not print error if logger is missing
-      volume_id: vfat - allow all possible sector sizes
-      volume_id: LUKS - export version
-      volume_id: ntfs - rely on valid master file table
-      volume_id: bump version
-      udevinfo: exclude "uevent" file from --attribute-walk
-      udevadm: merge all udev tools into a single binary
-      udevadm: accept command as option, like --help, --version
-      udevadm: add info option --device-id-of-file=<file>
-      Makefile: fix bogus version number than got committed
-      udevadm: also return major==0 results for --device-id-of-file
-      man: udevd.8 - remove udevcontrol section
-      udevadm: control - allow command to be passed as option
-
-MUNEDA Takahiro (1):
-      man: fix udevadm.8 typo
-
-Matthias Schwarzott (2):
-      firmware: remove hardcoded path to logger
-      rules: Gentoo update
-
-VMiklos (1):
-      rules: Frugalware update
-
-
-Summary of changes from v115 to v116
-============================================
-
-Bryan Kadzban (1):
-      rules: fix typos
-
-Harald Hoyer (3):
-      check line length after comment check and whitespace strip
-      only install *.rules
-      remove extra space from udevinfo symlink output
-
-Kay Sievers (29):
-      rules: fix two trivial typos
-      rules: random and urandom are 0666
-      rules: add REMOVE_CMD rule
-      track "move" events to rename database and failed files
-      rules: Gentoo update
-      rules: add i2o driver rule
-      man: recreate man pages
-      volume_id: fix linux_raid metadata version 1.0 detection
-      add $name substitution
-      do not delete the device node with ignore_remove, but handle the event
-      print warning for invalid TEST operations
-      rules: do not delete /lib/udev/devices/ nodes on "remove"
-      rules: remove broken nvram group assignment without any permission
-      add /dev/rtc symlink if new rtc drivers are used
-      increase WAIT_FOR_SYSFS timeout to 10 seconds
-      rules: put bsd nodes in /dev/bsd/ directory
-      path_id: fix for stacked class devices
-      ignore device node names while restoring symlinks from the stack
-      use SEQNUM in /dev/.udev/queue/ instead of devpath
-      rules: add memstick module loading
-      udevinfo: simplify symlink printing logic
-      prevent wrong symlink creation if database disagress with current rules
-      fix wrong variable used in logged string
-      update README
-      rule_generator: move all policy from write_net_rules to the rules file
-      rules: call usb_id only for SUBSYSTEMS=="usb"
-      rules: split out and fix persistent tape rules
-      fix debug output string
-      rule_generator: always match netif type in generated rule
-
-Matthias Schwarzott (3):
-      rules: Gentoo update
-      rules: Gentoo update
-      rules: Gentoo update
-
-Michael Morony (1):
-      set buffer size if strlcpy/strlcat indicate truncation
-
-maximilian attems (1):
-      correct includes in udev_selinux.c
-
-
-Summary of changes from v114 to v115
-============================================
-
-Harald Hoyer (1):
-      rules: fix typo in 80-drivers.rules
-
-Kay Sievers (15):
-      rules: add default rules
-      rules: update SUSE rules
-      rules: add packages rules
-      rules: add ia64 rules
-      rules: move md-raid rules to packages dir
-      rules: run vol_id only for partitions
-      rules: update Fedora rules
-      edd_id: move persistent rules to its own file
-      accept relative path for TEST
-      rules: add iowarrior rule
-      volume_id: fix sqashfs detection
-      do not ignore dynamic rule if it is the last one in the list
-      rule_generator: fix wrong DRIVERS!= logic
-      rules: update Fedora
-      Makefile: install default rules
-
-Marco d'Itri (3):
-      rules_generator: remove policy from write_cd_rules
-      rules_generator: fix write_cd_rules when similar names exist in the root directory
-      rules: Debian update
-
-
-Summary of changes from v113 to v114
-============================================
-
-Hannes Reinecke (3):
-      collect: extra to synchronize actions across events
-      add $driver subtitution
-      rules_generator: add S/390 persistent network support
-
-Kay Sievers (24):
-      rules_generator: remove executable flag from include file
-      always unlink temporary file before creating new one
-      rules: SUSE update
-      volume_id: ext4 detection
-      udevtrigger: allow to specify action string
-      add option to RUN key to ignore the return value of the program
-      use global udev_log variable instead of parameter in run_program
-      add udev_rules_run() to handle RUN list
-      move udev_utils_run.c into udev_rules.c
-      rules: SUSE update
-      name_list: rename loop_name -> name_loop
-      handle dynamic rules created in /dev/.udev/rules.d/
-      allow SYMLINK== match
-      libvolume_id: use /usr/$libdir in pc file
-      Makefile: add --as-needed flag to ld
-      restore behavior of NAME==
-      rules_generator: remove "installation" function
-      udevtrigger: trigger "driver" events
-      rules: update SUSE
-      rules: Fedora update
-      rules: add "do not edit" comment
-      rules: Fedora update
-      rules_generator: skip random MAC addresses
-      write changed network interface names to the kernel log
-
-Matthias Schwarzott (3):
-      rules: Gentoo update
-      fix inotify to work not only once
-      rules: Gentoo update
-
-Richard Hughes (1):
-      Makefile: add "make dist" for nightly snapshots
-
-
-Summary of changes from v112 to v113
-============================================
-
-David Zeuthen (1):
-      vol_id: do not fail if unable to drop privileges
-
-Kay Sievers (12):
-      add missing ChangeLog
-      make ATTR{[$SUBSYSTEM/$KERNEL]<attr>}="<value>" working
-      rules: recognize partitions and disk devices properly
-      rules: SUSE update
-      atomically replace existing nodes and symlinks
-      do not try to create existing file
-      info() for ignore_remove
-      rules: SUSE update
-      Makefile: check for missing ChangeLog or RELEASE-NOTES at release
-      allow to disable the replacement of unusual characters
-      no newline in log messages
-      udevd: do not use syslog if --verbose (debugging) is used
-
-Tobias Klauser (1):
-      fix typo in udev_utils_run.c
-
-
-Summary of changes from v111 to v112
-============================================
-
-Fabio Massimo Di Nitto (1):
-      rules: ignore partitons that span the entire disk
-
-Hannes Reinecke (1):
-      cciss device support
-
-Kay Sievers (34):
-      udevd: close /proc/meminfo after reading
-      create_floppy_devices: remove dead "unlink" code
-      volume_id: add function documentation
-      udev_db: escape path names with \x00 instead of %00
-      udevsettle: use long options
-      replace_chars: replace spaces in node name
-      volume_id: add and export string encoding function
-      vol_id: export encoded strings
-      rules: use encoded strings instead of skipping characters
-      udevtest: print message before log output
-      volume_id: escape % character
-      replace_chars: replace % character
-      IMPORT: do not mangle whitespace
-      scsi_id: do not install symlink in /sbin
-      rules: SUSE update
-      volume_id: terminate overlong label strings
-      scsi_id: add long options
-      rules: use long options for scsi_id
-      path_id: skip subsystem directory
-      rules: fix cciss rule
-      rules: SUSE update
-      scsi_id: fix typo in help text
-      fix "do not access parent" warning for ATTR{}
-      sysfs: add device lookup by $SUBSYSYTEM:$KERNEL
-      events for "bus" and "class" registration must be matched as "subsystem"
-      udevtest: add --subsystem option
-      sysfs: change order of subsystem lookup
-      add $sys substitution
-      add TEST=="<file>" key
-      add "[$SUBSYSTEM/$KERNEL]<attribute>" lookup
-      sysfs: handle bus/class top-level directories
-      sysfs: skip unknown sysfs directories
-      rules: SUSE update
-      release 112
-
-Miklos Vajna (2):
-      create_floppy_devices: add man page
-      path_id: remove on make uninstall
-
-Ryan Lortie (1):
-      volume_id: support for long-filename based labels
-
-Scott James Remnant (2):
-      replace_untrusted_chars: replace all whitespace with space
-      run_program: log "info" not "error" if program is missing
-
-
-Summary of changes from v110 to v111
-============================================
-
-Kay Sievers (19):
-      rules: SUSE update
-      rules: Fedora update
-      volume_id: use md native uuid format
-      vol_id: use long options
-      volume_id: add volume_id_get_* functions
-      vol_id: use volume_id_get_*
-      udevd: use fgets() to read /proc files
-      volume_id: add internal UUID_STRING
-      volume_id: add DDF support
-      vol_id: README update
-      volume_id: rename UUID_64BIT_LE/BE
-      vol_id: add ID_FS_UUID_SAFE
-      rules: use ID_FS_UUID_SAFE
-      rules: SUSE update
-      volume_id: give access to list of all available probers
-      vol_id: use libvolume_id prober list for --probe-all
-      volume_id: add remaining names for prober lookup by type
-      rules: SUSE update
-      volume_id: vol_id depends on libvolume_id
-
-Matthias Schwarzott (2):
-      volume_id: fix Makefile for parallel make
-      rules: Gentoo update
-
-
-Summary of changes from v109 to v110
-============================================
-
-Harald Hoyer (1):
-      udevcontrol: allow to set global variables in udevd
-
-Kay Sievers (13):
-      remove eventrecorder.sh
-      update SUSE rules
-      volume_id: add md metadata 1.0, 1.1, 1.2 support
-      unset variable with ENV{VAR}=""
-      delete copies of default rules in SUSE rules
-      volume_id: ext - fix endianess in version number
-      rules: Fedora update
-      volume_id: old md metadata has only 32 bit for the uuid
-      volume_id: minix version 3 support
-      don't create $tempnode for devices without major
-      usb_id: add <devpath> to help text
-      ata_id: use getopt_long()
-      rules: SUSE update
-
-Matthias Schwarzott (3):
-      Makefile: respect CFLAGS/LDFLAGS
-      rules: Gentoo update
-      ata_id: don't log error for libata devices on older kernels
-
-
-Summary of changes from v108 to v109
-============================================
-
-Harald Hoyer (1):
-      create_floppy_devices: create nodes with correct selinux context
-
-Kay Sievers (11):
-      udevtest: export ACTION string if given as option
-      update SUSE rules
-      make ACTION!="add|change" working
-      udevtest: import uevent variables if possible
-      udevinfo: export all information stored in database
-      default rules: add libata compat links
-      create_path: don't fail if something else created the directory
-      udevd: fix serialization of events
-      path_id: remove broken example
-      libvolume_id: do not install static library
-      update SUSE rules
-
-Matthias Schwarzott (2):
-      update Gentoo rules
-      persistent device naming: add joystick links
-
-VMiklos (1):
-      path_id: add man page
-
-
-Summary of changes from v107 to v108
-============================================
-
-Kay Sievers (3):
-      udevinfo: relax check for the correct device if looked up by name
-      don't write to sysfs files during test run
-      finally remove the directory event-multiplexer crap
-
-Matthias Schwarzott (2):
-      write_cd_rules: set default link type to "by-id" for usb and ieee1394 devices
-      update Gentoo rules
-
-Pozsar Balazs (1):
-      udevsettle: read udev not kernel seqnum first
-
-
-Summary of changes from v106 to v107
-============================================
-
-Jean Tourrilhes (1):
-      udevtest: export UDEV_LOG if we changed it
-
-Kay Sievers (33):
-      man: add missing options to various man pages
-      man: fix typo
-      create_floppy_devices: apply specified mode without umask
-      man: spelling fixes
-      udevmonitor: add switch for kernel and udev events
-      default rules: wait for 0:0:0:0 scsi devices only
-      update Fedora rules
-      delete dasd_id, it moved to s390-tools
-      update Gentoo rules
-      encode db-file names, instead of just replacing '/'
-      update internal variables if we see $DEVPATH during IMPORT
-      increase /proc/stat buffer
-      maintain index over device-names to devpath relation
-      restore overwritten symlinks when the device goes away
-      store devpath with the usual leading slash
-      add link_priority to rule options, and store it in database
-      pick actual valid device in udev_db_lookup_name
-      cleanup already existing db-entries and db-index on device update
-      selinux: move selinux_exit() to the main programs
-      remove old error message
-      read list of devices from index, make index private to database
-      priority based symlink handling
-      volume_id: get rid of compiler warning
-      udevinfo: remove -d option
-      update %n on netif name change
-      if a node goes away, possibly restore a waiting symlink
-      update TODO
-      man: add "link_priority" option
-      update SUSE rules
-      udevtest: add --force mode
-      udevinfo: print link priority
-      usb_id: append target:lun to storage device serial
-      run_directory: add final warning before removal
-
-Marco d'Itri (1):
-      update Debian rules
-
-Matthias Schwarzott (2):
-      udevd: cleanup std{in,our,err} on startup
-      udevmonitor: fix swapped event switch descriptions
-
-
-Summary of changes from v105 to v106
-============================================
-
-A. Costa (1):
-      man: fix typos in scsi_id and udevd
-
-Andrey Borzenkov (2):
-      vol_id: add -L to print raw partition label
-      vol_id: document -L
-
-Jamie Wellnitz (1):
-      persistent device naming: tape devices and medium changers
-
-Kay Sievers (15):
-      exclude parent devices from DRIVER== match
-      volume_id: really fix endianess bug in linux_raid detection
-      release 105
-      man: correct udevinfo --export-db
-      path_id: append LUN to iSCSI path
-      create_floppy_devices: add option for owner/group
-      update example rules
-      apply format chars to ATTR before writing to sysfs
-      add (subsystem) to udevmonitor output
-      update DRIVER== changes
-      remove --version from the udevinfo man page
-      add test for an attribute which contains an operator char
-      man: add note about parent matching behavior
-      scsi_id: accept tabs in /etc/scsi_id.conf
-      remove dead rule in persistent tape rules
-
-Matthias Schwarzott (4):
-      correct typo in extras/scsi_id/scsi_id.conf
-      fix retry-loop in netif-rename code
-      add option --version to udevd
-      rule_generator: fix for creating rules on read-only filesystem
-
-Peter Breitenlohner (1):
-      fix INSTALL_PROGRAM vs. INSTALL_SCRIPT
-
-Sergey Vlasov (3):
-      udevd: init signal pipe before daemonizing
-      unlink old database file before creating a new one
-      fix %c $string substitution
-
-Theodoros V. Kalamatianos (1):
-      fix udev attribute names with a colon
-
-
-Summary of changes from v104 to v105
-============================================
-
-A. Costa (1):
-      man: fix typos in scsi_id and udevd
-
-Andrey Borzenkov (2):
-      vol_id: add -L to print raw partition label
-      vol_id: document -L
-
-Kay Sievers (2):
-      exclude parent devices from DRIVER== match
-      volume_id: really fix endianess bug in linux_raid detection
-
-Matthias Schwarzott (2):
-      correct typo in extras/scsi_id/scsi_id.conf
-      fix retry-loop in netif-rename code
-
-Peter Breitenlohner (1):
-      fix INSTALL_PROGRAM vs. INSTALL_SCRIPT
-
-Sergey Vlasov (3):
-      udevd: init signal pipe before daemonizing
-      unlink old database file before creating a new one
-      fix %c $string substitution
-
-
-Summary of changes from v103 to v104
-============================================
-
-Kay Sievers (12):
-      update Fedora rules
-      update example rules
-      update SUSE rules
-      update SUSE rules
-      volume_id: fix endianess bug in linux_raid detection
-      man: fix udevmonitor text
-      man: recreate from xml
-      rename config "filename" to "dir"
-      remove outdated documentation
-      rename "udev.c" to "test-udev.c" - it is only for testing
-      update Fedora rules
-      use git-archive instead of git-tar-tree
-
-Kazuhiro Inaoka (1):
-      inotify syscall definitions for M32R
-
-Marco d'Itri (2):
-      write_cd_rules: identity-based persistence
-      scsi_id: remove trailing garbage from ID_SERIAL_SHORT
-
-Russell Coker (1):
-      SELinux: label created symlink instead of node
-
-
-Summary of changes from v102 to v103
-============================================
-
-Kay Sievers:
-      persistent storage rules: skip gnbd devices
-      volume_id: add checksum check to via_raid
-      volume_id: add comment about hfs uuid conversion
-      update SUSE rules
-      update Fedora rules
-
-
-Summary of changes from v101 to v102
-============================================
-
-Daniel Drake:
-      writing_udev_rules: fix typo in example rule
-
-Kay Sievers:
-      create missing ChangeLog for version 101
-      update SUSE rules
-      update default rules
-      first try "subsystem" link at a parent device, before guessing
-      if /sys/subsystem exists, skip class, bus, block scanning
-      scsi_id: export ID_SERIAL_SHORT without vendor/product
-      update SUSE rules
-
-MUNEDA Takahiro:
-      path_id: fix SAS disk handling
-
-
-Summary of changes from v100 to v101
-============================================
-
-Arjan Opmeer:
-      fix udevinfo help text typo
-
-Bryan Kadzban:
-      cleanup default rules
-      add IMPORT operations to the udev man page
-
-Kay Sievers:
-      remove Makefile magic for leading '0' in version
-      udevd: use getopt_long()
-      udevd: add --verbose option to log also to stdout
-      udevd: add --debug-trace option
-      rule_generator: improve net rule comment generation
-      volume_id: correct iso9660 high sierra header
-      warn if a PHYSEDV* key, the "device" link, or a parent attribute is used
-      don't print PHYSDEV* warnings for old WAIT_FOR_SYSFS rules
-      udevinfo: print error in --attribute-walk
-      udev_sysfs: unify symlink resolving
-      udevtrigger: trigger devices sorted by their dependency
-      fix spelling in deprecation warning
-      release 101
-
-Michał Bartoszkiewicz:
-      udevtrigger: fix typo that prevents partition events
-
-Miles Lane:
-      clarify "specified user/group unknown" error
-
-Piter PUNK:
-      update slackware rules
-
-VMiklos:
-      update Frugalware rules
-
-
-Summary of changes from v099 to v100
-============================================
-
-Kay Sievers:
-      update SUSE rules
-      fix messed up ChangeLog from release 099
-      man: add $attr{} section about symlinks
-      revert persistent-storage ata-serial '_' '-' replacement
-
-
-Summary of changes from v098 to v099
-============================================
-
-Greg KH:
-      update Gentoo rules
-
-Kay Sievers:
-      udev_db.c: include <sys/stat.h>
-      use fnmatch() instead of our own pattern match code
-      rename major/minor variable to maj/min to avoid warning
-      update source file headers
-      udevtest: print header that ENV{} can't work
-      update TODO
-      udevtrigger: options to filter by subsystem and sysfs attribute
-      udevtrigger: remove unused longindex
-      udevinfo: use long options
-      udevd: use files instead of symlinks for /dev/.udev/queue,failed
-      udevtrigger: fix pattern match
-      reorder options in udevinfo man page
-      udevinfo: fix SUBSYTEMS spelling error
-      fix ENV{TEST}="Test: $env{TEST}"
-      let $attr{symlink} return the last element of the path
-      cdrom_id: add rules file to call cdrom_id
-      udevinfo: do not show symlinks as attributes in --attribute-walk
-      remove broken name_cdrom.pl
-
-Marco d'Itri:
-      update Debian rules
-      run_program: close pipe fd's which are connected to child process
-      add persistent rules generator for net devices and optical drives
-
-MUNEDA Takahiro:
-      changes rules for ata disk from '_' to '-'
-
-Sergey Vlasov:
-      make struct option arrays static const
-      fix "subsytem" typo
-
-
-Summary of changes from v097 to v098
-============================================
-
-Alex Merry:
-      udevtest: allow /sys in the devpath paramter
-
-Harald Hoyer:
-      selinux: init once in the daemon, not in every event process
-
-Kay Sievers:
-      udevd: remove huge socket buffer on the control socket
-      man page: fix typo
-      rename udev_libc_wrapper -> udev_sysdeps
-      db: store devpath - node relationship for all devices
-      udevinfo: allow -a -n <node>
-      udevinfo, udevtest: simplify '/sys' stripping from devpath argument
-      lookup_user, lookup_group: report "unknown user" and "lookup failed"
-      consistent key naming to match only the event device or include all parent devices
-      skip rule, if too may keys of the same type are used
-      introduce ATTR{file}="value" to set sysfs attributes
-      update SUSE rules
-      update default rules
-      export DRIVER for older kernels as a replacement for PHYSDEVDRIVER
-      fix typo in SUBSYSTEMS key parsing
-      udevtrigger: add --retry-failed
-      volume_id: add suspend partition detection
-      vol_id: use primary group of 'nobody' instead of 'nogroup'
-      remove built-in /etc/passwd /etc/group parser
-      always expect KEY{value} on ATTR, ATTRS, ENV keys
-      use new key names in test programs
-      cleanup commandline argument handling
-      db: don't create a db file for only a node name to store
-      man: add ATTR{file}="value" assignment
-
-Lennart Poettering:
-      volume_id: fix fat32 cluster chain traversal
-
-Marco d'Itri:
-      fix 'unknow user' error from getpwnam/getgrnam
-      fix rc when using udev --daemon
-      update Debian rules
-
-Michał Bartoszkiewicz:
-      man pages: fix typos
-
-
-Summary of changes from v096 to v097
-============================================
-
-Anssi Hannula:
-      add joystick support to persistent input rules
-
-Kay Sievers:
-      firmware.sh: remove needless '/'
-      vol_id: add --skip-raid and --probe-all option
-      switch uevent netlink socket to group 1 only
-      increase /proc/stat read buffer
-      use "change" instead of "online" events
-      remove 'static' from local variable
-      libvolume_id: add parameter 'size' to all probe functions
-      man pages: replace 'device-path' by 'devpath'
-      man pages: work around xmlto which tries to be smart
-      refresh vol_id man page
-      udevinfo: add DRIVER==
-      Makefile: fix dependency
-      libvolume_id: read ufs2 label
-      switch ifdef __KLIBC__ to ifndef __GLIBC__
-      report failing getpwnam/getgrnam as error
-      rename udevcontrol message types and variables
-      initialize unused sockets to -1
-      udevd: remove useless udevinitsend parameter
-      update README
-      udevd: autotune max_childs/max_childs_running
-      update frugalware rules
-      update SUSE rules
-      move default rules to etc/udev/rules.d/
-      add 'crypto' devices to persistent storage rules
-      add late.rules to default rules
-      update Fedora rules
-      don't report an error on overlong comment lines
-      update SUSE rules
-      udevd: read DRIVER from the environment
-
-Marco d'Itri:
-      make rename_netif() error messages useful
-      path_id: fix an harmless syntax error
-
-Piter PUNK:
-      update slackware rules
-
-Richard Purdie:
-      Fix inotify syscalls on ARM
-
-
-Summary of changes from v095 to v096
-============================================
-
-Kay Sievers:
-      Makefiles: fix .PHONY for man page target
-      allow longer devpath values
-      path_id: prepare for new sysfs layout
-
-
-Summary of changes from v094 to v095
-============================================
-
-Kay Sievers:
-      update SUSE rules
-      don't remove symlinks if they are already there
-      allow "online" events to create/update symlinks
-      udevinfo: clarify parent device attribute use
-      update SUSE rules
-      netif rename: optimistic loop for the name to become free
-      remove broken %e enumeration
-
-Tobias Klauser:
-      print usage of udevcontrol when no or invalid command is given
-
-
-Summary of changes from v093 to v094
-============================================
-
-Daniel Drake:
-      update "writing udev rules"
-
-Kay Sievers:
-      libvolume_id: gfs + gfs2 support
-      remove MODALIAS key and substitution
-      add persistent-input.rules
-
-Marco d'Itri:
-      update Debian rules
-
-
-Summary of changes from v092 to v093
-============================================
-
-Hannes Reinecke:
-      path_id: add support for iSCSI devices
-
-Kay Sievers:
-      libvolume_id: fat - check for signature at end of sector
-      libvolume_id: add more software raid signatures
-      update Fedora rules
-      path_id: prevent endless loop for SAS devices on older kernels
-      remove udevsend
-      replace binary firmware helper with shell script
-      skip device mapper devices for persistent links
-
-
-Summary of changes from v091 to v092
-============================================
-
-Kay Sievers:
-      don't include stropts.h, some libc's don't like it
-      udevd: create leading directories for /dev/.udev/uevent_seqnum
-      vol_id: fix logging from libvolume_id's log function
-      update SUSE rules
-      update SUSE rules
-      add more warnings for invalid key operations
-      fix offsetof() build issue with recent glibc
-      selinux: fix typo in block device node selection
-      vol_id: add NetWare volume detection
-      edd_id: fix "(null)" output if "mbr_signature" does not exist
-      update Fedora rules
-      libvolume_id: nss - use different uuid
-
-Libor Klepac:
-      path_id: add platform and serio support
-
-Marco d'Itri:
-      update Debian rules
-      path_id: fix bashism
-
-
-Summary of changes from v090 to v091
-============================================
-
-Hannes Reinecke:
-      path_id: fix SAS device path generation
-
-Kay Sievers:
-      udevtest: don't try to delete symlinks
-      persistent rules: fix typo in dm rule
-      allow NAME=="value" to check for already assigned value
-      udevd: export initial sequence number on startup
-
-
-Summary of changes from v089 to v090
-============================================
-
-Kay Sievers:
-      udevd: export current seqnum and add udevsettle
-      volume_id: fix endianess conversion typo for FAT32
-      merge device event handling and make database content available on "remove"
-      set default udevsettle timeout to 3 minutes
-      export INTERFACE_OLD if we renamed a netif
-      let udevmonitor show the possibly renamed devpath
-      volume_id: move some debug to info level
-      udevtrigger: fix event order
-      usb_id: remove uneeded code
-      remove old symlinks before creating current ones
-      path_id: fix loop for SAS devices
-      apply format char to variables exported by ENV
-
-Marco d'Itri:
-      add inotify support for hppa and MIPS and log if inotify is not available
-
-Matt Kraai:
-      fix typo in error message
-
-
-Summary of changes from v088 to v089
-============================================
-
-Hannes Reinecke:
-      path_id: add bus to USB path
-
-Kay Sievers:
-      change rule to skip removable IDE devices
-      don't create uuid/label links for raid members
-      volume_id: provide library
-      fix rule order for persistent tape links
-      update man page
-      volume_id: provide a custom debug function
-      volume_id: rename subdirectory
-      volume_id: use shared library by default
-      because is better than cause
-      volume_id: remove some global symbols
-      volume_id: define exported symbols
-      remove all stripping code
-      man pages: mention udev(7) not udev(8)
-      update Debian rules
-      move all *_id programs to /lib/udev/
-      update Red Hat rules
-      update SUSE rules
-      pass CROSS_COMPILE to AR and RANLIB down to extras/
-      volume_id: update README
-      volume_id: generate man page from xml source
-      update README
-      fix symlink targets in Makefiles
-
-
-Summary of changes from v087 to v088
-============================================
-
-Hannes Reinecke:
-      persistent links: add scsi tape links and usb path support
-
-Kay Sievers:
-      volume_id: add squashfs detection
-      reset signal handler in event process
-      correct use of fcntl()
-      add udevtrigger to request events for coldplug
-      add ',' to trusted chars
-      volume_id: remove partition table parsing code
-      volume_id: remove all partition table support
-      fix spelling error in debug string
-      rename "persistent disk" to "persistent storage"
-      fix output for USB path
-
-
-Summary of changes from v086 to v087
-============================================
-
-Hannes Reinecke:
-      path_id: support SAS devices
-
-Kay Sievers:
-      fix persistent disk rules to exclude removable IDE drives
-      warn about %e, MODALIAS, $modalias
-      remove devfs rules and scripts
-
-Masatake YAMATO:
-      typo in debug text in udev_run_hotplugd.c
-
-
-Summary of changes from v085 to v086
-============================================
-
-Kay Sievers:
-      volume_id: replace __packed__ by PACKED macro
-      volume_id: split raid and filesystem detection
-      volume_id: add missing return
-      udevd: fix queue export for multiple events for the same device
-
-Kyle McMartin:
-      workaround missing kernel headers for some architectures
-
-Nix:
-      update to udev-084/doc/writing_udev_rules
-
-
-Summary of changes from v084 to v085
-============================================
-
-Andrey Borzenkov:
-      Fix trivial spelling errors in RELEASE-NOTES
-
-Jeroen Roovers:
-      fix typo in parisc support to path_id
-
-Kay Sievers:
-      make WAIT_FOR_SYSFS usable in non "wait-only" rules
-      fix typo in man page
-      include sys/socket.h for klibc build
-      cramfs detection for bigendian
-      exit WAIT_FOR_SYSFS if the whole device goes away
-      update SUSE rules
-      update Red Hat rules
-      update Gentoo rules
-      include errno.h in udev_libc_wrapper.c
-
-
-Summary of changes from v083 to v084
-============================================
-
-Kay Sievers:
-      update SUSE rules
-      switch CROSS to CROSS_COMPILE
-      replace fancy silent build program by simple kernel build like logic
-      move manpages to top level
-      remove UDEVD_UEVENT_INITSEND
-      whitespace fixes
-      scsi_id: remove dead files
-      optimize sysfs device and attribute cache
-      let SYSFS{} look at the device, not only the parent device
-      add debug output to sysfs operations
-
-
-Summary of changes from v082 to v083
-============================================
-
-Andrey Borzenkov:
-      man page: document when substitutions are applied for RUN and other keys
-      check for ignore_device in loop looks redundant
-
-Kay Sievers:
-      udevstart: fix NAME="" which prevents RUN from being executed
-      find programs in /lib/udev for IMPORT if {program} is not given
-      don't add $SUBSYSTEM automatically as $1 to programs
-      remove redundant substitution of RUN key
-
-
-Summary of changes from v081 to v082
-============================================
-
-Andrey Borzenkov:
-      substitute format chars in RUN after rule matching
-
-Kay Sievers:
-      scsi_id, usb_id: request device parent by subsystem
-      path_id: work with "all devices in /sys/devices"
-      ignore all messages with missing devpath or action
-      Makefile: remove dynamic config file generation
-      path_id: handle fiber channel (Hannes Reinecke <hare@suse.de>)
-      usb_id: don't fail on other subsytems than "scsi"
-      don't do RUN if "ignore_device" is given
-      increase kernel uevent buffer size
-      move udev(8) manpage to udev(7)
-      recreate man pages from xml source
-      remove udev, udevstart, udevsend from the default installation
-      update SUSE rules
-      rename apply_format() cause it is public now
-      udevtest: add udev_rules_apply_format() to RUN keys
-      let "ignore_device" always return the event successfully
-
-Olivier Blin:
-      fixes udev build with -fpie
-
-
-Summary of changes from v080 to v081
-============================================
-
-Kay Sievers:
-      add DEVLINKS to "remove" event
-      better log text and comments
-      vol_id: probe volume as user nobody
-      fix BUS, ID, $id usage
-      prepare moving of /sys/class devices to /sys/devices
-
-
-Summary of changes from v079 to v080
-============================================
-
-Brent Cook:
-      fix dependency for make -j2
-
-coly:
-      fix man page typos
-
-Kay Sievers:
-      update RELEASE-NOTES + TODO
-      fix typo in man page
-      update TODO
-      update SUSE rules
-      path_id: fix invalid character class
-      replace libsysfs
-
-Marco d'Itri:
-      udev_selinux.c: include udev.h
-
-
-Summary of changes from v078 to v079
-============================================
-
-Kay Sievers:
-      don't log error if database does not exist
-      use udev_root instead of "/dev"in selinux matchpathcon_init_prefix()
-      scsi_id: read page 0x80 with libata drives
-      update SUSE rules
-      remove %e from man page
-
-
-Summary of changes from v077 to v078
-============================================
-
-Greg Kroah-Hartman:
-      Update Gentoo udev main rule file.
-      add parisc support to path_id
-
-Hannes Reinecke:
-      scsi_id: -u fold multiple consecutive whitespace chars into single '_'
-
-Harald Hoyer:
-      optimize SELinux path match
-
-Kay Sievers:
-      update README
-      allow C99 statements
-      fix segfaulting create_floppy_devices
-      update SUSE rules
-      remove unused variables
-      remove default settings in udev.conf
-      clearenv() is now part of klibc
-      add DEVLINKS to the event environment
-
-Kurt Garloff:
-      scsi_id: support pre-SPC3 page 83 format
-
-
-Summary of changes from v076 to v077
-============================================
-
-Kay Sievers:
-      merge two consecutive static strlcat's
-      don't return an error, if "ignore_device" is used
-      remove outdated and misleading stuff
-      move SEQNUM event skipping to udevsend
-      update RELEASE-NOTES
-      update SUSE rules
-      allow programs in /lib/udev called without the path
-      update SUSE rules
-      add target to to generate ChangeLog section
-      update Red Hat rules
-
-Marco d'Itri:
-      allow to overwrite the configured udev_root by exporting UDEV_ROOT
-      let udevsend ignore events with SEQNUM set
-      update Debian rules
-
-
-Summary of changes from v75 to v076
-============================================
-
-Kay Sievers:
-      fix typo in eventrecorder
-      volume_id: include stddef.h header
-      remove misleading install instructions
-      remove all built-in wait_for_sysfs logic
-      add linux/types.h back, old glibc-kernel-headers want it
-      volume_id: use glibc's byteswap
-      udevd: ignore all messages without DEVPATH
-      udevd: track exit status of event process
-      udevd: export event queue and event state
-      remove "udev_db" option from config file
-      Makefile: remove exec_prefix and srcdir
-      update README and RELEASE-NOTES
-      udevd: track killed event processes as failed
-      update README
-      don't start udevd from udevsend
-      udevd: add a missing return
-      libvolume_id: fix weird fat volume recognition
-      move some helpers from extras to /lib/udev
-
-Scott James Remnant:
-      move delete_path() to utils
-      clean-up empty queue directories
-      Makefile: fail, if submake fails
-
-
-Summary of changes from v74 to v075
-============================================
-
-Greg Kroah-Hartman:
-      Make run_directory.c stat the place it is going to try to run.
-
-Kay Sievers:
-      forgot the ChangeLog for 074
-      volume_id: provide libvolume_id.a file
-      remove our own copy of klibc
-      remove outdated HOWTO
-      update TODO
-      update SUSE rules
-      remove completely useless start script
-      fix tests and remove no longer useful stuff
-      replace udeveventrecorder by a shell script
-
-
-Summary of changes from v73 to v074
-============================================
-
-Kay Sievers:
-      never queue events with TIMEOUT set
-      let NAME="" supress node creation, but do RUN keys
-      remove udevinitsend
-      update .gitignore
-
-Marco d'Itri:
-      add strerror() to error logs
-      move some logging from dbg() to info()
-
-
-Summary of changes from v72 to v073
-============================================
-
-Kay Sievers:
-      udevd: depend on netlink and remove all sequence reorder logic
-      print useconds in udevmonitor
-      add RELEASE-NOTES, update TODO
-
-
-Summary of changes from v71 to v072
-============================================
-
-Ananth N Mavinakayanahalli:
-  libsysfs: translate devpath of the symlinked class devices to its real path
-
-Jan Luebbe:
-  add man pages for *_id programs
-
-Kay Sievers:
-  volume_id: add OCFS Version 1
-  volume_id: add Veritas fs
-  volume_id: check ext fs for valid blocksize, cause magic is only 2 bytes
-  volume_id: move blocksize validation to fix jbd recognition
-  volume_id: fix typo in ocfs
-  volume_id: add vxfs include
-  volume_id: make FAT32 recognition more robust
-  volume_id: Version 051
-  volume_id: fix typo in ext blocksize check
-  volume_id: Version 052
-  FAQ: remove confusing statement about module loading
-  cleanup compiler/linker flags
-  use DESTDIR on uninstall, no need to pass prefix to submake
-  allow to pass STRIPCMD, to skip stripping of binaries
-  cleanup make release
-  fix the new warnings I asked for
-  move rules parsing into daemon
-  "make STRIPCMD=" will disable the stripping of binaries
-  remove no longer working udevd-test program
-  "STRIPCMD=" for the EXTRAS
-  add dummy inotify syscalls on unsupported architecture
-  remove no longer needed waiting for "dev" file
-  revert the "read symlink as device patch"
-  use libsysfs to translate the class linke to the device path
-  libsysfs: remove brute-force "bus", "driver" searching for old kernels
-  test: add "driver" and "bus" links to test sysfs tree
-  update RELEASE-NOTES
-  udevd: don't daemonize before initialization
-  log to console if syslog is not available
-  udevd: disable OOM
-  remove precompiled rules option
-  export DEVNAME on "remove" only if we really got a node to remove
-  fix typo in umask()
-
-
-Summary of changes from v70 to v071
-============================================
-
-Greg Kroah-Hartman:
-      Remove the udev.spec file as no one uses it anymore
-
-John Hull:
-      edd_id: check that EDD id is unique
-
-Kay Sievers:
-      ata_id: open volume O_NONBLOCK
-      add "Persistent Device Naming" rules file for disks
-      scsi_id: switch temporary node creation to /dev
-      volume_id: set reiser instead of reiserfs for filesystem type
-      update devfs rules header
-      update Debian rules
-      update Fedora rules
-      update Debian rules
-      remove no longer needed includes
-      switch tools and volume_id from LGPL to GPLv2
-      add edd-*-part%n to the persistent.rules
-      update Debian persistent rules
-      clarify README
-      udevd: fix initial timeout handling
-      force event socket buffer size to 16MB
-      udevd: move logging from err to info for non-hotplug uevent
-      fix selinux compilation
-      libsysfs: accept sysmlinks to directories instead of real directories
-
-Marco d'Itri:
-      run_directory: fix typo in "make install"
-
-
-Summary of changes from v069 to v070
-============================================
-
-Amir Shalem:
-  udevd: fix udevd read() calls to leave room for null byte
-
-Edward Goggin:
-  scsi_id: derive a UID for a SCSI-2 not compliant with the page 83
-
-Greg Kroah-Hartman:
-  fix nbd error messages with a gentoo rule hack
-  fix scsi_id rule in gentoo config file
-
-Jürg Billeter:
-  EXTRAS/Makefile: fix install targets to match main Makefile
-
-Kay Sievers:
-  volume_id: fix error handling with failing read()
-  EXTRAS: cleanup and sync all Makefiles
-  add install test to 'make buildtest'
-  update RELEASE-NOTES
-
-Olivier Blin:
-  fix a debug text typo in udev_rules.c
-
-
-Summary of changes from v068 to v069
-============================================
-
-Amir Shalem:
-  fix typo in firmware_helper
-
-Duncan Sands:
-  firmware_helper: fix write count
-
-Kay Sievers:
-  *_id: fix zero length in set_str()
-  add program name to logged error
-  fix exit code of udevinitsend and udevmonitor
-  udevd: keep the right order for messages without SEQNUM
-  volume_id: don't probe for mac_partition_maps
-  udevmonitor: cleanup on exit
-  path_id: remove SUSE specific PATH
-  update SUSE rules
-  add pci_express to bus list
-  update SUSE rules
-  store ENV{key}="value" exported keys in the database
-  fix lookup for name in the udevdb, it should return the devpath
-  prepare for new HAL udevdb dump
-  print persistent data with "udevinfo -q all"
-  change parameter order of udev_db_search_name()
-  add and use name_list_cleanup() for cleaning up the string lists
-  don't store devpath in udevdb, we don't need it
-  add uft8 validation for safe volume label exporting
-  start to enforce plain ascii or valid utf8
-  use WRITE_END/READ_END for the pipe index
-  remove not needed sig_flag for state of signal_pipe
-  don't reenter get_udevd_msg() if message is ignored
-  rename ...trailing_char() to ...trailing_chars()
-  vol_id: ID_LABEL_SAFE will no longer contain fancy characters
-  udevd: move some logging to "info" and "err"
-  remove special TIMEOUT handling from incoming queue
-  udev_test.pl: we replace untrusted chars with '_'
-  check the udevdb before assigning a new %e
-  update RELEASE-NOTES
-  udevinfo: add database export
-  write man page masters in DocBook XML
-  udevinfo: rename dump() to export()
-  test the automatic man page rebuild and checkin
-  Makefile: remove all the duplicated rules
-  all man pages rewritten to use DocBook XML
-  add missing udevsend man page
-  also forgot udevmonitor.8
-  udevinfo: restore -d option
-  scsi_id: rename SYSFS to LIBSYSFS
-  add edd_id tool to match BIOS EDD disk information
-  move and update libsysfs.txt
-  klibc: update to version 1.1.1
-  delete cdromsymlinks* - obsoleted by cdrom_id and IMPORT rules
-  delete docs/persistent_naming - obsoleted by persistent disk names
-  delete old Fedora html page
-  add "totally outdated" header to docs/overview :)
-  update SUSE rules
-  fix useless but funny name_cdrom.pl script to work again
-  update TODO
-  Makefile: fix prerequisits for $(PROGRAMS)
-  Makefile: cleanup install targets
-  remove chassis_id program
-  fic gcov use and move it into the Makefile
-  FAQ: update things that have changed
-
-Thierry Vignaud:
-  switch to '==' in raid-devfs.sh
-
-
-Summary of changes from v067 to v068
-============================================
-
-Greg Kroah-Hartman:
-  add EXTRAS documentation to the README file.
-  Always open the cdrom drive in non-blocking mode in cdrom_id
-  cdrom_id: change err() to info() to help with debugging problems
-
-Kay Sievers:
-  cleanup some debug output and move to info level + unify select() loops
-  move udevmonitor to /usr/sbin
-  ENV{TEST}=="1" compares and ENV{TEST}="1" sets the environment
-  vol_id: fix sloppy error handling
-  fix typo in cdrom_id syslog
-  bring std(in|out|err) fd's in a sane state
-  fix printed udevmonitor header
-
-
-Summary of changes from v066 to v067
-============================================
-
-Greg Kroah-Hartman:
-  added the cdrom.h #defines directly into the cdrom_id.c file
-
-Kay Sievers:
-  update SUSE rules
-  fix make install, as we don't provide a default rule set anymore
-  fix more compiler warnings ...
-  fix udevstart event ordering, we want /dev/null very early
-  don't fail too bad, if /dev/null does not exist
-
-
-Summary of changes from v065 to v066
-============================================
-
-Greg Kroah-Hartman:
-  update gentoo rule file.
-  Created cdrom_id program to make it easier to determine cdrom types
-  added cdrom_id to the build check
-  updated gentoo rule file to handle removable ide devices.
-  changed cdrom_id exports to be easier to understand and consistant with other _id programs.
-  fix klibc build issue in cdrom_id.c
-  Change the gentoo rules to use cdrom_id instead of cdsymlink.sh
-  changed location of gentoo helper apps to be /sbin instead of in scripts dir
-  tweak the gentoo rules some more.
-
-Kay Sievers:
-  add NETLINK define for the lazy distros
-  read sysfs attribute also from parent class device
-  switch some strlcpy's to memcpy
-  allow clean shutdown of udevd
-  add flag for reading of precompiled rules
-  update distro rules files
-  add SUSE rules
-  update SUSE rules
-  add firmware_helper to load firmware
-  more distro rules updates
-  update README
-  remove example rules and put the dev.d stuff into the run_directory folder
-  trivial text cleanups
-  update SUSE rules
-  split udev_util in several files
-  update SUSE rules
-  allow logging of all output from executed tools
-  add Usage: to udevmonitor and udevcontrol
-  move some logging to the info level
-
-Thierry Vignaud:
-  fix udevinfo output
-
-
-Summary of changes from v064 to v065
-============================================
-
-Greg Kroah-Hartman:
-  Added persistent name rules for block devices to gentoo rule file.
-  Added horrible (but fun) path_id script to extras.
-  Update gentoo rules file.
-
-Kay Sievers:
-  update release notes for next version
-  add udevmonitor, to debug netlink+udev events at the same time
-  allow RUN to send the environment to a local socket
-  fix GGC signed pointer warnings and switch volume_id to stdint
-
-
-Summary of changes from v063 to v064
-============================================
-
-Andre Masella:
-  volume_id: add OCFS (Oracle Cluster File System) support
-
-Hannes Reinecke:
-  usb_id: fix typo
-  add ID_BUS to *_id programs
-  create_floppy_devices: add tool to create floppy nodes based on sysfs info
-
-Kay Sievers:
-  move code to its own files
-  make SYSFS{} usable for all devices
-  add padding to rules structure
-  allow rules to have labels and skip to next label
-  thread unknown ENV{key} match as empty value
-
-
-Summary of changes from v062 to v063
-============================================
-
-Anton Farygin:
-  fix typo in GROUP value application
-
-Greg Kroah-Hartman:
-  add 'make tests' as I'm always typing that one wrong...
-  Really commit the udev_run_devd changes...
-  Fixed udev_run_devd to run the /etc/dev.d/DEVNAME/ files too
-  fix position of raw rules in gentoo config file
-
-Hannes Reinecke:
-  dasd_id: add s390 disk-label prober
-  fix usb_id and let scsi_id ignore "illegal request"
-
-Kay Sievers:
-  volume_id: remove s390 dasd handling, it is dasd_id now
-  trivial fixes for *_id programs
-  IMPORT: add {parent} to import the persistent data of the parent device
-  allow multiple values to be matched with KEY=="value1|value2"
-  udevd: set incoming socket buffer SO_RCVBUF to maximum
-  remember mapped rules state
-  ata_id: check for empty serial number
-  compile dasd only on s390
-
-Ville Skyttä:
-  correct default mode documentation in udev
-
-
-Summary of changes from v061 to v062
-============================================
-
-Kay Sievers:
-  fix symlink values separated by multiple spaces
-  update RELEASE-NOTES
-  fix typo in group assignment
-  fix default-name handling and NAME="" rules
-  add WAIT_FOR_SYSFS key to loop until a file in sysfs arrives
-  fix unquoted strings in udevinitsend
-
-Summary of changes from v060 to v061
-============================================
-
-Greg Kroah-Hartman:
-  Sync up the Debian rules files
-  fix cdrom symlink problem in gentoo rules
-  Fix ChangeLog titles
-
-Kay Sievers:
-  update RELEASE-NOTES
-  we want to provide OPTFLAGS
-  rename ALARM_TIMEOUT to UDEV_ALARM_TIMEOUT
-  udevd: optimize env-key parsing
-  don't resolve OWNER, GROUP on precompile if string contains %, $
-  set default device node to /dev
-  create udevdb files only if somehting interesting happened
-  pack parsed rules list
-  replace useless defines by inline text
-  move rule matches to function
-  add usb_id program to generate usb-storage device identifiers
-  add IEEE1394 rules to the gentoo rule file
-  fake also kernel-name if we renamed a netif
-  allow OPTIONS to be recognized for /sys/modules /sys/devices events
-  switch gentoo rules to new operators
-
-
-Summary of changes from v059 to v060
-============================================
-
-Greg Kroah-Hartman:
-  Fix the gentoo udev rules to allow the box to boot properly
-
-Gustavo Zacarias:
-  Udev doesn't properly build with $CROSS
-
-Kay Sievers:
-  Keep udevstart from skipping devices without a 'dev' file
-
-Marco d'Itri:
-  #define NETLINK_KOBJECT_UEVENT
-
-
-Summary of changes from v058 to v059
-============================================
-
-Greg Kroah-Hartman:
-  Update the gentoo rule file
-  Fix udevinfo for empty sysfs directories
-  Fix makefile to allow 'make release' to work with git
-
-Hannes Reinecke:
-  udev: fix netdev RUN handling
-  udevcontrol: fix exit code
-
-Kay Sievers:
-  prepare RELEASE-NOTES
-  add ID_TYPE to the id probers
-  add -x to scsi_id to export the queried values in env format
-  store the imported device information in the udevdb
-  rename udev_volume_id to vol_id and add --export option
-  add ata_id to read serial numbers from ATA drives
-  IMPORT allow to import program returned keys into the env
-  unify execute_command() and execute_program()
-  IMPORT=<file> allow to import a shell-var style config-file
-  allow rules to be compiled to one binary file
-  fix the fix and change the file to wait for to the "bus" link
-  fix udevstart and let all events trvel trough udev
-  prepare for module loading rules and add MODALIAS key
-  remove device node, when type block/char has changed
-  Makefile: remove dev.d/ hotplug.d/ from install target
-  udevcontrol: add max_childs command
-  udevd: control log-priority of the running daemon with udevcontrol
-  udeveventrecorder: add small program that writes an event to disk
-  klibc: add missing files
-  udevinitsend: handle replay messages correctly
-  udev man page: add operators
-  udevd: allow starting of udevd with stopped exec-queue
-  klibc: version 1.0.14
-  udev: handle all events - not only class and block devices
-  volume_id: use udev-provided log-level
-  udev: clear lists if a new value is assigned
-  udev: move dev.d/ handling to external helper
-  udev: allow final assignments :=
-  udevd: improve timeout handling
-  Makefile: fix DESTDIR
-  udevd: add initsend
-  udevd: add udevcontrol
-  udevd: listen for netlink events
-
-Stefan Schweizer:
-  Dialout group fix for capi devices in the gentoo rules file
-
-Summary of changes from v057 to v058
-============================================
-
-Daniel Drake:
-  o Writing udev rules docs update
-
-Darren Salt:
-  o update cdsymlinks to latest version
-
-Greg Kroah-Hartman:
-  o remove detach_state files from the sysfs test tree
-  o Update permissions on test scripts so they will run properly now
-  o hopefully fix up the symlinks in the test directory
-  o Removed klibc/klibc.spec as it is autogenerated
-  o Added symlinks thanks to Kay's script and git hacking
-  o add Red Hat/Fedora html documenation
-  o Update Red Hat default udev rules
-
-Kay Sievers:
-  o selinux: fix handling during creation of symlinks
-  o Fedora udev.rules update
-  o libsysfs: version 2.0
-  o klibc: version 1.0.7
-
-Masanao Igarashi:
-  o Fix libsysfs issue with relying on the detach_state file to be
-
-Summary of changes from v056 to v057
-============================================
-
-<tklauser:access.unizh.ch>:
-  o fix stupid all_partitions bug
-
-Kay Sievers:
-  o add test for make -j4 to build-check
-  o klibc: version 1.0.6
-  o update Debian rules
-  o apply default permissions only for devices that will need it
-  o adapt RELEASE-NOTES
-  o udev_volume_id: fix endianess macros
-  o udev-test.pl: add test for DEVNAME export to RUN environment
-  o update the man page to reflect the recent changes
-  o export DEVNAME to RUN-key executed programs
-  o fix make -j4 and the local klibc-install
-  o update RELEASE-NOTES
-  o add RUN key to be able to run rule based notification
-  o fix udevtest to print the error if logging is disabled
-  o move execute_program to utils + add action to init_device
-  o correct correction for error path for PROGRAM execution
-  o correct error path for PROGRAM execution
-  o klibc: version 1.0.5
-  o check for strlen()==0 before accessing strlen()-1
-  o allow to match against empty key values
-  o read %s{}-sysfs values at any device in the chain
-  o udev_rules.c: don't change sysfs_device while walking up the device chain
-  o klibc: strlcpy/strlcat - don't alter destination if size == 0
-  o fix klibc's broken strlcpy/strlcat
-  o udevinfo: print SYSFS attribute the same way we match it
-  o remove untrusted chars read from sysfs-values or returned by PROGRAM
-  o udevinfo: print errors to stderr instead of stdout
-  o klibc: version 1.0.4
-  o support log-priority levels in udev.conf
-  o test-suite: remove UDEV_TEST, it's not needed anymore
-  o libsysfs: remove trailing slash on SYSFS_PATH override
-
-
-Summary of changes from v055 to v056
-============================================
-
-<tklauser:access.unizh.ch>:
-  o fix header paths in udev_libc_wrapper.c
-
-Kay Sievers:
-  o udev-test.pl: use more common user/group names
-  o klibc: remove SCCS directories from the temporary klibc install
-  o udev-test.pl: add a test where the group cannot be found in /etc/passwd
-  o udev-test.pl: add check for textual uid/gid
-  o fix bad typo that prevents the GROUP to be applied
-  o udevd: don't delay events with TIMEOUT in the environment
-  o klibc: use klcc wrapper instead of our own Makefile
-  o change call_foreach_file to return a list
-
-
-Summary of changes from v054 to v055
-============================================
-
-<jkluebs:luebsphoto.com>:
-  o This patch causes the remove handler to check that each symlink actually points to the correct devnode and skip it if it does not.
-
-<pebenito:gentoo.org>:
-  o udev selinux fix
-
-<tklauser:access.unizh.ch>:
-  o The following patch fixes some warnings when compiling volume_id from udev with the -Wall compiler flag. Define _GNU_SOURCE for strnlen() and correct the path to logging.h
-  o The following patch fixes a warning when compiling chassis_id from udev with the -Wall compiler flag. There are too much conversions in the format string of sscanf(). One %d can be dropped.
-
-Greg Kroah-Hartman:
-  o fix raid rules
-  o added frugalware udev ruleset
-  o merge selinux and Kay's symlink fixes together
-
-Hannes Reinecke:
-  o volume_id: Fix label/uuid reading for reiserfs
-
-Kay Sievers:
-  o add udevstart to the RELEASE-NOTES
-  o volume_id: version 43
-  o clarify the shortcomings of %e
-  o correct rule match for devices without a physical device
-  o remove unneeded code, libsysfs does this for us
-  o add final release note
-  o add ENV{} key to match agains environment variables
-  o simplify sysfs_pair handling
-  o add a test and simplify debug statement
-  o support =, ==, !=, += for the key match and assignment
-  o add OPTION="last_rule" to skip any later rule
-  o rename namedev_dev to udev_rule
-  o correct enum device_type
-  o remove udevstart on make clean
-  o volume_id: version 42
-  o volume_id: version 41
-  o remove unneeded include
-  o The path to dlist.h is not correct
-  o udevinfo -d: use '=' as separator, cause ':' may be a part of the devpath
-  o klibc: version 1.0.3
-  o add RELEASE-NOTES file
-  o test suite: move "driver" link to physical device
-  o remove PLACE key match
-  o don't lookup "root" in the userdb
-  o fix ia64 compile
-  o fix segfaulting udev while DRIVER matching
-  o cleanup list.h
-  o klibc: version 0.214
-  o rename device_list->list to device_list->node
-  o replace strncpy()/strncat() by strlcpy()/strlcat()
-  o split udev and udevstart
-  o udev_volume_id: version 39
-  o rename LOG to USE_LOG in all places
-  o remove Makefile magic for klibc integration
-  o klibc_fixups: remove no longer needed stuff
-  o udev_volume_id: volume_id v38
-  o use numeric owner/group as default values to avoid parsing userdb
-  o fix up segfaulting binaries with new klibc
-  o udevinfo -d: speed-up device dump
-  o klibc: version 0.211
-  o klibc_fixups: remove unneeded stuff
-  o replace weird defines by real code
-  o udev-test.pl: remove useless tests
-  o allow unlimitied count of symlinks
-  o unmap db-file after use
-  o remove typedef for call_foreach_file() handler function
-  o correct udev_init_device
-  o rename attributes to options
-  o kill stupid gcc4 warning
-  o trivial clenaup of namedev code
-  o klibc: check for gcc4
-  o klibc: update v0.205
-
-Thierry Vignaud:
-  o gentoo rule update for raid devices
-
-
-Summary of changes from v053 to v054
-============================================
-
-<tklauser:access.unizh.ch>:
-  o udev_volume_id: add Reiser4 support
-
-Kay Sievers:
-  o namedev: skip backslashes only if followed by newline
-  o wait_for_sysfs: add joydev
-  o udevinfo: print devpath -> node relationship for all devices
-  o trivial rename of some variables
-  o klibc v0.199
-  o big libsysfs diet (pre 2.0 version)
-  o udev_volume_id: volume_id v35
-  o add "serio" to bus list
-  o determine device type in udev_init_device()
-  o move kernel name/number evaluation into udev_init_device()
-  o detect NAME="" as ignore_device rule
-  o trivial namedev cleanup
-  o cleanup db functions
-  o clean up match_place()
-  o switch device type to enum
-  o switch major/minor to dev_t
-  o remove the device node only if the major/minor number matches
-  o libsysfs: work around a klibc bug
-  o introduce OPTIONS=ignore_device, ignore_remove, all_partitions" key
-  o namedev: execute PROGRAM only once and not possibly for every physical device
-
-Patrick Mansfield:
-  o update scsi_id to work with libsysfs changes
-
-
-Summary of changes from v052 to v053
-============================================
-
-Greg Kroah-Hartman:
-  o fix gentoo fb permission issue
-  o allow simple-build-check.sh to go faster if MAKEOPTS is set
-  o make the release tarballs have writable files in them
-  o remove gentoo permission file as it's not valid anymore
-
-Kay Sievers:
-  o fix special file mode mask for temporary device node
-  o udevstart: simplify "dev" file searching
-  o udev_volume_id: remove temporary node creation and parent handling
-  o add %P modifier to query the node name of the parent device
-  o udev_volume_id: remove __packed__ from dasd structure as it does not work
-  o create /block/*/range count of partitons for all_partitions
-
-Patrick Mansfield:
-  o scsi_id changes for use with udev %N and %p
-
-
-Summary of changes from v051 to v052
-============================================
-
-<md:linux.it>:
-  o debian: update rules files
-  o raid-devfs.sh: devfs names for hardware RAID controllers
-  o scsi_id: when udevstart is started, /tmp is not writeable
-  o cdsymlinks.sh: trivial fix, the variable is initialized to '', not 0
-
-<sschweizer:gmail.com>:
-  o gentoo/udev.rules: add default permissions for sound devices
-
-Greg Kroah-Hartman:
-  o fix example comment in ide-devfs.sh
-  o Add infiniband to gentoo rules
-  o Another gentoo fix, adding dvb support
-  o Fix gentoo bug #76056 (fb device group permissions.)
-  o Fix gentoo bug #81102, device nodes for the pktcdvd device
-
-Kay Sievers:
-  o provide temporary device node for callouts to access the device
-  o udev_volume_id: fix dasd disklabel reading with -l option
-  o udev_volume_id: volume_id version 034
-  o udev_volume_id: rename probe_ibm into probe_dasd
-  o udev_volume_id: volume_id version 032
-  o Makefile: add some more warnings and prepare for clean gcc4 compile
-  o Makefile: cleanup conditional config option sections
-  o fix -Wsign-compare warnings
-  o chassis_id: clean compilation and fix bad function parameter passing
-  o simple_build_check: make it possible to pass KERNEL_DIR
-  o selinux: cleanup udev integration
-
-Michael Buesch:
-  o trivial: remove _all_ trailing slashes with no_trailing_slash()
-  o trivial: fix signedness
-  o namdev: allow symlink-only rules to specify node permissions
-  o udevd: fix valgrind warning
-
-
-Summary of changes from v050 to v051
-============================================
-
-<roland:digitalvampire.org>:
-  o This fixes a silly mistake in how udevinfo prints the major and minor numbers (right now it prints the minor next to "MAJOR" and the major next to "MINOR" ;)
-
-<tklauser:access.unizh.chbk>:
-  o I tried to compile udev 050plus with the GCC 4.0 snapshot 200412119 and got two errors about possibly uninitialized structs, so I fixed this. 
-
-Christian Bornträger:
-  o udev_volume_id: fix -d option
-
-Greg Kroah-Hartman:
-  o gentoo fb permission fix
-  o fix gcc 2.96 issue in libsysfs
-  o remove the lfs startup script on request of the author
-  o clean up the aoe char device rules, and delete the block one as it's not needed
-  o add aoe block and char device rules to the gentoo rule file
-  o fix udev_volume_id build error
-
-Hannes Reinecke:
-  o rearrange link order in Makefile
-
-Kay Sievers:
-  o udev_volume_id: new version of volume_id
-  o klibc: update to version 0.198
-  o udev_volume_id: fix FAT label reading
-  o klibc: update to version 0.196
-  o udevd: throttle the forking of processes
-  o udevd: add possible initialization of expected_seqnum
-  o udevd: it's obviously not the brightest idea to exit a device node manager if it doesn't find /dev/null
-  o udevd: separate socket handling to prepare for other event sources
-  o udevd: support -d switch to become a daemon
-  o udev_volume_id: version 27
-  o udevd: split up message receiving an queueing
-  o remove useless warning if udev.conf contains keys not read by udev itself
-  o improve event sequence serialization
-  o remove udevsend syslog noise on udevd startup
-  o limit the initial timeout of the udevd event handling
-  o correct detection of hotplug.d/ udevsend loop
-  o correct log statement
-  o remove default_* permissions from udev.conf file
-  o update Fedora config files and add some more tests
-  o allow permissions only rules
-  o add SUBSYSTEM rule to catch all block devices and apply the disk permissions
-  o update Fedora config files
-  o handle renamed network interfaces properly if we manage hotplug.d/
-  o allow multiline rules by backslash at the end of the line
-  o add OnStream tape drive rules
-  o simplify rules file by setting default mode to 0660
-  o simplify permission application
-  o I broke the extras/ again. Add simple build test script now
-  o Merge vrfy.org:/home/kay/src/udev into vrfy.org:/home/kay/src/udev.kay
-  o initial merge of fedora udev.permissions into udev.rules
-  o remove permissions file mentioning from the udev man page
-  o fix some typos in gentoo's udev.rules introduced by the merge
-
-Michael Buesch:
-  o The attached patch fixes the code path if namedev_name_device() fails
-
-Summary of changes from v049 to v050
-============================================
-
-<harald:redhat.com>:
-  o selinux patch
-
-<tklauser:access.unizh.ch>:
-  o I made some more changes to the manpage of udev including
-
-Kay Sievers:
-  o update libsysfs to CVS version and fix segfaulting attribute reading
-  o klibc supports LOG_PID now, so remove our own implementation
-  o avoid building klibc test programs and pass SUBDIRS= to klibc clean
-
-
-Summary of changes from v048 to v049
-============================================
-
-Greg Kroah-Hartman:
-  o fix 'make clean' error in klibc
-
-Kay Sievers:
-  o update klibc to 0.194
-  o export DEVNAME regardless of the state of udev_dev_d
-  o add class specific files for class/spi_transport and class/spi_host
-  o udevd-test.pl: remove wrong date calculation
-  o check earlier if we should run as udevstart
-  o remove double initialization
-  o include missing header to udevtest.c
-  o add -V option to udev to print the version number
-  o prevent udev node creatinon for "class" registration
-  o udevd: serialization of the event sequence of a chain of devices
-  o add a class/fc_host file to the list of what to wait for
-  o udev_volume_id: links sysfs.a instead of all objects
-
-Martin Schlemmer:
-  o remove leftover from udevinfo's -d option
-
-
-Summary of changes from v047 to v048
-============================================
-
-Greg Kroah-Hartman:
-  o fix udev_volume_id so it will now build properly
-  o fix scsi_id build errors due to changes in the main udev makefile
-
-
-Summary of changes from v046 to v047
-============================================
-
-<klauser:access.unizh.ch>:
-  o Various typos and other litte errors in udev.8.in
-
-<sjoerd:spring.luon.net>:
-  o DEVNAME on device removal
-
-<sschweizer:gmail.com>:
-  o Allow GROUP to have modifiers in it
-
-Greg Kroah-Hartman:
-  o add more debian rules files
-  o move distro specific config files into their own directories
-  o update debian rules files
-  o added asterix rules to the gentoo file
-  o use udevstart for udev.init.* files
-  o delete a bunch of files no longer needed
-  o fix gentoo scsi cdrom rule
-  o Fix the multithreaded build again
-  o merge
-  o comment out ability to run udev-test.pl with valgrind
-  o fix spurious valgrind warning in udev
-  o fix udevinfo '-q path' option as it was not working
-  o merge
-  o fix parallel build error
-
-Kay Sievers:
-  o update Fedora dev.d/ example and remove unused conf.d/ directory
-  o don't install distribution specific init script on "make install"
-  o restore OWNER/GROUP assignment in rule coming from RESULT
-  o make gcov compile scripts working with recent gcc
-  o fix udev-test/udev-test.pl to work with again
-  o add net/atml and class/ppdev to the wait_for_sysfs exception list
-  o add net/nlv* devices to the exception list
-  o add "pcmcia" and "fc_transport" to the wait_for_sysfs lists
-  o remove unused timestamp field
-  o simplify permission handling
-  o handle /etc/hotplug.d/ only if the event comes from udevd
-  o trivial cleanups and change some comments
-  o remove unused variables
-  o udevsend/udevd handle events without a subsystem
-  o use blacklist on device "remove" and remove dev.d/ call code duplication
-  o update the man pages and correct Usage: hints
-  o don't call the hotplug scripts with a test run
-  o don't call dev.d/ scripts twice, if directory = subsystem
-  o remove archive file if we changed something
-  o link archive insted of objects
-  o rename udev_lib to udev_utils and dev_d to udev_multiplex
-  o handle whole hotplug event with udevd/udev
-  o integrate wait_for_sysfs in udev
-  o make the searched multiplex directories conditionally
-  o add MANAGED_EVENT to the forked udev environment
-  o export DEVNAME on remove event
-  o export udev_log flag to the environment
-  o remove my test code
-  o add support for /devices-devices without any file to wait for
-  o Patch from Alex Riesen <raa.lkml@gmail.com>
-  o add a bunch of busses to the list of what to wait for
-  o close connection to syslog in forked udevd child
-  o udevd exit path cleanup
-  o fix network device naming bug
-
-
-Summary of changes from v045 to v046
-============================================
-
-Greg Kroah-Hartman:
-  o make spotless for releases
-
-Kay Sievers:
-  o Don't try to print major/minor for devices without a dev file
-  o remove get_device_type and merge that into udev_set_values()
-  o prevent udevd crash if DEVPATH is not set
-  o add ippp and bcrypt to the exception lists of wait_for_sysfs
-  o let klibc add the trailing newline to syslog conditionally
-  o disable logging for udevstart
-  o add NAME{ignore_remove} attribute
-  o remove historical SYSFS_attr="value" format
-  o don't wait for sysfs if the kernel(2.6.10-rc2) tells us what not to expect
-  o change key names in udevinfo sysfs walk to match the kernel
-  o support DRIVER as a rule key
-  o support SUBSYSTEM as a rule key
-  o rename udevdb* to udev_db*
-  o Make dev.d/ handling a separate processing stage
-  o make the udev object available to more processing stages
-  o remove udev_lib dependency from udevsend, which makes it smaller
-  o add ACTION to udev object to expose it to the whole process
-  o make udevinfo's -r option also workimg for symlink queries
-  o let udev act as udevstart if argv[1] == "udevstart"
-  o improve udevinfo sysfs info walk
-  o add sysfs info walk to udevinfo
-  o pass the whole event environment to udevd
-  o replace tdb database by simple lockless file database
-
-
-Summary of changes from v044 to v045
-============================================
-
-Martin Schlemmer:
-  o Some updates for Gentoo's udev rules
-
-
-Summary of changes from v043 to v044
-============================================
-
-Greg Kroah-Hartman:
-  o add cdsymlinks.sh support to gentoo rules file
-  o fix gentoo legacy tty rule
-  o remove 'sudo' usage from the Makefile
-  o make udev-test.pl test for root permissions before running
-
-Kay Sievers:
-  o reduce syslog noise of udevsend if multiple instances try to start udevd
-  o add i2c-dev to the list of devices without a bus
-
-
-Summary of changes from v042 to v043
-============================================
-
-Greg Kroah-Hartman:
-  o add test target to makefile
-  o add dumb script to show all sysfs devices in the system
-
-Kay Sievers:
-  o Shut up wait_for_sysfs class/net failure messages, as it's not possible to
-    get that right for all net devices. Kernels later than 2.6.10-rc1 will
-    handle that by carrying the neccessary information in the hotplug event.  
-  o wait() for specific pid to return from fork()
-  o Don't use any syslog() in signal handler, cause it may deadlock
-  o Add support for highpoint ataraid to volume_id to suppress label reading on raid set members.
-  o Add a bunch of devices without "device" symlinks
-  o Exit, if udevtest cannot open the device (segfault)
-  o Patches from Harald Hoyer <harald@redhat.com>
-  o Apply the default permissions even if we found a entry in the permissions
-    file. Correct one test, as the default is applied correctly now and the
-    mode will no longer be 0000.
-  o add test for format chars in multiple symlinks to replace
-  o Add net/vmnet and class/zaptel to the list of devices without physical device
-
-
-Summary of changes from v040 to v042
-============================================
-
-Greg Kroah-Hartman:
-  o add inotify to the rules for gentoo
-
-Kay Sievers:
-  o skip waiting for device if we get a bad event for class creation and not for a device underneath it
-  o add net/pan and net/bnep handling
-  o switch wait for bus_file to stat() instead of open() add net/tun device handling add ieee1394 device handling
-  o Remove the last klibc specific line from the main udev code Move _KLIBC_HAS_ARCH_SIG_ATOMIC_T to the fixup file which is automatically included by the Makefile is we build with klibc
-  o ignore *.rej files from failed patches
-  o update to libsysfs 1.2.0 and add some stuff klib_fixup Now we have only the sysfs.h file different from the upstream version to map our dbg() macro.
-  o improve klibc fixup integration
-  o cleanup udevd/udevstart
-  o expose sysfs functions for sharing it
-
-
-Summary of changes from v039 to v040
-============================================
-
-<jk:blackdown.de>:
-  o wait_for_sysfs update for dm devices
-
-Greg Kroah-Hartman:
-  o sparse cleanups on the tree
-  o fix stupid cut-and-paste error for msr devices on gentoo boxes
-  o add *~ to bk ignore list
-  o delete udevruler.c as per Kay's request
-  o fix up the wait_for_sysfs_test script a bit
-
-Kay Sievers:
-  o fix debug in volume id / fix clashing global var name
-  o volume_id fix
-  o $local user
-  o cleanup netif handling and netif-dev.d/ events
-  o big cleanup of internal udev api
-  o don't wait for dummy devices
-  o close the syslog
-  o Fix ppp net devices in wait_for_sysfs
-  o Fix wait_for_sysfs messages (more debugging info)
-
-
-Summary of changes from v038 to v039
-============================================
-
-Greg Kroah-Hartman:
-  o Hopefully fix the vcs issue in wait_for_sysfs
-  o take out & from wait_for_sysfs_test that I previously missed
-  o add very nice cdsymlinks scripts
-  o add some helper scripts for dvb and input devices
-  o add debian config files
-  o let the extras/ programs build "pretty" also
-  o tweak the ccdv program to handle files in subdirectories being built
-  o crap, I messed up the 'sed' instances pretty badly, this fixes the config and man page mess
-  o fix broken 'make -j5' functionality
-
-Kay Sievers:
-  o swich attribute open() to simple stat()
-  o wait_for_sysfs update for /class/firmware and /class/net/irda devices
-  o fix unusual sysfs behavior for pcmcia_socket
-  o remove sleeps from udev as it is external now
-  o delete udevruler?
-  o Makefile fix
-
-Patrick Mansfield:
-  o update udev to scsi_id 0.7
-  o pass SYSFS setting down for extras builds
-  o move assignments past local variables
-
-
-Summary of changes from v037 to v038
-============================================
-
-<andrew.patterson:hp.com>:
-  o Re: Problem parsing %s in udev rules
-
-Greg Kroah-Hartman:
-  o fix up error in building extras and libsysfs
-
-Summary of changes from v036 to v037
-============================================
-
-<md:linux.it>:
-  o small udev patch
-
-Greg Kroah-Hartman:
-  o fix compilation warning in tdb log message
-  o Fix build error with klibc due to recent changes
-  o merge
-  o add wait_for_sysfs test script to the tarball to help people debug their boxes
-  o add ipsec to wait_for_sysfs ignore list
-  o added ccdv to bk ignore list
-  o a few more Makefile tweaks for the quiet feature
-  o Make the build silent, thanks to a helper program from ncftp
-  o rename files to have '_' instead of '-' in them
-  o change max time to wait in wait_for_sysfs to 10 seconds to hopefully handle some slow machines
-  o add support for class/raw/ to wait_for_sysfs
-  o fix up Makefile for wait_for_sysfs udev_version.h dependancy
-  o remove the debian specific file, as they don't want to share with the rest of the world :(
-
-Kay Sievers:
-  o prevent deadlocks on an corrupt udev database
-  o wait_for_sysfs_update
-
-Michael Buesch:
-  o fix asmlinkage
-  o fix incompatible pointer type warning
-
-
-Summary of changes from v035 to v036
-============================================
-
-Greg Kroah-Hartman:
-  o add the error number to the error message in wait_for_sysfs to help out in debugging problems
-
-Summary of changes from v034 to v035
-============================================
-
-Greg Kroah-Hartman:
-  o added ieee1394 support to wait_for_sysfs
-  o update wait_for_sysfs with a bunch more devices thanks to user reports
-
-Summary of changes from v033 to v034
-============================================
-
-Kay Sievers:
-  o wait_for_sysfs bluetooth class update
-
-Greg Kroah-Hartman:
-  o add comment in wait_for_sysfs to explain the structure better
-  o Revert previous dev_d.c change, it's not what is causing HAL problems
-  o hm, somethings odd with DEVPATH, see if this fixes it
-  o 33_bk mark for the makefile
-  o wait_for_sysfs: clean up the logic for the list of devices that we do not expect device symlinks for
-  o get rid of annoying extra lines in the syslog for some libsysfs debug messages
-  o added support for i2c devices in wait_for_sysfs.c
-  o add support for i2c-adapter devices to wait_for_sysfs.c
-
-Summary of changes from v032 to v033
-============================================
-
-<harald:redhat.com>:
-  o udev close on exec
-  o some cleanups and security fixes
-  o some cleanups and security fixes
-  o selinux for udev
-  o cleanup PATCH for extras/chassis_id/Makefile
-
-<kpfleming:backtobasicsmgmt.com>:
-  o respect prefix= setting in built udev.conf (updated)
-
-Greg Kroah-Hartman:
-  o add support for usb interfaces to wait_for_sysfs to keep it quiet
-  o enable native tdb spinlocks on i386 platforms
-  o delete extras/multipath-tools as per the author's request
-  o be paranoid in dev_d.c
-  o add USE_SELINUX to README documentation so people have a chance to see what is going on
-  o update the selinux.h file to start to look sane
-  o update bk ignore list for the wait_for_sysfs binary
-  o kdetv wants to see device nodes in /dev
-  o update comments in scsi-devfs.sh
-  o fix up Makefiles to get the klibc build working properly
-  o update bk ignore list for new klibc generated files
-  o oops forgot to add the new klibc/include directory
-  o update klibc to version 0.181
-
-Kay Sievers:
-  o fix problems with dev.d and udevstart
-  o wait_for_sysfs debug cleanup
-  o fix problems using scsi_id with udevstart
-  o update volume_id
-  o finally solve the bad sysfs-timing for all of us
-  o volume-id build fix and update
-  o switch udev's seqnum to u64
-  o add enum tests
-  o fix udev segfaults with bad permissions file
-
-Patrick Mansfield:
-  o update udev to include scsi_id 0.6
-
-
-Summary of changes from v031 to v032
-============================================
-
-<harald:redhat.com>:
-  o udev parse bug
-
-Kay Sievers:
-  o handle only block and class devices
-  o fix udevstart badly broken in udev 031
-
-
-Summary of changes from v030 to v031
-============================================
-
-<arun:codemovers.org>:
-  o udev - read long lines from config files overflow fix
-
-<ballarin.marc:gmx.de>:
-  o Update the FAQ with info about hardlink security
-
-<david:fubar.dk>:
-  o compatibility symlinks for udev
-
-David Weinehall:
-  o Minor POSIX-fixes for udev
-
-Greg Kroah-Hartman:
-  o add symlink for video rule
-  o add a "first" list to udevstart and make it contain the class/mem/ devices
-  o fix compiler warning in udevtest.c
-  o Fix old-style pty breakage in rules file for tty device
-  o add rules for i386 cpu devices
-  o add permission for legotower usb devices
-
-Kay Sievers:
-  o Fix naming ethernet devices in udevstart
-  o update udev_volume_id
-  o let /sbin/hotplug execute udev earlier
-  o pass SEQNUM trough udevd
-  o fix manpages based on esr's spambot
-
-Martin Schlemmer:
-  o add microcode rule to permissions.gentoo file
-
-Michael Buesch:
-  o Try to provide a bit of security for hardlinks to /dev entries
-
-Olaf Hering:
-  o udevsend depends on udev_lib.o
-
-Tom Rini:
-  o fix UDEV_NO_SLEEP
-  o clean up start_udev a bit
-  o Make udev/udevstart be one binary
-  o Add 'asmlinkage' to udev-030
-
-
-Summary of changes from v029 to v030
-============================================
-
-Greg Kroah-Hartman:
-  o fix stupid off-by-one bug that caused udevstart to die on x86-64 boxes
-
-
-Summary of changes from v028 to v029
-============================================
-
-Greg Kroah-Hartman:
-  o add permission rule for jogdial device
-  o fix dumb bug I added to udevstart
-  o make a "last list" of devices for udevstart to operate on last
-  o fix permission problem with input event and ts nodes for gentoo
-  o change default perms of misc/rtc to be readable by anyone
-
-Olaf Hering:
-  o allow NAME_SIZE > SYSFS_PATH_MAX
-
-
-Summary of changes from v027 to v028
-============================================
-
-<atul.sabharwal:intel.com>:
-  o Patch for chassis_id exras module
-
-Daniel Drake:
-  o Writing udev rules doc update
-
-Greg Kroah-Hartman:
-  o clean up block whitelist search logic a bit
-  o reverse order of scanning of udevstart to look at class before block
-
-Kay Sievers:
-  o update udev_volume_id
-
-Leann Ogasawara:
-  o udevstart performance increase
-
-Patrick Mansfield:
-  o update udev scsi_id to scsi_id 0.5
-
-
-Summary of changes from v026 to v027
-============================================
-
-<fork0:users.sf.net>:
-  o fix handle leak in udev_lib.c
-
-Greg Kroah-Hartman:
-  o tweak the gentoo default permission rules as they are wrong for tty and misc devices
-
-
-Summary of changes from v025 to v026
-============================================
-
-Arnd Bergmann:
-  o udev rpm fix
-
-Greg Kroah-Hartman:
-  o add test for ! in partition name
-  o 025_bk mark
-  o Update to version 117 of klibc (from version 108)
-  o add volume_id ignore rule for bk
-  o add volume_id support to the udev.spec file
-  o remove dbus and selinux stuff from the udev.spec file
-  o delete udev_selinux as it doesn't work properly and is the wrong way to do it
-  o Deleted the udev_dbus extra as it didn't really work properly and HAL has a real solution now
-  o add udev.permissions.slackware file
-  o udevstart: close open directories
-
-Kay Sievers:
-  o fix udevd zombies
-  o catchup with recent klibc
-  o Re: udevsend fallback
-  o udev_volume_id update
-  o udev callout for reading filesystem labels
-  o udev callout for reading filesystem labels
-  o udev default config layout changes
-
-Leann Ogasawara:
-  o evaluate getenv() return value for udev_config.c
-
-Summary of changes from v024 to v025
-============================================
-
-<md:linux.it>:
-  o devfs.sh-ide-floppy
-
-<sjoerd:spring.luon.net>:
-  o DEVNODE -> DEVNAME transition fixes
-
-Daniel Drake:
-  o Update writing udev rules docs
-
-Greg Kroah-Hartman:
-  o make dev.d call each directory in the directory chain of the device name, instead of just the whole name
-  o add devd_test script
-  o add more permissions based on SuSE's recommendations
-  o added rules for tun and raw devices
-  o add udev conf.d file
-  o Switch the default config to point to a directory for the rules and permission files
-  o update the Red Hat .dev files to work on other distros
-  o add dbus.dev, pam_console.dev and selinux.dev files for /etc/dev.d/default/ usage
-  o add hints for red hat users from Leann Ogasawara <ogasawara@osdl.org>
-  o add scripts to run gcov for udev from Leann Ogasawara <ogasawara@osdl.org>
-  o change permissions on udevd test scripts
-  o Fix build process for users who have LC_ALL set to a non-english language
-  o Added expanded tests to the test framework from Leann Ogasawara <ogasawara@osdl.org>
-  o added execelent "writing udev rules" document from Daniel Drake <dan@reactivated.net>
-  o added rule to put USB printers in their proper places
-  o added rules for CAPI devices
-  o added a dev.d alsa script to help people out
-
-Kay Sievers:
-  o fix test regressions
-  o udev_selinux changes
-  o udevd test script
-  o udev_dbus changes
-  o fix devpath for netdev
-
-Leann Ogasawara:
-  o gcov for udev
-
-
-Summary of changes from v023 to v024
-============================================
-
-<atul.sabharwal:intel.com>:
-  o Add README for chassis_id
-  o Add chassis_id program to extras directory
-
-<chris_friesen:sympatico.ca>:
-  o udevd race conditions and performance,  assorted cleanups
-
-<hare:suse.de>:
-  o fix SEGV in libsysfs/dlist.c
-
-<maryedie:osdl.org>:
-  o add OSDL documentation for persistent naming
-
-<md:linux.it>:
-  o small ide-devfs.sh fix
-
-Greg Kroah-Hartman:
-  o remove compiler warning from udevd.c
-  o only generate udev.8 on the fly, not all other man pages
-  o update bk ignore list some more
-  o update bk ignore list
-  o switch to generate the man pages during the normal build, not during the install
-  o convert udev.8.in to use @udevdir@ macro for make install
-  o first step of making man pages dynamically generated
-  o add install and uninstall the etc/dev.d/net/hotplug.dev file to the Makefile
-  o tweak net_test a bit
-  o fix some segfaults when running udevtest for network devices
-  o make a net_test test script using udevtest
-  o handle the subsytem if provided in udevtest
-  o add hotplug.dev script to handle renamed network devices
-  o add a bunch of network class devices to the test sysfs tree
-  o add udevruler to the bk ignore list
-  o update RFC-dev.d docs due to DEVNODE to DEVNAME change
-  o clean up chassis_id coding style
-  o clean up the OSDL document formatting a bit
-  o add netlink rules to devfs and gentoo rules files
-  o added USB device rules to rules files
-  o clean up the gentoo rules file a bit more, adding dri rules
-  o fix up udev.rules to handle oss rules better
-  o 023_bk mark
-  o fix udev.spec file for where udevtest should be placed
-
-Kay Sievers:
-  o tweak node unlink handling
-  o switch udevd's msg_dump() to #define
-  o handle netdev in udevruler
-  o man page cleanup
-  o put config info in db for netdev
-  o increase udevd event timeout
-  o udevstart fix
-  o put netdev handling and dev.d/ in manpages
-  o DEVPATH for netdev
-  o netdev - udevdb+dev.d changes
-  o udevd race conditions and performance,  assorted cleanups - take 2
-  o udevinfo patch
-  o dev_d.c file sorting and cleanup
-  o apply all_partitions rule to main block device only
-
-
-Summary of changes from v022 to v023
-============================================
-
-Kay Sievers:
-  o hmm, handle net devices with udev?
-  o correct apply_format() for symlink only rules
-  o don't init namedev on remove
-  o first stupid try for a rule compose gui
-  o replace fgets() with mmap() and introduce udev_lib.[hc]
-  o make udevtest a real program :)
-
-Daniel E. F. Stekloff:
-  o udevinfo patch
-
-Greg Kroah-Hartman:
-  o create the /etc/dev.d/ directories in 'make install'
-  o actually have udev run files ending in .dev in the /etc/dev.d/ directory as documented
-  o added RFC-dev.d document detailing how /etc/dev.d/ works
-  o fixed up udev.spec to handle selinux stuff properly now
-  o remove USE_DBUS and USE_SELINUX flags from the README as they are no longer present
-  o remove selinux stuff from the main Makefile
-  o move udev_selinux into extras/selinux
-  o fix dbus build in the udev.spec file
-  o remove dbus stuff from main Makefile
-  o move udev_dbus to extras/dbus
-  o udev_dbus can now compile properly, but linnking is another story
-  o remove udev_dbus.h from Makefile
-  o first cut at standalone udev_selinux program
-  o remove selinux support from udev core as it's no longer needed
-  o first cut at standalone udev_dbus program
-  o add get_devnode() helper to udev_lib for udev_dbus program
-  o remove dbus code from core udev code as it's no longer needed to be there
-  o add /etc/dev.d/ support for udev add and remove events
-  o fix build error in namedev.c caused by previous patch
-  o 022_bk tag
-  o fix 'make spotless' to really do that in klibc
-  o add a question/answer about automounting usb devices to the FAQ
-  o mark scsi-devfs.sh as executable
-  o Increase the name size as requested by Richard Gooch <rgooch@ras.ucalgary.ca>
-  o fix udevtest to build properly after the big udev_lib change
-
-Olaf Hering:
-  o uninitialized variable for mknod and friend
-
-Richard Gooch:
-  o SCSI logical and physical names for udev
-
-Theodore Y. T'so:
-  o Trivial man page typo fixes to udev
-
-
-Summary of changes from v021 to v022
-============================================
-
-<ananth:in.ibm.com>:
-  o more Libsysfs updates
-  o Libsysfs updates
-
-<async:cc.gatech.edu>:
-  o fix HOWTO-udev_for_dev for udevdir
-
-Kay Sievers:
-  o udev-test.pl cleanup
-  o add dev node test to udev-test.pl
-  o add permission tests
-  o "symlink only" test
-  o callout part selector tweak
-  o cleanup callout fork
-  o allow to specify node permissions in the rule
-  o man page beauty
-  o put symlink only rules to the man page
-  o rename strn*() macros to strmax
-  o conditional remove of trailing sysfs whitespace
-  o clarify udevinfo text
-  o better fix for NAME="foo-%c{N}" gets a truncated name
-  o overall trivial trivial cleanup
-  o fix NAME="foo-%c{N}" gets a truncated name
-  o cleanup mult field string handling
-
-<ken:cgi101.com>:
-  o fix a type in docs/libsysfs.txt
-  o Added line to udev.permissions.redhat
-  o Include more examples in the docs area for gentoo and redhat
-
-<md:linux.it>:
-  o udevstart fixes
-
-Greg Kroah-Hartman:
-  o add big major tests to udev-test.pl
-  o add a test for a minor over 255
-  o udev-test.pl: print out major:minor and perm test "ok" if is ok
-  o make perm and major:minor test errors be reported properly
-  o remove extra ; in namedev_parse.c
-  o Added multipath-tools 0.1.1 release
-  o deleted current extras/multipath directory
-  o 021_bk mark
-  o fix the build for older versions of gcc
-
-Hanna V. Linder:
-  o Small fix to remove extra "will" in man page
-
-Olaf Hering:
-  o make spotless
-  o udev* segfaults with new klibc
-
-Patrick Mansfield:
-  o add tests for NAME="foo-%c{N}"
-
-Summary of changes from v020 to v021
-============================================
-
-Kay Sievers:
-  o install udevinfo in /usr/bin
-  o blacklist pcmcia_socket
-
-Greg Kroah-Hartman:
-  o fix udev.spec to find udevinfo now that it has moved to /usr/bin
-  o Fix another problem with Makefile installing initscript
-  o fix the Makefile to install the init script into the proper directory
-  o make spec file turn off selinux support by default
-
-
-Summary of changes from v019 to v020
-============================================
-
-<christophe.varoqui:free.fr>:
-  o multipath update
-
-Kay Sievers:
-  o man page udevstart
-  o cleanup udevstart
-  o bugfix for local user
-  o unlink bugfix
-  o TODO update
-  o clarify udevinfo device walk
-  o udevinfo symlink reverse query
-  o fix stroul endptr use
-  o add $local user spport for permissions
-  o udev - man page update
-  o udev - fix debug info for multiple rule file config
-  o udev - kill udevd on install
-  o udev - activate formt length attribute
-  o udev - safer sprintf() use
-
-<md:linux.it>:
-  o no error on enoent
-  o escape dashes in man pages
-  o remove usage of expr in ide-devfs.sh
-
-<rml:ximian.com>:
-  o automatically install correct initscript
-  o update documetation for $local
-
-Andrey Borzenkov:
-  o Add symlink only rules support
-
-Greg Kroah-Hartman:
-  o update the TODO list as we already have a devfs config file
-  o make start_udev use udevstart binary
-  o install udevstart
-  o Remove Debian permission files as the Debian maintainer doesn't seem to want to share :(
-  o update the Gentoo rules files
-  o Add Red Hat rules and permissions files
-  o add udevstart to the ignore list
-  o add udevstart program based on a old patch from Harald Hoyer <harald@redhat.com>
-  o unlink the file before we try to create it
-  o Merge greg@bucket:/home/greg/src/udev into kroah.com:/home/greg/src/udev
-
-
-Summary of changes from v018 to v019
-============================================
-
-Kay Sievers:
-  o TODO update
-  o udev - correct relative symlink
-  o udev - safer string handling - part four
-  o udev - safer string handling - part three
-  o udev - safer string handling - part two
-  o udev - man page update
-  o udev - safer string handling all over the place
-  o manpage update
-  o udev - allow all files in a directory as the config
-  o udev - simple klibc textual uid/gid handling
-
-Andrey Borzenkov:
-  o do not remove real .udev.tdb during RPM build
-
-Greg Kroah-Hartman:
-  o add new TODO item about local user permissions
-  o Add initial SELinux support for udev
-  o fix build for very old versions of make
-  o remove limit of the number of args passed to PROGRAM
-  o force udev to include the internal version of libsysfs and never the external one
-  o fix up libsysfs header file usage to fix bug reports from users that have sysfsutils installed already
-  o remove udevtest on 'make clean'
-  o remove udevd priority TODO item, as it's not needed at all
-
-Patrick Mansfield:
-  o update udev scsi_id to scsi_id 0.4
-
-
-Summary of changes from v017 to v018
-============================================
-
-<ext.devoteam.varoqui:sncf.fr>:
-  o [PATCH] symlink dm-[0-9]* rule
-  o update extras/multipath
-
-<john-hotplug:fjellstad.org>:
-  o init.d debian patch
-
-Kay Sievers:
-  o udev - TODO update
-  o udev - add %s{filename} to man page
-  o udev - udevd/udevsend man page
-  o udev - switch callout part selector to {attribute}
-  o udev - switch SYSFS_file to SYSFS{file}
-  o udev - create all partitions of blockdevice
-  o allow SYSFS{file}
-  o Adding '%s' format specifier to NAME and SYMLINK
-
-Greg Kroah-Hartman:
-  o added some scsi_id files to the bk ignore file
-  o added scsi_id and some more documentation to the udev.spec file
-  o update udev.rules.gentoo with new config file format
-  o Update the Gentoo udev.rules and udev.permissions files
-  o Create a udev.rules.examples file to hold odd udev.rules
-  o add udevd priority issue to the TODO list
-  o more HOWTO cleanups
-  o add HOWTO detailing how to use udev to manage /dev
-  o mv libsysfs/libsysfs.h to libsysfs/sysfs/libsysfs.h to make it easier to use
-  o add start_udev init script
-  o add support for UDEV_NO_SLEEP env variable so Gentoo people will be happy
-  o start up udevd ourselves in the init script to give it some good priorities
-  o update the red hat init script to handle nodes that are not present
-  o add a "old style" SYSFS_attribute test to udev-test.pl
-  o Have udevsend report more info in debug mode
-  o Have udevd report it's version in debug mode
-  o fix up bug created for udevtest in previous partition creation patch
-  o update the udev.spec to add udevtest and make some more Red Hat suggested changes
-  o add ability to install udevtest to Makefile
-  o 017_bk mark
-  o Add another test to udev-test.pl and fix a bug when only running 1 test
-  o Fix bug where we did not use the "converted" kernel name if we had no rule
-
-Patrick Mansfield:
-  o udev use new libsysfs header file location
-  o udev add some ID tests
-
-
-Summary of changes from v016 to v017
-============================================
-
-<azarah:nosferatu.za.org>:
-  o make logging a config option
-
-<christophe.varoqui:free.fr>:
-  o more udev-016/extras/multipath
-  o more udev-016/extras/multipath
-  o update extras/multipath
-
-Kay Sievers:
-  o udev - keep private data out of the database?
-  o better credential patch
-  o udevd - client access authorization
-  o compile udevd with klibc
-  o udev - fix "ignore method"
-  o udev - fix cdrom symlink rule
-  o convert udevsend/udevd to DGRAM and single-threaded
-  o udevd - kill the lockfile
-  o udevd - fix socket path length
-  o udevd - switch socket path to abstract namespace
-  o udevd - allow to bypass sequence number
-  o include used function
-
-Greg Kroah-Hartman:
-  o add udev_log to the documentation
-  o fix offsetof() define in klibc
-  o add some .spec file changes from Red Hat
-  o update the init.d udev script based on a patch from Red Hat
-  o remove the .udev.tdb when installing or uninstalling to be safe
-  o remove the database at startup
-  o fix bug in permission handling
-  o update klibc to version .107
-  o update the bitkeeper ignore file list
-  o add udevtest program to build
-  o fix problem where usb devices can be either the main device or the interface
-  o more logging.h cleanups to be a bit more flexible
-  o stop using mode_t as different libcs define it in different ways :(
-  o remove some more KLIBC fixups that are no longer needed
-  o let udev-test.pl run an individual test if you ask it to
-  o Handle the '!' character that some block devices have
-  o add a block device with a ! in the name, and a test for this
-  o fix up 'make release' to use bk to build the export tree
-  o fix log option code so that it actually works for all udev programs
-  o finish syncing up with klibc
-  o sync with latest version of klibc (0.107)
-  o fix up Makefile dependancies for udev_version.h
-
-Patrick Mansfield:
-  o udev add wild card compare for ID
-  o udev kill extra bus_id compares in match_id
-
-
-Summary of changes from v015 to v016
-============================================
-
-<elkropac:students.zcu.cz>:
-  o get_dev_number() in extras/ide-devfs.sh
-
-<rrm3:rrm3.org>:
-  o FAQ udev.rules.devfs
-
-Greg Kroah-Hartman:
-  o add udevd and udevsend to the spec file
-  o make /etc/hotplug.d/default/udev.hotplug symlink point to udevsend now
-  o add KERNEL_DIR option so that the distros will be happy
-  o make udevsend binary even smaller
-  o udevsend now almost compiles with klibc, struct sockaddr_un is only problem now
-  o fix up logging code so that it can be built without it being enabled
-  o rework the logging code so that each program logs with the proper name in the syslog
-  o remove logging.c as it's no longer needed
-  o kill the last examples that contained the %D option
-  o remove a __KLIBC__ tests in libsysfs, as klibc now supports getpagesize()
-  o udevd - remove stupid locking error I wrote
-  o update to klibc version 0.101, fixing the stdin bug
-  o fix Makefile typo for USE_LSB install
-  o allow dbus code to actually build again
-
-Kay Sievers:
-  o let udevsend build with klibc
-  o udevd - config cleanup
-  o udevd - cleanup and better timeout handling
-  o fix possible buffer overflow
-  o udevd - next round of fixes
-  o udevinfo - missing options for man page
-  o udev - trivial style cleanup
-
-
-Summary of changes from v014 to v015
-============================================
-
-<mbuesch:freenet.de>:
-  o LFS init script update
-
-Greg Kroah-Hartman:
-  o update klibc to version 0.98
-  o clean up udevinfo on 'make clean'
-  o add udevinfo man page to spec file
-  o remove command line documentation from udev man page
-  o create initial version of udevinfo man page
-  o added URL to spec file
-  o add udevinfo to udev.spec file
-  o add udevinfo to install target of Makefile
-  o rip out command line code from udev, now that we have udevinfo
-  o udevinfo doesn't need to declare main_envp
-  o move get_pair to udev_config.c because udevinfo doesn't need all of namedev.o
-  o more makefile cleanups
-  o move udevinfo into the main build and clean up the main Makefile a bit
-  o clean up compiler warnings if building using klibc
-  o make udevd only have one instance running at a time
-  o new testd.block script for debugging
-  o udevsnd : clean up message creation logic a bit
-  o make bk ignore udevd and udevsend binaries
-  o whitespace cleanups
-  o remove TODO item about BUS value, as it is now done
-  o add support for figuring out which device on the sysfs "chain" the rule applies to
-
-Kay Sievers:
-  o udevinfo - now a real program :)
-  o udevd - cleanup and better timeout handling
-  o udev - next round of udev event order daemon
-  o fix udevd exec
-  o udev - udevinfo with device chain walk
-  o spilt udev into pieces
-
-
-Summary of changes from v013 to v014
-============================================
-
-<ananthmg:rediffmail.com>:
-  o libsysfs update for refresh + namedev.c changes
-
-<christophe.varoqui:free.fr>:
-  o udev-013/extras/multipath update
-
-<flamingice:sourmilk.net>:
-  o minor patch for devfs rules
-
-Kay Sievers:
-  o udev - program to query all device attributes to build a rule
-  o set default owner/group in db - update
-  o udev - reverse user query options
-  o udev - kill %D from udev-test.pl
-  o add udev logging to info log
-  o udev - mention format string escape char in man page
-
-Greg Kroah-Hartman:
-  o misc code cleanups
-  o fixup logging.h to handle different logging options properly
-  o clean up the logging patch a bit to make the option more like the other options
-  o remove the %D modifier as it is not longer needed
-  o remove unneeded keyboard rule
-  o add usb_host and pci_bus to the class blacklist
-  o added input device rules to udev.rules and udev.rules.devfs
-  o 013_bk mark
-
-Hanna V. Linder:
-  o set default owner/group in db
-  o small cut n paste error fix
-
-Patrick Mansfield:
-  o update udev scsi_id to scsi_id 0.3
-
-
-Summary of changes from v012 to v013
-============================================
-
-<eike-hotplug:sf-tec.de>:
-  o LSB init script and other stuff
-
-<elkropac:students.zcu.cz>:
-  o fix udev directory for Debian init script
-
-<tiggi:infa.abo.fi>:
-  o udev 012 old gcc fixup
-
-Christophe Saout:
-  o add IGNORE rule type
-  o small cleanup
-
-Greg Kroah-Hartman:
-  o update TODO with some new, small items
-  o Cset exclude: greg@kroah.com|ChangeSet|20040113010256|48515
-  o update the README in a few places
-  o fix -d typo in the manpage update
-  o Fix stupid gcc "optimization" of 1 character printk() calls.... Ick
-  o oops, forgot to fix up the PROGRAM result from ID to RESULT in the config files
-  o Add alsa device rules and a few other devfs rules
-  o fix a few stale comments in namedev.c
-  o convert the default rules files to the new format
-  o convert the test shell scripts to the config file format
-  o add bus test for usb-serial bus
-  o Add some helpful messages if the user uses the older config file format
-  o added dri rule to the default config file
-  o added init.d udev script for debian
-  o add a script that tests the IGNORE rule
-  o add silly script that names cdrom drives based on the cd in them
-  o add cdrom rule for ide cdrom
-  o replace list_for_each with list_for_each_entry, saving a few lines of code
-  o add a blacklist of class devices we do not want to look at
-
-Kay Sievers:
-  o fix klibc with printf() and gcc
-  o udev - small script optimization
-  o udev - introduce format escape char
-  o udev - more CALLOUT is PROGRAM now
-  o udev - CALLOUT is PROGRAM now
-  o update documentation for new config file format
-  o more advanced user query options
-  o udev - simple debug tweak
-  o udev - drop all methods :)
-  o udev - advanced user query options
-  o udev - Makefile error
-  o udev - make exec_callout() reusable
-  o udev - exec status fix for klibc
-  o fix Silly udev script
-
-
-Summary of changes from v011 to v012
-============================================
-
-<azarah:nosferatu.za.org>:
-  o make symlink work properly if there is already a file in its place
-  o Fix udev gcc-2.95.4 compat
-
-<christophe.varoqui:free.fr>:
-  o extras multipath update
-  o extras multipath update
-
-Kay Sievers:
-  o mention user callable udev + options in man page
-  o make udev user callable to query the database
-  o depend on all .h files
-  o cleanup namedev_parse debug text
-  o extend exec_program[]
-  o ide-devfs.sh update
-  o fix for apply_format()
-  o check for empty symlink string
-  o 'ide' missing in bus_files[]
-  o small trivial cleanup of latest changes
-
-<mbuesch:freenet.de>:
-  o introduce signal handler
-
-<rml:ximian.com>:
-  o udev spec file update
-
-Greg Kroah-Hartman:
-  o minor grammer fixes for the udev_vs_devfs document
-  o move the dbus config file to etc/dbus-1/system.d/
-  o move the config files to etc/udev to clean up main directory a bit
-  o add Gentoo versions of the rules and permissions files
-  o if using glibc, link dynamically, as no one like 500Kb udev binaries
-  o minor change to udev_vs_devfs document
-  o added udev vs devfs supid document to the tree
-  o move the signal handling registration to after we have initialized enough stuff
-  o make ide-devfs.sh executable in the tree
-  o udev.permissions.debian - forgot the dm nodes
-  o update the udev.permissions.debian file with new entries
-  o added udev.init script for the Linux From Scratch project
-
-
-
-Summary of changes from v010 to v011
-============================================
-
-<mbuesch:freenet.de>:
-  o proper cleanup on udevdb_init() failure
-
-<mh:nadir.org>:
-  o patch udev 009-010 rpm spec file
-
-<svetljo:gmx.de>:
-  o fix udev sed Makefile usage
-
-Greg Kroah-Hartman:
-  o add documentation about the BUS key being optional for the LABEL rule
-  o add tests for LABEL rule with a device that has no bus
-  o Don't require the BUS value for the LABEL rule
-  o If a LABEL rule has a BUS id, then we must check to see if the device is on a bus
-  o add documentation about the BUS key being optional for the CALLOUT rule
-  o If a CALLOUT rule has a BUS id, then we must check to see if the device is on a bus
-  o Don't require the BUS value for the CALLOUT rule
-  o add test for callout rule with a device that has no bus
-  o 010_bk stamp
-  o added different build options to the rpm udev.spec file
-  o add pci to the bus_files list
-  o check for empty line a bit better in the parser
-  o more init script cleanups, the stop target now calls udev to cleanup instead of just removing the whole /udev directory
-  o make udev init script run udev in the background to let startup go much faster
-  o fix long delay for all devices in namedev
-
-
-Summary of changes from v009 to v010
-============================================
-
-<ananth:in.ibm.com>:
-  o change pgsize
-
-<christophe.varoqui:free.fr>:
-  o extras multipath update
-  o extras multipath update
-  o extras multipath update
-  o extras multipath update
-
-Kay Sievers:
-  o fix udev-test.pl
-  o small cleanup udev-remove.c
-  o experimental CALLOUT script for devfs ide node creation with cd, disc, part
-  o add any valid device
-  o introduce format char 'k' for kernel-name
-  o trivial make fixes
-  o don't overwrite old config on install
-  o udev-remove.c cleanups
-  o bug in udev-remove.c
-  o trivial cleanup parser changes
-
-<roman.kagan:itep.ru>:
-  o fix comment and whitespace handling in config files
-
-Adam Kropelin:
-  o Allow build with empty EXTRAS
-
-Daniel E. F. Stekloff:
-  o libsysfs 0.4.0 patch
-  o fix scsi_id segfault with udev-009
-  o add libsysfs docs
-
-David T. Hollis:
-  o mark config files as such in the rpm spec file
-
-Greg Kroah-Hartman:
-  o fix complier warning in namedev.c
-  o add documentation for the new '%k' modifier (kernel name replacement)
-  o add documentation about the multiple sysfs values that are now allowed for the LABEL rule
-  o add tests for multi-file LABEL rules
-  o add ability to have up to 5 SYSFS_ file/value pairs for the LABEL rule
-  o Just live with a sleep(1) in namedev for now until libsysfs is fixed up
-  o try to wait until the proper device file shows up in sysfs
-  o remove unneeded TODO and FIXME entry
-  o clean up the stand-alone tests to work properly on other people's machines
-  o add tests to catch whitespace and comment config file parsing errors
-
-
-Summary of changes from v008 to v009
-============================================
-
-<christophe.varoqui:free.fr>:
-  o more extras/multipath changes
-  o and more extras/multipath updates
-  o more extras/multipath updates
-  o yet more extras/multipath
-  o more extras/multipath updates
-  o extras/multipath update
-
-<david:fubar.dk>:
-  o D-BUS patch for udev-008
-
-<eike-hotplug:sf-tec.de>:
-  o add init.d/udev to "make install"
-  o add init.d/udev to the spec file
-
-Kay Sievers:
-  o don't rely on field order in namedev_parse
-  o get part of callout return string
-  o remove '\n' from end of callout return
-  o man-page mention multiple symlinks
-  o allow multiple symlinks
-  o cleanup man & remove symlink comment
-  o experimental (very simple) SYMLINK creation
-  o man page beauty
-  o pattern match for label method
-  o a bug in linefeed removal
-
-<rml:ximian.com>:
-  o remove udev from runlevels on uninstall
-  o install initscript in udev rpm
-
-Daniel E. F. Stekloff:
-  o pre-libsysfs-0.4.0 patch
-
-Greg Kroah-Hartman:
-  o signal fixes due to klibc update
-  o sync klibc with release 0.95
-  o add mol permissions to the debian permissions file
-  o update the FAQ with info about bad modprobe events from the devfs scheme
-  o some cleanups due to the need for LABEL rules to use "SYSFS_" now
-  o Add restart target to the etc/init.d/udev script
-  o tweak the config file generation portion of the Makefile a bit
-  o change devfs disk name rule from 'disk' to 'disc'
-  o add vc support to udev.rules.devfs
-  o added a devfs udev config file from Marco d'Itri <md@Linux.IT>
-  o set default mode to 0600 to be safer
-  o Makefile tweaks for the DBUS build
-  o update the FAQ due to the latest devfs mess on lkml and also due to symlinks now working
-  o document the different Makefile config options that we have
-  o change USE_DBUS to DBUS in Makefile, and disable it by default as it's still to hard to build on all systems
-  o fix formatting of udev_dbus.c to use tabs.  Also get it to build properly now
-  o move all of the DBUS logic into one file and remove all of the #ifdef crud from the main code
-
-Olaf Hering:
-  o dump latest klibc into the udev build tree
-  o use udevdir in udev.conf
-
-Patrick Mansfield:
-  o better allow builds of extras programs under udev
-  o update udev extras/scsi_id to version 0.2
-
-
-Summary of changes from v007 to v008
-============================================
-
-<azarah:nosferatu.za.org>:
-  o more config file parsing robustness
-
-<christophe.varoqui:free.fr>:
-  o udev-007/extras/multipath update
-
-Arnd Bergmann:
-  o Build failure - missing linux/limits.h include?
-  o Add format modifier for devfs like naming
-  o klibc makefile fixes
-
-Daniel E. F. Stekloff:
-  o another patch for path problem
-  o quick fix for libsysfs bus
-  o libsysfs changes for sysfsutils 0.3.0
-
-Greg Kroah-Hartman:
-  o fix up some duplicated function compiler warnings in libsysfs
-  o fix some compiler warnings in the tdb code
-  o Added Kay's name to the man page
-  o update the wildcard documentation in the man page to show the new styles supported
-  o fix permission handling logic
-  o enable default_mode ability to actually build
-  o add support for the default_mode variable, as it is documented
-  o show permissions and groups in the label_test
-  o remove some items off of the TODO list, as they are now done
-  o fix up the tests to work without all of the environ variables
-  o get rid of the majority of the debug environment variables
-  o Update the man page to show the new config file, it's format, and how to use it
-  o fix up the tests to support the rules file name change
-  o add support for a main udev config file, udev.conf
-  o turn debugging messages off by default
-  o split out the namedev config parsing logic to namedev_parse.c
-  o rename namedev's get_attr() to be main namedev_name_device() as that's what it really is
-  o add devfs like tty rules as an example in the default config file
-  o operate on the rules in the order they are in the config file (within the rule type) instead of operating on them backwards.
-  o Cset exclude: dsteklof@us.ibm.com|ChangeSet|20031126173159|56255
-  o add test for checking the BUS value
-  o fix problem where we were not looking at the BUS value
-  o add scsi and pci bus links in the test sysfs tree
-  o add test and documentation for new %D devfs format modifier
-  o changed the default location of the database to /udev/.udev.tdb to be LSB compliant
-  o get rid of functions in klibc_fixups that are now in klibc
-  o sync up with the 0.84 version of klibc
-  o fix udev init.d script to handle all class devices in sysfs
-  o fix the test.block and test.tty scripts due to their moveing.  Also add a test.all script
-  o 007_bk version change to Makefile
-
-Kay Sievers:
-  o pattern matching for namedev
-  o catch replace device by wildcard
-  o udev.8 tweak numeric id text
-  o udev-test.pl add subdir test
-  o namedev.c strcat tweak
-  o overall whitespace + debug text conditioning
-  o udev-test.pl - tweaks
-
-Martin Hicks:
-  o Add -nodefaultlibs while compiling against klibc
-
-Olaf Hering:
-  o ARCH detection for ppc
-
-Patrick Mansfield:
-  o fix udev parallel builds with klibc
-
-
-Summary of changes from v006 to v007
-============================================
-
-<md:linux.it>:
-  o fix segfault in parsing bad udev.permissions file
-
-Greg Kroah-Hartman:
-  o update default config file with a CALLOUT rule, and more documentation
-  o updated the man page with the latest format specifier changes
-  o added ability to put format specifiers in the CALLOUT program string
-  o tweak udev-test.pl to report '0' errors if that's what happened
-  o only build klibc_fixups.c if we are actually using klibc
-  o add support for string group and string user names in udev.permissions
-  o add getgrnam and getpwnam to klibc_fixups files
-  o remove Makefile.klibc
-  o add udev-test perl script from Kay Sievers <kay.sievers@vrfy.org> which blows away my puny shell scripts
-  o added debian's version of udev.permissions
-  o change to 006_bk version
-
-Kay Sievers:
-  o format char for CALLOUT output
-  o more namedev whitespace cleanups
-  o support arguments in callout exec
-  o namedev.c - change order of fields in CALLOUT
-  o namedev.c whitespace + debug text cleanup
-  o man page with udev.permissions wildcard
-
-Olaf Hering:
-  o static klibc udev does not link against crt0.o
-
-Summary of changes from v005 to v006
-============================================
-
-<chris_friesen:sympatico.ca>:
-  o faster test scripts
-
-Arnd Bergmann:
-  o more robust config file parsing in namedev.c
-  o add bus id modifier
-
-Daniel E. F. Stekloff:
-  o patch for libsysfs sysfs directory handling
-
-Greg Kroah-Hartman:
-  o add another line to udev.permissions in the proper format
-  o tweak replace_test
-  o fix permissions to work properly now
-  o add real udev.permissions file to test directory
-  o fix namedev.c to build with older version of gcc
-  o add dumb test for all of the different modifiers
-  o update the TODO list with more items that people can easily do
-  o move the test.block and test.tty scripts to the test/ directory
-  o add remove actions to the test scripts
-  o turn DEBUG_PARSER off by default
-  o add some documentation for the %b modifier to the default config file
-  o fix make install rule for when the udev symlink is already there
-  o change release target in makefile
-  o change debug level on printf values for now
-  o updated demo config file
-  o add some documentation of the modifiers to the default config file
-  o add demo config file
-  o updated bk ignore list for klibc generated files
-  o add printf option to label test to verify it works
-  o fix up printf-like functionality due to previous changes
-  o get the major/minor number before we name the device
-  o add scsi_id "extra" program from Patrick Mansfield <patmans@us.ibm.com>
-  o Add multipath "extra" program from Christophe Varoqui, <christophe.varoqui@free.fr>
-  o trailing whitespace cleanups
-  o splig LABEL and NUMBER into separate functions
-  o add TOPO regression test
-  o move TOPOLOGY rule to it's own function
-  o fix bug where NUMBER and TOPOLOGY would not work for partitions
-  o clean up the way we find the sysdevice for a block device for namedev
-  o updated label test script (tests for partitions now.)
-  o split REPLACE and CALLOUT into separate functions
-  o add debug line for REPLACE call
-  o add replace test
-  o add more sysfs test tree files
-  o change UDEV_SYSFS_PATH environment variable due to libsysfs change
-  o fix bug in klibc's isspace function
-  o fix udev-add.c to build properly with older versions of gcc
-  o add prototype for ftruncate to klibc
-  o Remove a few items from the TODO list that are already done
-  o version number to 005_bk
-  o pull some klibc stuff into the make Makefile to try to stay in sync
-  o klibc build fixes
-
-Kay Sievers:
-  o apply permissions.conf support for wildcard and default name
-  o man page with included placeholder list
-  o implement printf-like placeholder support for NAME
-  o more manpage tweaks
-  o add support for subdirs
-  o add uid/gid to nodes
-
-Olaf Hering:
-  o DESTDIR for udev
-
-Paul Mundt:
-  o Fixup path for kernel includes when building with klibc
-
-Robert Love:
-  o udev init script
-
-
-Summary of changes from v004 to v005
-============================================
-
-<kay:vrfy.org>:
-  o namedev.c comments + debug patch
-  o man page update
-
-Greg Kroah-Hartman:
-  o ignore the klibc/linux symlink
-  o add klibc linux symlink info to the README
-  o get 'make release' to work properly again
-  o added README info for how to build using klibc
-  o turn off debugging if we are building with klibc
-  o turn off debugging in namedev
-  o added vsyslog support to klibc
-  o add ftruncate to klibc
-  o klibc specific tweaks
-  o libsysfs does not need mntent.h in it's header file
-  o udev build tweaks to tdb's spinlock code
-  o klibc makefile changes
-  o build tdb and libsysfs from the same makefile as udev
-  o udev-add build cleanups for other libc versions
-  o tweak tdb to build within udev better
-  o make libsysfs spit debug messages to the same place as the rest of udev
-  o make libsysfs build cleanly
-  o updated bk ignore list
-  o added klibc version 0.82 (cvs tree) to the udev tree
-  o makefile fix for now
-  o Merge greg@bucket:/home/greg/src/udev into kroah.com:/home/greg/src/udev
-  o hm, makefile bug with so many files...  will fix later
-  o regression tests starting to be added
-  o fix LABEL bug for device files (not class files.)
-  o more warning flags to the build
-  o got rid of struct device_attr
-  o rename namedev.permissions and namedev.config to udev.permissions and udev.config
-  o fix dbg line in namedev.c
-  o more overrides of config info with env variables if in test mode
-  o Fix bug causing udev to sleep forever waiting for dev file to show up
-  o change version to 004_bk
-  o make config files, sysfs root, and udev root configurable from config variables
-
-Robert Love:
-  o udev: sleep_for_dev() bits
-  o udev: another canidate for static
-
-
-Summary of changes from v003 to v004
-============================================
-
-Daniel E. F. Stekloff:
-  o new version of libsysfs patch
-
-Greg Kroah-Hartman:
-  o 004 release
-  o major database cleanups
-  o Changed test.block and test.tty to take ACTION from the command line
-  o don't sleep if 'dev' file is already present on device add
-  o fix comment about how the "dev" file is made up
-  o more database work.  Now we only store the info we really need right now
-  o add BUS= bug to TODO list so it will not get forgotten
-  o spec file changes
-  o test.block changes
-  o ok, rpm likes the "_" character instead of "-" better
-  o change the version to 003-bk to keep things sane with people using the bk tree
-  o got "remove of named devices" working
-  o fix segfaults when dealing with partitions
-
-Kay Sievers:
-  o man file update
-  o man page update
-
-Robert Love:
-  o udev: mode should be mode_t
-  o udev: trivial trivialities
-  o udev: cool test scripts again
-  o udev spec file symlink support
-  o udev: cool test scripts
-  o udev spec file bits
-
-
-Summary of changes from v0.2 to v003
-============================================
-
-Daniel E. F. Stekloff:
-  o udevdb patch
-  o udevdb prototype
-
-Greg Kroah-Hartman:
-  o update the spec file for the new version and install process
-  o fix makefile release rule to not drop tdb.h file
-  o Add FAQ for udev
-  o removed AUTHORS and INSTALL files as they were pretty pointless
-  o copyright updates
-  o Add AUTHORS and INSTALL files
-  o TODO updates
-  o Updatd the README
-  o updated the TODO list
-  o add udev man page (basically just a place holder for now.)
-  o added uninstall support
-  o added install target for makefile so people don't have to do it by hand anymore
-  o add version to debug log on startup
-  o tell the user what mknod() we are trying to do
-  o add dbg_parse() to cut down on parse file debugging statements
-  o put config files and database in /etc/udev by default
-  o add ols 2003 udev paper to docs/
-  o clean up some debugging stuff in namedev.c
-  o do not build the tdb binary programs, only the objects
-  o merge tdb into the build process
-  o Added tdb code from latest cvs version in the samba tree
-  o added my name to the .spec file
-  o minor cleanups
-  o cleanup the mknod code a bit
-  o remove mknod callout
-  o handle new major:minor format of dev files that showed up in 2.6.0-test2-bk3 or so
-  o oops, everything was getting created as 000 mode, try to fix this up, but fail...
-  o more test stuff
-
-Olaf Hering:
-  o print udev pid
-
-Patrick Mansfield:
-  o add callout config type to udev
-
-Paul Mundt:
-  o Fix TDB cross compilation
-  o udev spec file
-  o udev/libsysfs cross compile fixes
-
-
-Summary of changes from v0.1 to v0.2
-============================================
-
-Greg Kroah-Hartman:
-  o more test stuff
-  o removed unneeded stuff from udev.h
-  o added 0.2 change log info
-  o start working on label support, and fix some segfaults for block devices
-  o test config file changes
-  o add NUMBER support (basically same logic as TOPOLOGY, perhaps we should
-    merge this...)
-  o added topology support
-  o got REPLACE to work properly
-  o make struct config_device contain a struct device_attr instead of
-    duplicating the mess
-  o block test
-  o split the tests up into different files
-  o split udev main logic into udev-add and udev-remove
-  o Clean up the namedev interface a bit, making the code smaller
-  o bk: update ignore list
-  o update the tests to handle block devices too
-  o add initial libsysfs support
-  o added libsysfs to the build
-  o added libsysfs code from sysutils-0.1.1-071803 release
-  o namedev config files are fully parsed
-  o more permission tests
-  o make log_message spit out warnings so I don't have to spend forever
-    chasing down stupid bugs that aren't there...
-  o added klibc makefile
-  o Initial namedev parsing of config files
-  o sleep for 2 seconds to give the kernel a chance to actually create the
-    files we need
-  o pick a better default UDEV_ROOT
-  o fix up the test to actually work
-  o added more documentation in README and TODO files
-
-
-Summary of changes up to v0.1
-============================================
-
-Greg Kroah-Hartman:
-  o added more documentation in README and TODO files
-  o updated the documentation
-  o cleaned up the makefile a bit
-  o remove now works!
-  o restructure code to be able to actually get remove_node() to work
-  o Creating nodes actually works
-  o added stupid test script for debugging
-  o added initial documentation and gpl license
-  o enabled debugging
-  o updated ignore list
-  o added initial files
-  o fixed up config
-  o Initial repository create
-  o BitKeeper file /home/greg/src/udev/udev/ChangeSet
-
diff --git a/src/udev/INSTALL b/src/udev/INSTALL
deleted file mode 100644 (file)
index 0a34e77..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-The options used usually look like:
-  %configure \
-    --prefix=/usr \
-    --sysconfdir=/etc \
-    --bindir=/usr/bin \
-    --libdir=/usr/lib64 \
-    --libexecdir=/usr/lib \
-    --with-systemdsystemunitdir=/usr/lib/systemd/system \
-    --with-selinux
-
-The options used in a RPM spec file look like:
-  %configure \
-    --prefix=%{_prefix} \
-    --sysconfdir=%{_sysconfdir} \
-    --bindir=%{_bindir} \
-    --libdir=%{_libdir} \
-    --libexecdir=%{_prefix}/lib \
-    --with-systemdsystemunitdir=%{_prefix}/lib/systemd/system \
-    --with-selinux
-
-The options to install udev in the rootfs instead of /usr,
-and udevadm in /sbin:
-    --prefix=%{_prefix} \
-    --with-rootprefix= \
-    --sysconfdir=%{_sysconfdir} \
-    --bindir=/sbin \
-    --libdir=%{_libdir} \
-    --with-rootlibdir=/lib64 \
-    --libexecdir=/lib \
-    --with-systemdsystemunitdir=/lib/systemd/system \
-    --with-selinux
-
-Some tools expect udevadm in 'sbin'. A symlink to udevadm in 'bin'
-needs to be manually created if needed.
-
-The defined location for scripts and binaries which are called
-from rules is (/usr)/lib/udev/ on all systems and architectures. Any
-other location will break other packages, who rightfully expect
-the (/usr)/lib/udev/ directory, to install their rule helper and udev
-rule files.
-
-Default udev rules and persistent device naming rules may be required
-by other software that depends on the data udev collects from the
-devices.
diff --git a/src/udev/Makefile.am b/src/udev/Makefile.am
deleted file mode 100644 (file)
index 1c7f86b..0000000
+++ /dev/null
@@ -1,712 +0,0 @@
-# Copyright (C) 2008-2012 Kay Sievers <kay.sievers@vrfy.org>
-# Copyright (C) 2009 Diego Elio 'Flameeyes' Pettenò <flameeyes@gmail.com>
-
-SUBDIRS = .
-
-ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
-
-AM_MAKEFLAGS = --no-print-directory
-
-LIBUDEV_CURRENT=13
-LIBUDEV_REVISION=2
-LIBUDEV_AGE=13
-
-LIBGUDEV_CURRENT=1
-LIBGUDEV_REVISION=1
-LIBGUDEV_AGE=1
-
-AM_CPPFLAGS = \
-       -include $(top_builddir)/config.h \
-       -I$(top_srcdir)/src \
-       -DSYSCONFDIR=\""$(sysconfdir)"\" \
-       -DPKGLIBEXECDIR=\""$(libexecdir)/udev"\"
-
-AM_CFLAGS = \
-       ${my_CFLAGS} \
-       -fvisibility=hidden \
-       -ffunction-sections \
-       -fdata-sections
-
-AM_LDFLAGS = \
-       -Wl,--gc-sections \
-       -Wl,--as-needed
-
-DISTCHECK_CONFIGURE_FLAGS = \
-       --enable-debug \
-       --enable-rule_generator \
-       --enable-floppy \
-       --with-selinux \
-       --enable-gtk-doc \
-       --with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
-
-BUILT_SOURCES =
-EXTRA_DIST =
-CLEANFILES =
-INSTALL_EXEC_HOOKS =
-INSTALL_DATA_HOOKS =
-UNINSTALL_EXEC_HOOKS =
-DISTCHECK_HOOKS =
-DISTCLEAN_LOCAL_HOOKS =
-
-udevhomedir = $(libexecdir)/udev
-udevhome_SCRIPTS =
-dist_udevhome_SCRIPTS =
-dist_udevhome_DATA =
-dist_man_MANS =
-
-SED_PROCESS = \
-       $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(SED) \
-       -e 's,@VERSION\@,$(VERSION),g' \
-       -e 's,@prefix\@,$(prefix),g' \
-       -e 's,@rootprefix\@,$(rootprefix),g' \
-       -e 's,@exec_prefix\@,$(exec_prefix),g' \
-       -e 's,@libdir\@,$(libdir),g' \
-       -e 's,@includedir\@,$(includedir),g' \
-       -e 's,@bindir\@,$(bindir),g' \
-       -e 's,@pkglibexecdir\@,$(libexecdir)/udev,g' \
-       < $< > $@ || rm $@
-
-%.pc: %.pc.in Makefile
-       $(SED_PROCESS)
-
-%.rules: %.rules.in Makefile
-       $(SED_PROCESS)
-
-%.service: %.service.in Makefile
-       $(SED_PROCESS)
-
-%.sh: %.sh.in Makefile
-       $(SED_PROCESS)
-       $(AM_V_GEN)chmod +x $@
-
-%.pl: %.pl.in Makefile
-       $(SED_PROCESS)
-       $(AM_V_GEN)chmod +x $@
-
-# ------------------------------------------------------------------------------
-SUBDIRS += src/docs
-
-include_HEADERS = src/libudev.h
-lib_LTLIBRARIES = libudev.la
-noinst_LTLIBRARIES = libudev-private.la
-
-libudev_la_SOURCES =\
-       src/libudev-private.h \
-       src/libudev.c \
-       src/libudev-list.c \
-       src/libudev-util.c \
-       src/libudev-device.c \
-       src/libudev-enumerate.c \
-       src/libudev-monitor.c \
-       src/libudev-queue.c
-
-libudev_la_LDFLAGS = \
-       $(AM_LDFLAGS) \
-       -version-info $(LIBUDEV_CURRENT):$(LIBUDEV_REVISION):$(LIBUDEV_AGE)
-
-libudev_private_la_SOURCES =\
-       $(libudev_la_SOURCES) \
-       src/libudev-util-private.c \
-       src/libudev-device-private.c \
-       src/libudev-queue-private.c
-
-if WITH_SELINUX
-libudev_private_la_SOURCES += src/libudev-selinux-private.c
-libudev_private_la_LIBADD = $(SELINUX_LIBS)
-endif
-
-pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = src/libudev.pc
-EXTRA_DIST += src/libudev.pc.in
-CLEANFILES += src/libudev.pc
-
-EXTRA_DIST += src/COPYING
-# move lib from $(libdir) to $(rootlib_execdir) and update devel link, if needed
-libudev-install-move-hook:
-       if test "$(libdir)" != "$(rootlib_execdir)"; then \
-               mkdir -p $(DESTDIR)$(rootlib_execdir) && \
-               so_img_name=$$(readlink $(DESTDIR)$(libdir)/libudev.so) && \
-               so_img_rel_target_prefix=$$(echo $(libdir) | sed 's,\(^/\|\)[^/][^/]*,..,g') && \
-               ln -sf $$so_img_rel_target_prefix$(rootlib_execdir)/$$so_img_name $(DESTDIR)$(libdir)/libudev.so && \
-               mv $(DESTDIR)$(libdir)/libudev.so.* $(DESTDIR)$(rootlib_execdir); \
-       fi
-
-libudev-uninstall-move-hook:
-       rm -f $(DESTDIR)$(rootlib_execdir)/libudev.so*
-
-INSTALL_EXEC_HOOKS += libudev-install-move-hook
-UNINSTALL_EXEC_HOOKS += libudev-uninstall-move-hook
-
-# ------------------------------------------------------------------------------
-udev-confdirs:
-       -mkdir -p $(DESTDIR)$(sysconfdir)/udev/rules.d
-       -mkdir -p $(DESTDIR)$(libexecdir)/udev/devices
-
-INSTALL_DATA_HOOKS += udev-confdirs
-
-udevrulesdir = $(libexecdir)/udev/rules.d
-dist_udevrules_DATA = \
-       rules/42-usb-hid-pm.rules \
-       rules/50-udev-default.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/75-net-description.rules \
-       rules/75-tty-description.rules \
-       rules/78-sound-card.rules \
-       rules/80-drivers.rules \
-       rules/95-udev-late.rules
-
-udevconfdir = $(sysconfdir)/udev
-dist_udevconf_DATA = src/udev.conf
-
-sharepkgconfigdir = $(datadir)/pkgconfig
-sharepkgconfig_DATA = src/udev.pc
-EXTRA_DIST += src/udev.pc.in
-CLEANFILES += src/udev.pc
-
-if WITH_SYSTEMD
-dist_systemdsystemunit_DATA = \
-       src/udev-control.socket \
-       src/udev-kernel.socket
-
-systemdsystemunit_DATA = \
-       src/udev.service \
-       src/udev-trigger.service \
-       src/udev-settle.service
-
-EXTRA_DIST += \
-       src/udev.service.in \
-       src/udev-trigger.service.in \
-       src/udev-settle.service.in
-
-CLEANFILES += \
-       src/udev.service \
-       src/udev-trigger.service \
-       src/udev-settle.service
-
-systemd-install-hook:
-       mkdir -p $(DESTDIR)$(systemdsystemunitdir)/sockets.target.wants
-       ln -sf ../udev-control.socket $(DESTDIR)$(systemdsystemunitdir)/sockets.target.wants/udev-control.socket
-       ln -sf ../udev-kernel.socket $(DESTDIR)$(systemdsystemunitdir)/sockets.target.wants/udev-kernel.socket
-       mkdir -p $(DESTDIR)$(systemdsystemunitdir)/basic.target.wants
-       ln -sf ../udev.service $(DESTDIR)$(systemdsystemunitdir)/basic.target.wants/udev.service
-       ln -sf ../udev-trigger.service $(DESTDIR)$(systemdsystemunitdir)/basic.target.wants/udev-trigger.service
-
-INSTALL_DATA_HOOKS += systemd-install-hook
-endif
-
-bin_PROGRAMS = \
-       udevadm
-
-pkglibexec_PROGRAMS = \
-       udevd
-
-udev_common_sources = \
-       src/udev.h \
-       src/udev-event.c \
-       src/udev-watch.c \
-       src/udev-node.c \
-       src/udev-rules.c \
-       src/udev-ctrl.c \
-       src/udev-builtin.c \
-       src/udev-builtin-blkid.c \
-       src/udev-builtin-firmware.c \
-       src/udev-builtin-hwdb.c \
-       src/udev-builtin-input_id.c \
-       src/udev-builtin-kmod.c \
-       src/udev-builtin-path_id.c \
-       src/udev-builtin-usb_id.c
-
-udev_common_CFLAGS = \
-       $(BLKID_CFLAGS) \
-       $(KMOD_CFLAGS)
-
-udev_common_LDADD = \
-       libudev-private.la \
-       $(BLKID_LIBS) \
-       $(KMOD_LIBS)
-
-udev_common_CPPFLAGS = \
-       $(AM_CPPFLAGS) \
-       -DFIRMWARE_PATH="$(FIRMWARE_PATH)" \
-       -DUSB_DATABASE=\"$(USB_DATABASE)\" -DPCI_DATABASE=\"$(PCI_DATABASE)\"
-
-udevd_SOURCES = \
-       $(udev_common_sources) \
-       src/udevd.c \
-       src/sd-daemon.h \
-       src/sd-daemon.c
-udevd_CFLAGS = $(udev_common_CFLAGS)
-udevd_LDADD = $(udev_common_LDADD)
-udevd_CPPFLAGS = $(udev_common_CPPFLAGS)
-
-udevadm_SOURCES = \
-       $(udev_common_sources) \
-       src/udevadm.c \
-       src/udevadm-info.c \
-       src/udevadm-control.c \
-       src/udevadm-monitor.c \
-       src/udevadm-settle.c \
-       src/udevadm-trigger.c \
-       src/udevadm-test.c \
-       src/udevadm-test-builtin.c
-udevadm_CFLAGS = $(udev_common_CFLAGS)
-udevadm_LDADD = $(udev_common_LDADD)
-udevadm_CPPFLAGS = $(udev_common_CPPFLAGS)
-
-# ------------------------------------------------------------------------------
-if ENABLE_MANPAGES
-dist_man_MANS += \
-       src/udev.7 \
-       src/udevadm.8 \
-       src/udevd.8
-endif
-
-EXTRA_DIST += \
-       src/udev.xml \
-       src/udevadm.xml \
-       src/udevd.xml
-
-if HAVE_XSLTPROC
-dist_noinst_DATA = \
-       src/udev.html \
-       src/udevadm.html \
-       src/udevd.html
-
-src/%.7 src/%.8 : src/%.xml
-       $(AM_V_GEN)$(XSLTPROC) -o $@ -nonet http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $<
-
-src/%.html : src/%.xml
-       $(AM_V_GEN)$(XSLTPROC) -o $@ -nonet http://docbook.sourceforge.net/release/xsl/current/xhtml-1_1/docbook.xsl $<
-endif
-
-# ------------------------------------------------------------------------------
-TESTS = \
-       test/udev-test.pl \
-       test/rules-test.sh
-
-check_PROGRAMS = \
-       test-libudev \
-       test-udev
-
-test_libudev_SOURCES = src/test-libudev.c
-test_libudev_LDADD = libudev.la
-
-test_udev_SOURCES = \
-       $(udev_common_sources) \
-       src/test-udev.c
-test_udev_CFLAGS = $(udev_common_CFLAGS)
-test_udev_LDADD = $(udev_common_LDADD)
-test_udev_CPPFLAGS = $(udev_common_CPPFLAGS)
-test_udev_DEPENDENCIES = test/sys
-
-# packed sysfs test tree
-test/sys:
-       $(AM_V_GEN)mkdir -p test && 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
-
-# ------------------------------------------------------------------------------
-ata_id_SOURCES = src/ata_id/ata_id.c
-ata_id_LDADD = libudev-private.la
-pkglibexec_PROGRAMS += ata_id
-
-# ------------------------------------------------------------------------------
-cdrom_id_SOURCES = src/cdrom_id/cdrom_id.c
-cdrom_id_LDADD = libudev-private.la
-pkglibexec_PROGRAMS += cdrom_id
-dist_udevrules_DATA += src/cdrom_id/60-cdrom_id.rules
-
-# ------------------------------------------------------------------------------
-collect_SOURCES = src/collect/collect.c
-collect_LDADD = libudev-private.la
-pkglibexec_PROGRAMS += collect
-
-# ------------------------------------------------------------------------------
-scsi_id_SOURCES =\
-       src/scsi_id/scsi_id.c \
-       src/scsi_id/scsi_serial.c \
-       src/scsi_id/scsi.h \
-       src/scsi_id/scsi_id.h
-scsi_id_LDADD = libudev-private.la
-pkglibexec_PROGRAMS += scsi_id
-dist_man_MANS += src/scsi_id/scsi_id.8
-EXTRA_DIST += src/scsi_id/README
-
-# ------------------------------------------------------------------------------
-v4l_id_SOURCES = src/v4l_id/v4l_id.c
-v4l_id_LDADD = libudev-private.la
-pkglibexec_PROGRAMS += v4l_id
-dist_udevrules_DATA += src/v4l_id/60-persistent-v4l.rules
-
-# ------------------------------------------------------------------------------
-accelerometer_SOURCES = src/accelerometer/accelerometer.c
-accelerometer_LDADD = libudev-private.la -lm
-pkglibexec_PROGRAMS += accelerometer
-dist_udevrules_DATA += src/accelerometer/61-accelerometer.rules
-
-# ------------------------------------------------------------------------------
-if ENABLE_GUDEV
-SUBDIRS += src/gudev/docs
-
-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
-
-pkgconfig_DATA += src/gudev/gudev-1.0.pc
-EXTRA_DIST += src/gudev/gudev-1.0.pc.in
-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 = \
-       -fvisibility=default \
-       $(GLIB_CFLAGS)
-
-libgudev_1_0_la_LIBADD = libudev.la $(GLIB_LIBS)
-
-libgudev_1_0_la_LDFLAGS = \
-       -version-info $(LIBGUDEV_CURRENT):$(LIBGUDEV_REVISION):$(LIBGUDEV_AGE) \
-       -export-dynamic -no-undefined \
-       -export-symbols-regex '^g_udev_.*'
-
-EXTRA_DIST += \
-       src/gudev/COPYING \
-       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
-
-src/gudev/gudevmarshal.h: src/gudev/gudevmarshal.list
-       $(AM_V_GEN)glib-genmarshal $< --prefix=g_udev_marshal --header > $@
-
-src/gudev/gudevmarshal.c: src/gudev/gudevmarshal.list
-       $(AM_V_GEN)echo "#include \"gudevmarshal.h\"" > $@ && \
-       glib-genmarshal $< --prefix=g_udev_marshal --body >> $@
-
-src/gudev/gudevenumtypes.h: src/gudev/gudevenumtypes.h.template src/gudev/gudevenums.h
-       $(AM_V_GEN)glib-mkenums --template $^ > \
-           $@.tmp && mv $@.tmp $@
-
-src/gudev/gudevenumtypes.c: src/gudev/gudevenumtypes.c.template src/gudev/gudevenums.h
-       $(AM_V_GEN)glib-mkenums --template $^ > \
-           $@.tmp && mv $@.tmp $@
-
-if ENABLE_INTROSPECTION
-src/gudev/GUdev-1.0.gir: libgudev-1.0.la $(G_IR_SCANNER)
-       $(AM_V_GEN)$(G_IR_SCANNER) -v \
-               --warn-all \
-               --namespace GUdev \
-               --nsversion=1.0 \
-               --include=GObject-2.0 \
-               --library=gudev-1.0 \
-               --library-path=$(top_builddir)/src \
-               --library-path=$(top_builddir)/src/gudev \
-               --output $@ \
-               --pkg=glib-2.0 \
-               --pkg=gobject-2.0 \
-               --pkg-export=gudev-1.0 \
-               --c-include=gudev/gudev.h \
-               -I$(top_srcdir)/src/\
-               -I$(top_builddir)/src/\
-               -D_GUDEV_COMPILATION \
-               -D_GUDEV_WORK_AROUND_DEV_T_BUG \
-               $(top_srcdir)/src/gudev/gudev.h \
-               $(top_srcdir)/src/gudev/gudevtypes.h \
-               $(top_srcdir)/src/gudev/gudevenums.h \
-               $(or $(wildcard $(top_builddir)/src/gudev/gudevenumtypes.h),$(top_srcdir)/src/gudev/gudevenumtypes.h) \
-               $(top_srcdir)/src/gudev/gudevclient.h \
-               $(top_srcdir)/src/gudev/gudevdevice.h \
-               $(top_srcdir)/src/gudev/gudevenumerator.h \
-               $(top_srcdir)/src/gudev/gudevclient.c \
-               $(top_srcdir)/src/gudev/gudevdevice.c \
-               $(top_srcdir)/src/gudev/gudevenumerator.c
-
-src/gudev/GUdev-1.0.typelib: src/gudev/GUdev-1.0.gir $(G_IR_COMPILER)
-       $(AM_V_GEN)g-ir-compiler $< -o $@
-
-girdir = $(GIRDIR)
-gir_DATA = src/gudev/GUdev-1.0.gir
-
-typelibsdir = $(GIRTYPELIBDIR)
-typelibs_DATA = src/gudev/GUdev-1.0.typelib
-
-CLEANFILES += $(gir_DATA) $(typelibs_DATA)
-endif # ENABLE_INTROSPECTION
-
-# move lib from $(libdir) to $(rootlib_execdir) and update devel link, if needed
-libgudev-install-move-hook:
-       if test "$(libdir)" != "$(rootlib_execdir)"; then \
-               mkdir -p $(DESTDIR)$(rootlib_execdir) && \
-               so_img_name=$$(readlink $(DESTDIR)$(libdir)/libgudev-1.0.so) && \
-               so_img_rel_target_prefix=$$(echo $(libdir) | sed 's,\(^/\|\)[^/][^/]*,..,g') && \
-               ln -sf $$so_img_rel_target_prefix$(rootlib_execdir)/$$so_img_name $(DESTDIR)$(libdir)/libgudev-1.0.so && \
-               mv $(DESTDIR)$(libdir)/libgudev-1.0.so.* $(DESTDIR)$(rootlib_execdir); \
-       fi
-
-libgudev-uninstall-move-hook:
-       rm -f $(DESTDIR)$(rootlib_execdir)/libgudev-1.0.so*
-
-INSTALL_EXEC_HOOKS += libgudev-install-move-hook
-UNINSTALL_EXEC_HOOKS += libgudev-uninstall-move-hook
-endif
-
-# ------------------------------------------------------------------------------
-if ENABLE_KEYMAP
-keymap_SOURCES = src/keymap/keymap.c
-keymap_CPPFLAGS = $(AM_CPPFLAGS) -I src/keymap
-nodist_keymap_SOURCES = \
-       src/keymap/keys-from-name.h \
-       src/keymap/keys-to-name.h
-BUILT_SOURCES += $(nodist_keymap_SOURCES)
-
-pkglibexec_PROGRAMS += keymap
-dist_doc_DATA = src/keymap/README.keymap.txt
-
-dist_udevrules_DATA += \
-       src/keymap/95-keymap.rules \
-       src/keymap/95-keyboard-force-release.rules
-
-dist_udevhome_SCRIPTS += src/keymap/findkeyboards
-udevhome_SCRIPTS += src/keymap/keyboard-force-release.sh
-
-EXTRA_DIST += \
-       src/keymap/check-keymaps.sh \
-       src/keymap/keyboard-force-release.sh.in
-
-CLEANFILES += \
-       src/keymap/keys.txt \
-       src/keymap/keys-from-name.gperf \
-       src/keymap/keyboard-force-release.sh
-
-udevkeymapdir = $(libexecdir)/udev/keymaps
-dist_udevkeymap_DATA = \
-       src/keymap/keymaps/acer \
-       src/keymap/keymaps/acer-aspire_5720 \
-       src/keymap/keymaps/acer-aspire_8930 \
-       src/keymap/keymaps/acer-aspire_5920g \
-       src/keymap/keymaps/acer-aspire_6920 \
-       src/keymap/keymaps/acer-travelmate_c300 \
-       src/keymap/keymaps/asus \
-       src/keymap/keymaps/compaq-e_evo \
-       src/keymap/keymaps/dell \
-       src/keymap/keymaps/dell-latitude-xt2 \
-       src/keymap/keymaps/everex-xt5000 \
-       src/keymap/keymaps/fujitsu-amilo_li_2732 \
-       src/keymap/keymaps/fujitsu-amilo_pa_2548 \
-       src/keymap/keymaps/fujitsu-amilo_pro_edition_v3505 \
-       src/keymap/keymaps/fujitsu-amilo_pro_v3205 \
-       src/keymap/keymaps/fujitsu-amilo_si_1520 \
-       src/keymap/keymaps/fujitsu-esprimo_mobile_v5 \
-       src/keymap/keymaps/fujitsu-esprimo_mobile_v6 \
-       src/keymap/keymaps/genius-slimstar-320 \
-       src/keymap/keymaps/hewlett-packard \
-       src/keymap/keymaps/hewlett-packard-2510p_2530p \
-       src/keymap/keymaps/hewlett-packard-compaq_elitebook \
-       src/keymap/keymaps/hewlett-packard-pavilion \
-       src/keymap/keymaps/hewlett-packard-presario-2100 \
-       src/keymap/keymaps/hewlett-packard-tablet \
-       src/keymap/keymaps/hewlett-packard-tx2 \
-       src/keymap/keymaps/ibm-thinkpad-usb-keyboard-trackpoint \
-       src/keymap/keymaps/inventec-symphony_6.0_7.0 \
-       src/keymap/keymaps/lenovo-3000 \
-       src/keymap/keymaps/lenovo-ideapad \
-       src/keymap/keymaps/lenovo-thinkpad-usb-keyboard-trackpoint \
-       src/keymap/keymaps/lenovo-thinkpad_x6_tablet \
-       src/keymap/keymaps/lenovo-thinkpad_x200_tablet \
-       src/keymap/keymaps/lg-x110 \
-       src/keymap/keymaps/logitech-wave \
-       src/keymap/keymaps/logitech-wave-cordless \
-       src/keymap/keymaps/logitech-wave-pro-cordless \
-       src/keymap/keymaps/maxdata-pro_7000 \
-       src/keymap/keymaps/medion-fid2060 \
-       src/keymap/keymaps/medionnb-a555 \
-       src/keymap/keymaps/micro-star \
-       src/keymap/keymaps/module-asus-w3j \
-       src/keymap/keymaps/module-ibm \
-       src/keymap/keymaps/module-lenovo \
-       src/keymap/keymaps/module-sony \
-       src/keymap/keymaps/module-sony-old \
-       src/keymap/keymaps/module-sony-vgn \
-       src/keymap/keymaps/olpc-xo \
-       src/keymap/keymaps/onkyo \
-       src/keymap/keymaps/oqo-model2 \
-       src/keymap/keymaps/samsung-other \
-       src/keymap/keymaps/samsung-90x3a \
-       src/keymap/keymaps/samsung-sq1us \
-       src/keymap/keymaps/samsung-sx20s \
-       src/keymap/keymaps/toshiba-satellite_a100 \
-       src/keymap/keymaps/toshiba-satellite_a110 \
-       src/keymap/keymaps/toshiba-satellite_m30x \
-       src/keymap/keymaps/zepto-znote
-
-udevkeymapforcereldir = $(libexecdir)/udev/keymaps/force-release
-dist_udevkeymapforcerel_DATA = \
-       src/keymap/force-release-maps/dell-touchpad \
-       src/keymap/force-release-maps/hp-other \
-       src/keymap/force-release-maps/samsung-other \
-       src/keymap/force-release-maps/samsung-90x3a \
-       src/keymap/force-release-maps/common-volume-keys
-
-src/keymap/keys.txt: $(INCLUDE_PREFIX)/linux/input.h
-       $(AM_V_at)mkdir -p src/keymap
-       $(AM_V_GEN)$(AWK) '/^#define.*KEY_[^ ]+[ \t]+[0-9]/ { if ($$2 != "KEY_MAX") { print $$2 } }' < $< | sed 's/^KEY_COFFEE$$/KEY_SCREENLOCK/' > $@
-
-src/keymap/keys-from-name.gperf: src/keymap/keys.txt
-       $(AM_V_GEN)$(AWK) 'BEGIN{ print "struct key { const char* name; unsigned short id; };"; print "%null-strings"; print "%%";} { print $$1 ", " $$1 }' < $< > $@
-
-src/keymap/keys-from-name.h: src/keymap/keys-from-name.gperf Makefile
-       $(AM_V_GEN)$(GPERF) -L ANSI-C -t --ignore-case -N lookup_key -H hash_key_name -p -C < $< > $@
-
-src/keymap/keys-to-name.h: src/keymap/keys.txt Makefile
-       $(AM_V_GEN)$(AWK) 'BEGIN{ print "const char* const key_names[KEY_CNT] = { "} { print "[" $$1 "] = \"" $$1 "\"," } END{print "};"}' < $< > $@
-
-keymaps-distcheck-hook: src/keymap/keys.txt
-       $(top_srcdir)/src/keymap/check-keymaps.sh $(top_srcdir) $^
-DISTCHECK_HOOKS += keymaps-distcheck-hook
-endif
-
-if ENABLE_MTD_PROBE
-# ------------------------------------------------------------------------------
-mtd_probe_SOURCES =  \
-       src/mtd_probe/mtd_probe.c \
-       src/mtd_probe/mtd_probe.h \
-       src/mtd_probe/probe_smartmedia.c
-mtd_probe_CPPFLAGS = $(AM_CPPFLAGS)
-dist_udevrules_DATA += src/mtd_probe/75-probe_mtd.rules
-pkglibexec_PROGRAMS += mtd_probe
-endif
-
-# ------------------------------------------------------------------------------
-if ENABLE_RULE_GENERATOR
-dist_udevhome_SCRIPTS += \
-       src/rule_generator/write_cd_rules \
-       src/rule_generator/write_net_rules
-
-dist_udevhome_DATA += \
-       src/rule_generator/rule_generator.functions
-
-dist_udevrules_DATA += \
-       src/rule_generator/75-cd-aliases-generator.rules \
-       src/rule_generator/75-persistent-net-generator.rules
-endif
-
-# ------------------------------------------------------------------------------
-if ENABLE_FLOPPY
-create_floppy_devices_SOURCES = src/floppy/create_floppy_devices.c
-create_floppy_devices_LDADD = libudev-private.la
-pkglibexec_PROGRAMS += create_floppy_devices
-dist_udevrules_DATA += src/floppy/60-floppy.rules
-endif
-
-# ------------------------------------------------------------------------------
-clean-local:
-       rm -rf udev-test-install
-
-distclean-local:
-       rm -rf autom4te.cache
-
-EXTRA_DIST += \
-       $(TESTS) \
-       test/rule-syntax-check.py
-
-CLEANFILES += \
-       $(BUILT_SOURCES)
-
-install-exec-hook: $(INSTALL_EXEC_HOOKS)
-
-install-data-hook: $(INSTALL_DATA_HOOKS)
-
-uninstall-hook: $(UNINSTALL_EXEC_HOOKS)
-
-distcheck-hook: $(DISTCHECK_HOOKS)
-
-distclean-local: $(DISTCLEAN_LOCAL_HOOKS)
-
-# ------------------------------------------------------------------------------
-PREVIOUS_VERSION = `expr $(VERSION) - 1`
-changelog:
-       @ head -1 ChangeLog | grep -q "to v$(PREVIOUS_VERSION)"
-       @ mv ChangeLog ChangeLog.tmp
-       @ echo "Summary of changes from v$(PREVIOUS_VERSION) to v$(VERSION)" >> ChangeLog
-       @ echo "============================================" >> ChangeLog
-       @ echo >> ChangeLog
-       @ git log --pretty=short $(PREVIOUS_VERSION)..HEAD | git shortlog  >> ChangeLog
-       @ echo >> ChangeLog
-       @ cat ChangeLog
-       @ cat ChangeLog.tmp >> ChangeLog
-       @ rm ChangeLog.tmp
-
-test-install:
-       rm -rf $(PWD)/udev-test-install/
-       make DESTDIR=$(PWD)/udev-test-install install
-       tree $(PWD)/udev-test-install/
-
-git-release:
-       head -1 ChangeLog | grep -q "to v$(VERSION)"
-       head -1 NEWS | grep -q "udev $(VERSION)"
-       git commit -a -m "release $(VERSION)"
-       git tag -m "udev $(VERSION)" -s $(VERSION)
-       git gc --prune=0
-
-git-sync:
-       git push
-       git push --tags
-
-tar-sync:
-       rm -f udev-$(VERSION).tar.sign
-       xz -d -c udev-$(VERSION).tar.xz | gpg --armor --detach-sign --output udev-$(VERSION).tar.sign
-       kup put udev-$(VERSION).tar.xz  udev-$(VERSION).tar.sign /pub/linux/utils/kernel/hotplug/
-
-doc-sync:
-       for i in src/*.html; do rm -f $$i.sign; gpg --armor --detach-sign --output=$$i.sign $$i; done
-       for i in src/*.html; do echo $$i; kup put $$i $$i.sign /pub/linux/utils/kernel/hotplug/udev/; done
-       for i in src/docs/html/*.{html,css,png}; do rm -f $$i.sign; gpg --armor --detach-sign --output=$$i.sign $$i; done
-       for i in src/docs/html/*.{html,css,png}; do echo $$i; kup put $$i $$i.sign /pub/linux/utils/kernel/hotplug/libudev/; done
-       for i in src/gudev/docs/html/*.{html,css,png}; do rm -f $$i.sign; gpg --armor --detach-sign --output=$$i.sign $$i; done
-       for i in src/gudev/docs/html/*.{html,css,png}; do echo $$i; kup put $$i $$i.sign /pub/linux/utils/kernel/hotplug/gudev/; done
diff --git a/src/udev/NEWS b/src/udev/NEWS
deleted file mode 100644 (file)
index f4f6f4e..0000000
+++ /dev/null
@@ -1,1735 +0,0 @@
-udev 182
-========
-Rules files in /etc/udev/rules.s/ with the same name as rules files in
-/run/udev/rules.d/ now always have precedence. The stack of files is now:
-/usr/lib (package), /run (runtime, auto-generated), /etc (admin), while
-the later ones override the earlier ones. In other words: the admin has
-always the last say.
-
-USB auto-suspend is now enabled by default for some built-in USB HID
-devices.
-
-/dev/disk/by-path/ links are no longer created for ATA devices behind
-an 'ATA transport class', the logic to extract predictable numbers does
-not exist in the kernel at this moment.
-
-/dev/disk/by-id/scsi-* compatibility links are no longer created for
-ATA devices, they have their own ata-* prefix.
-
-The s390 rule to set mode == 0666 for /dev/z90crypt is is removed from
-the udev tree and will be part of s390utils (or alternatively could be
-done by the kernel driver itself).
-
-The udev-acl tool is no longer provided, it will be part of a future
-ConsoleKit release. On systemd systems, advanced ConsoleKit and udev-acl
-functionality are provided by systemd.
-
-udev 181
-========
-Require kmod version 5.
-
-Provide /dev/cdrom symlink for /dev/sr0.
-
-udev 180
-========
-Fix for ID_PART_ENTRY_* property names, added by the blkid built-in. The
-fix is needed for udisk2 to operate properly.
-
-Fix for skipped rule execution when the kernel has removed the device
-node in /dev again, before the event was even started. The fix is needed
-to run device-mapper/LVM events properly.
-
-Fix for the man page installation, which was skipped when xsltproc was not
-installed.
-
-udev 179
-========
-Bugfix for $name resolution, which broke at least some keymap handling.
-
-udev 178
-========
-Bugfix for the firmware loading behavior with kernel modules which
-try to load firmware in the module_init() path. The blocked event
-runs into a timout now, which should allow the firmware to be loaded.
-
-Bugfix for a wrong DEVNAME= export, which breaks at least the udev-acl
-tool.
-
-Bugfix for missing ID_ properties for GPT partitions.
-
-The RUN+="socket:.." option is deprecated and should not be used. A warning
-during rules parsing is printed now. Services which listen to udev events,
-need to subscribe to the netlink messages with libudev and not let udev block
-in the rules execution until the message is delivered.
-
-udev 177
-========
-Bugfix for rule_generator instalation.
-
-udev 176
-========
-The 'devtmpfs' filesystem is required now, udev will not create or delete
-device nodes anymore, it only adjusts permissions and ownership of device
-nodes and maintains additional symlinks.
-
-A writable /run directory (ususally tmpfs) is required now for a fully
-functional udev, there is no longer a fallback to /dev/.udev.
-
-The default 'configure' install locations have changed. Packages for systems
-with the historic / vs. /usr split need to be adapted, otherwise udev will
-be installed in /usr and not work properly. Example configuration options
-to install things the traditional way are in INSTALL.
-
-The default install location of the 'udevadm' tool moved from 'sbin'
-to /usr/bin. Some tools expect udevadm in 'sbin', a symlink to udevadm
-needs to be manually created if needed, or --bindir=/sbin be specified.
-
-The expected value of '--libexecdir=' has changed and must no longer contain
-the 'udev' directory.
-
-Kernel modules are now loaded directly by linking udev to 'libkmod'. The
-'modprobe' tool is no longer executed by udev.
-
-The 'blkid' tool is no longer executed from udev rules. Udev links
-directly to libblkid now.
-
-Firmware is loaded natively by udev now, the external 'firmware' binary
-is no longer used.
-
-All built-in tools can be listed and tested with 'udevadm test-builtin'.
-
-The 'udevadm control --reload-rules' option has been renamed to '--reload'.
-It now also reloads the kernel module configuration.
-
-The systemd socket files use PassCredentials=yes, which is available in
-systemd version 38.
-
-The udev build system only creates a .xz tarball now.
-
-All tabs in the source code used for indentation are replaced by spaces now. :)
-
-udev 175
-========
-Bugfixes.
-
-udev 174
-========
-Bugfixes.
-
-The udev daemon moved to /lib/udev/udevd. Non-systemd init systems
-and non-dracut initramfs image generators need to change the init
-scripts. Alternatively the udev build needs to move udevd back to
-/sbin or create a symlink in /sbin, which is not done by default.
-
-The path_id, usb_id, input_id tools are built-in commands now and
-the stand-alone tools do not exist anymore. Static lists of file in
-initramfs generators need to be updated. For testing, the commands
-can still be executed standalone with 'udevadm test-builtin <cmd>'.
-
-The fusectl filesystem is no longer mounted directly from udev.
-Systemd systems will take care of mounting fusectl and configfs
-now. Non-systemd systems need to ship their own rule if they
-need these filesystems auto-mounted.
-
-The long deprecated keys: SYSFS=, ID=, BUS= have been removed.
-
-The support for 'udevadm trigger --type=failed, and the
-RUN{fail_event_on_error} attribute was removed.
-
-The udev control socket is now created in /run/udev/control
-and no longer as an abstract namespace one.
-
-The rules to create persistent network interface and cdrom link
-rules automatically in /etc/udev/rules.d/ have been disabled by
-default. Explicit configuration will be required for these use
-cases, udev will no longer try to write any persistent system
-configuration from a device hotplug path.
-
-udev 173
-========
-Bugfixes.
-
-The udev-acl extra is no longer enabled by default now. To enable it,
---enable-udev_acl needs to be given at ./configure time. On systemd
-systems, the udev-acl rules prevent it from running as the functionality
-has moved to systemd.
-
-udev 172
-========
-Bugfixes.
-
-Udev now enables kernel media-presence polling if available. Part
-of udisks optical drive tray-handling moved to cdrom_id: The tray
-is locked as soon as a media is detected to enable the receiving
-of media-eject-request events. Media-eject-request events will
-eject the media.
-
-Libudev enumerate is now able to enumerate a subtree of a given
-device.
-
-The mobile-action-modeswitch modeswitch tool was deleted. The
-functionality is provided by usb_modeswitch now.
-
-udev 171
-========
-Bugfixes.
-
-The systemd service files require systemd version 28. The systemd
-socket activation make it possible now to start 'udevd' and 'udevadm
-trigger' in parallel.
-
-udev 170
-========
-Fix bug in control message handling, which can lead to a failing
-udevadm control --exit. Thanks to Jürg Billeter for help tracking
-it down.
-
-udev 169
-========
-Bugfixes.
-
-We require at least Linux kernel 2.6.32 now. Some platforms might
-require a later kernel that supports accept4() and similar, or
-need to backport the trivial syscall wiring to the older kernels.
-
-The hid2hci tool moved to the bluez package and was removed.
-
-Many of the extras can be --enable/--disabled at ./configure
-time. The --disable-extras option was removed. Some extras have
-been disabled by default. The current options and their defaults
-can be checked with './configure --help'.
-
-udev 168
-========
-Bugfixes.
-
-Udev logs a warning now if /run is not writable at udevd
-startup. It will still fall back to /dev/.udev, but this is
-now considered a bug.
-
-The running udev daemon can now cleanly shut down with:
-  udevadm control --exit
-
-Udev in initramfs should clean the state of the udev database
-with: udevadm info --cleanup-db which will remove all state left
-behind from events/rules in initramfs. If initramfs uses
---cleanup-db and device-mapper/LVM, the rules in initramfs need
-to add OPTIONS+="db_persist" for all dm devices. This will
-prevent removal of the udev database for these devices.
-
-Spawned programs by PROGRAM/IMPORT/RUN now have a hard timeout of
-120 seconds per process. If that timeout is reached the spawned
-process will be killed. The event timeout can be overwritten with
-udev rules.
-
-If systemd is used, udev gets now activated by netlink data.
-Systemd will bind the netlink socket which will buffer all data.
-If needed, such setup allows a seemless update of the udev daemon,
-where no event can be lost during a udevd update/restart.
-Packages need to make sure to: systemctl stop udev.socket udev.service
-or 'mask' udev.service during the upgrade to prevent any unwanted
-auto-spawning of udevd.
-This version of udev conflicts with systemd version below 25. The
-unchanged service files will not wirk correctly.
-
-udev 167
-========
-Bugfixes.
-
-The udev runtime data moved from /dev/.udev/ to /run/udev/. The
-/run mountpoint is supposed to be a tmpfs mounted during early boot,
-available and writable to for all tools at any time during bootup,
-it replaces /var/run/, which should become a symlink some day.
-
-If /run does not exist, or is not writable, udev will fall back using
-/dev/.udev/.
-
-On systemd systems with initramfs and LVM used, packagers must
-make sure, that the systemd and initramfs versions match. The initramfs
-needs to create the /run mountpoint for udev to store the data, and
-mount this tmpfs to /run in the rootfs, so the that the udev database
-is preserved for the udev version started in the rootfs.
-
-The command 'udevadm info --convert-db' is gone. The udev daemon
-itself, at startup, converts any old database version if necessary.
-
-The systemd services files have been reorganized. The udev control
-socket is bound by systemd and passed to the started udev daemon.
-The udev-settle.service is no longer active by default. Services which
-can not handle hotplug setups properly need to actively pull it in, to
-act like a barrier. Alternatively the settle service can be unconditionally
-'systemctl'enabled, and act like a barrier for basic.target.
-
-The fstab_import callout is no longer built or installed. Udev
-should not be used to mount, does not watch changes to fstab, and
-should not mirror fstab values in the udev database.
-
-udev 166
-========
-Bugfixes.
-
-New and updated keymaps.
-
-udev 165
-========
-Bugfixes.
-
-The udev database has changed, After installation of a new udev
-version, 'udevadm info --convert-db' should be called, to let the new
-udev/libudev version read the already stored data.
-
-udevadm now supports quoting of property values, and prefixing of
-key names:
-  $ udevadm info --export --export-prefix=MY_ --query=property -n sda
-  MY_MAJOR='259'
-  MY_MINOR='0'
-  MY_DEVNAME='/dev/sda'
-  MY_DEVTYPE='disk'
-  ...
-
-libudev now supports:
-  udev_device_get_is_initialized()
-  udev_enumerate_add_match_is_initialized()
-to be able to skip devices the kernel has created , but udev has
-not already handled.
-
-libudev now supports:
-  udev_device_get_usec_since_initialized()
-to retrieve the "age" of a udev device record.
-
-GUdev supports a more generic GUdevEnumerator class, udev TAG
-handling, device initialization and timestamp now.
-
-The counterpart of /sys/dev/{char,block}/$major:$minor,
-/dev/{char,block}/$major:$minor symlinks are now unconditionally
-created, even when no rule files exist.
-
-New and updated keymaps.
-
-udev 164
-========
-Bugfixes.
-
-GUdev moved from /usr to /.
-
-udev 163
-========
-Bugfixes.
-
-udev 162
-========
-Bugfixes.
-
-Persistent network naming rules are disabled inside of Qemu/KVM now.
-
-New and updated keymaps.
-
-Udev gets unconditionally enabled on systemd installations now. There
-is no longer the need to to run 'systemctl enable udev.service'.
-
-udev 161
-========
-Bugfixes.
-
-udev 160
-========
-Bugfixes.
-
-udev 159
-========
-Bugfixes.
-
-New and fixed keymaps.
-
-Install systemd service files if applicable.
-
-udev 158
-========
-Bugfixes.
-
-All distribution specific rules are removed from the udev source tree,
-most of them are no longer needed. The Gentoo rules which allow to support
-older kernel versions, which are not covered by the default rules anymore
-has moved to rules/misc/30-kernel-compat.rules.
-
-udev 157
-========
-Bugfixes.
-
-The option --debug-trace and the environemnt variable UDEVD_MAX_CHILDS=
-was removed from udevd.
-
-Udevd now checks the kernel commandline for the following variables:
-  udev.log-priority=<syslog priority>
-  udev.children-max=<maximum number of workers>
-  udev.exec-delay=<seconds to delay the execution of RUN=>
-to help debuging coldplug setups where the loading of a kernel
-module crashes the system.
-
-The subdirectory in the source tree rules/packages has been renamed to
-rules/arch, anc contains only architecture specific rules now.
-
-udev 156
-========
-Bugfixes.
-
-udev 155
-========
-Bugfixes.
-
-Now the udev daemon itself, does on startup:
-  - copy the content of /lib/udev/devices to /dev
-  - create the standard symlinks like /dev/std{in,out,err},
-    /dev/core, /dev/fd, ...
-  - use static node information provided by kernel modules
-    and creates these nodes to allow module on-demand loading
-  - possibly apply permissions to all ststic nodes from udev
-    rules which are annotated to match a static node
-
-The default mode for a device node is 0600 now to match the kernel
-created devtmpfs defaults. If GROUP= is specified and no MODE= is
-given the default will be 0660.
-
-udev 154
-========
-Bugfixes.
-
-Udev now gradually starts to pass control over the primary device nodes
-and their names to the kernel, and will in the end only manage the
-permissions of the node, and possibly create additional symlinks.
-As a first step NAME="" will be ignored, and NAME= setings with names
-other than the kernel provided name will result in a logged warning.
-Kernels that don't provide device names, or devtmpfs is not used, will
-still work as they did before, but it is strongly recommended to use
-only the same names for the primary device node as the recent kernel
-provides for all devices.
-
-udev 153
-========
-Fix broken firmware loader search path.
-
-udev 152
-========
-Bugfixes.
-
-"udevadm trigger" defaults to "change" events now instead of "add"
-events. The "udev boot script" might need to add "--action=add" to
-the trigger command if not already there, in case the initial coldplug
-events are expected as "add" events.
-
-The option "all_partitons" was removed from udev. This should not be
-needed for usual hardware. Udev can not safely make assumptions
-about non-existing partition major/minor numbers, and therefore no
-longer provide this unreliable and unsafe option.
-
-The option "ignore_remove" was removed from udev. With devtmpfs
-udev passed control over device nodes to the kernel. This option
-should not be needed, or can not work as advertised. Neither
-udev nor the kernel will remove device nodes which are copied from
-the /lib/udev/devices/ directory.
-
-All "add|change" matches are replaced by "!remove" in the rules and
-in the udev logic. All types of events will update possible symlinks
-and permissions, only "remove" is handled special now.
-
-The modem modeswitch extra was removed and the external usb_modeswitch
-program should be used instead.
-
-New and fixed keymaps.
-
-udev 151
-========
-Bugfixes.
-
-udev 150
-========
-Bugfixes.
-
-Kernels with SYSFS_DEPRECATED=y are not supported since a while. Many users
-depend on the current sysfs layout and the information not available in the
-deprecated layout. All remaining support for the deprecated sysfs layout is
-removed now.
-
-udev 149
-========
-Fix for a possible endless loop in the new input_id program.
-
-udev 148
-========
-Bugfixes.
-
-The option "ignore_device" does no longer exist. There is no way to
-ignore an event, as libudev events can not be suppressed by rules.
-It only prevented RUN keys from being executed, which results in an
-inconsistent behavior in current setups.
-
-BUS=, SYSFS{}=, ID= are long deprecated and should be SUBSYSTEM(S)=,
-ATTR(S){}=, KERNEL(S)=. It will cause a warning once for every rule
-file from now on.
-
-The support for the deprecated IDE devices has been removed from the
-default set of rules. Distros who still care about non-libata drivers
-need to add the rules to the compat rules file.
-
-The ID_CLASS property on input devices has been replaced by the more accurate
-set of flags ID_INPUT_{KEYBOARD,KEY,MOUSE,TOUCHPAD,TABLET,JOYSTICK}. These are
-determined by the new "input_id" prober now. Some devices, such as touchpads,
-can have several classes. So if you previously had custom udev rules which e. g.
-checked for ENV{ID_CLASS}=="kbd", you need to replace this with
-ENV{ID_INPUT_KEYBOARD}=="?*".
-
-udev 147
-========
-Bugfixes.
-
-To support DEVPATH strings larger than the maximum file name length, the
-private udev database format has changed. If some software still reads the
-private files in /dev/.udev/, which it shouldn't, now it's time to fix it.
-Please do not port anything to the new format again, everything in /dev/.udev
-is and always was private to udev, and may and will change any time without
-prior notice.
-
-Multiple devices claiming the same names in /dev are limited to symlinks
-only now. Mixing identical symlink names and node names is not supported.
-This reduces the amount of data in the database significantly.
-
-NAME="%k" causes a warning now. It's is and always was completely superfluous.
-It will break kernel supplied DEVNAMEs and therefore it needs to be removed
-from all rules.
-
-Most NAME= instructions got removed. Kernel 2.6.31 supplies the needed names
-if they are not the default. To support older kernels, the NAME= rules need to
-be added to the compat rules file.
-
-Symlinks to udevadm with the old command names are no longer resolved to
-the udevadm commands.
-
-The udev-acl tool got adopted to changes in ConsoleKit. Version 0.4.1 is
-required now.
-
-The option "last_rule" does no longer exist. Its use breaks too many
-things which expect to be run from independent later rules, and is an idication
-that something needs to be fixed properly instead.
-
-The gudev API is no longer marked as experimental,
-G_UDEV_API_IS_SUBJECT_TO_CHANGE is no longer needed. The gudev introspection
-is enabled by default now. Various projects already depend on introspection
-information to bind dynamic languages to the gudev interfaces.
-
-udev 146
-========
-Bugfixes.
-
-The udevadm trigger "--retry-failed" option, which is replaced since quite
-a while by "--type=failed" is removed.
-
-The failed tracking was not working at all for a few releases. The RUN
-option "ignore_error" is replaced by a "fail_event_on_error" option, and the
-default is not to track any failing RUN executions.
-
-New keymaps, new modem, hid2hci updated.
-
-udev 145
-========
-Fix possible crash in udevd when worker processes are busy, rules are
-changed at the same time, and workers get killed to reload the rules.
-
-udev 144
-========
-Bugfixes.
-
-Properties set with ENV{.FOO}="bar" are marked private by starting the
-name with a '.'. They will not be stored in the database, and not be
-exported with the event.
-
-Firmware files are looked up in:
-  /lib/firmware/updates/$(uname -r)
-  /lib/firmware/updates
-  /lib/firmware/$(uname -r)
-  /lib/firmware"
-now.
-
-ATA devices switched the property from ID_BUS=scsi to ID_BUS=ata.
-ata_id, instead of scsi_id, is the default tool now for ATA devices.
-
-udev 143
-========
-Bugfixes.
-
-The configure options have changed because another library needs to be
-installed in a different location. Instead of exec_prefix and udev_prefix,
-libdir, rootlibdir and libexecdir are used. The Details are explained in
-the README file.
-
-Event processes now get re-used after they handled an event. This reduces
-the number of forks and the pressure on the CPU significantly, because
-cloned event processes no longer cause page faults in the main daemon.
-After the events have settled, a few worker processes stay around for
-future events, all others get cleaned up.
-
-To be able to use signalfd(), udev depends on kernel version 2.6.25 now.
-Also inotify support is mandatory now to run udev.
-
-The format of the queue exported by the udev damon has changed. There is
-no longer a /dev/.udev/queue/ directory. The current event queue can be
-accessed with udevadm settle and libudedv.
-
-Libudev does not have the unstable API header anymore. From now on,
-incompatible changes will be handled by bumping the library major version.
-
-To build udev from the git tree gtk-doc is needed now. The tarballs will
-build without it and contain the pre-built documentation. An online copy
-is available here:
-  http://www.kernel.org/pub/linux/utils/kernel/hotplug/libudev/
-
-The tools from the udev-extras repository have been merged into the main
-udev repository. Some of the extras have larger external dependencies, and
-they can be disabled with the configure switch --disable-extras.
-
-udev 142
-========
-Bugfixes.
-
-The program vol_id and the library libvolume_id are removed from the
-repository. Libvolume_id is merged with libblkid from the util-linux-ng
-package. Persistent disk links for label and uuid depend on the
-util-linux-ng version (2.15) of blkid now. Older versions of blkid
-can not be used with udev.
-
-Libudev allows to subscribe to udev events. To prevent unwanted messages
-to be delivered, and waking up the subscribing process, a filter can be
-installed, to drop messages inside a kernel socket filter. The filters
-match on the <subsytem>:<devtype> properties of the device.
-    This is part of the ongoing effort to replace HAL, and switch current
-users over to directly use libudev.
-    Libudev is still marked as experimental, and its interface might
-eventually change if needed, but no major changes of the currently exported
-interface are expected anymore, and a first stable release should happen
-soon.
-
-A too old kernel (2.6.21) or a kernel with CONFIG_SYSFS_DEPRECATED
-is not supported since while and udevd will log an error message at
-startup. It should still be able to boot-up, but advanced rules and system
-services which depend on the information not available in the old sysfs
-format will fail to work correctly.
-
-DVB device naming is supplied by the kernel now. In case older kernels
-need to be supported, the old shell script should be added to a compat
-rules file.
-
-udev 141
-========
-Bugfixes.
-
-The processed udev events get send back to the netlink socket. Libudev
-provides access to these events. This is work-in-progress, to replace
-the DeviceKit daemon functionality directly with libudev. There are
-upcoming kernel changes to allow non-root users to subcribe to these
-events.
-
-udev 140
-========
-Bugfixes.
-
-"udevadm settle" now optionally accepts a range of events to wait for,
-instead of waiting for "all" events.
-
-udev 139
-========
-Bugfixes.
-
-The installed watch for block device metadata changes is now removed
-during event hadling, because some (broken) tools may be called from udev
-rules and (wrongly) open the device with write access. After the finished
-event handling the watch is restored.
-
-udev 138
-========
-Bugfixes.
-
-Device nodes can be watched for changes with inotify with OPTIONS="watch".
-If closed after being opened for writing, a "change" uevent will occur.
-/dev/disk/by-{label,uuid}/* symlinks will be automatically updated.
-
-udev 137
-========
-Bugfixes.
-
-The udevadm test command has no longer a --force option, nodes and symlinks
-are always updated with a test run now.
-
-The udevd daemon can be started with --resolve-names=never to avoid all user
-and group lookups (e.g. in cut-down systems) or --resolve-names=late to
-lookup user and groups every time events are handled.
-
-udev 136
-========
-Bugfixes.
-
-We are currently merging the Ubuntu rules in the udev default rules,
-and get one step closer to provide a common Linux /dev setup, regarding
-device names, symlinks, and default device permissions. On udev startup,
-we now expect the following groups to be resolvable to their ids with
-glibc's getgrnam():
-  disk, cdrom, floppy, tape, audio, video, lp, tty, dialout, kmem.
-LDAP setups need to make sure, that these groups are always resolvable at
-bootup, with only the rootfs mounted, and without network access available.
-
-Some systems may need to add some new, currently not used groups, or need
-to add some users to new groups, but the cost of this change is minimal,
-compared to the pain the current, rather random, differences between the
-various distributions cause for upstream projects and third-party vendors.
-
-In general, "normal" users who log into a machine should never be a member
-of any such group, but the device-access should be managed by dynamic ACLs,
-which get added and removed for the specific users on login/logout and
-session activity/inactivity. These groups are only provided for custom setups,
-and mainly system services, to allow proper privilege separation.
-A video-streaming daemon uid would be a member of "audio" and "video", to get
-access to the sound and video devices, but no "normal" user should ever belong
-to the "audio" group, because he could listen to the built-in microphone with
-any ssh-session established from the other side of the world.
-
-/dev/serial/by-{id,path}/ now contains links for ttyUSB devices,
-which do not depend on the kernel device name. As usual, unique
-devices - only a single one per product connected, or a real
-USB serial number in the device - are always found with the same
-name in the by-id/ directory.
-Completely identical devices may overwrite their names in by-id/
-and can only be found reliably in the by-path/ directory. Devices
-specified by by-path/ must not change their connection, like the
-USB port number they are plugged in, to keep their name.
-
-To support some advanced features, Linux 2.6.22 is the oldest supported
-version now. The kernel config with enabled SYSFS_DEPRECATED is no longer
-supported. Older kernels should still work, and devices nodes should be
-reliably created, but some rules and libudev will not work correctly because
-the old kernels do not provide the expected information or interfaces.
-
-udev 135
-========
-Bugfixes.
-
-Fix for a possible segfault while swapping network interface names in udev
-versions 131-134.
-
-udev 134
-========
-Bugfixes.
-
-The group "video" is part of the default rules now.
-
-udev 133
-========
-Bugfix for kernels using SYSFS_DEPRECATED* option and finding parent
-block devices in some cases. No common distro uses this option anymore,
-and we do not get enough testing for this and recent udev versions. If
-this option is not needed to run some old distro with a new kernel,
-it should be disabled in the kernel config.
-
-Bugfix for the $links substitution variable, which may crash if no links
-are created. This should not happen in usual setups because we always
-create /dev/{block,char}/ links.
-
-The strings of the parsed rules, which are kept in memory, no longer
-contain duplicate entries, or duplicate tails of strings. This, and the
-new rules parsing/matching code reduces the total in-memory size of
-a huge distro rule sets to 0.08 MB, compared to the 1.2MB of udev
-version 130.
-
-The export of DEVTYPE=disk/partition got removed from the default
-rules. This value is available from the kernel. The pnp shell script
-modprobe hack is removed from the default rules. ACPI devices have _proper_
-modalias support and take care of the same functionality.
-Installations which support old kernels, but install current default
-udev rules may want to add that to the compat rules file.
-
-Libvolume_id now always probes for all known filesystems, and does not
-stop at the first match. Some filesystems are marked as "exclusive probe",
-and if any other filesytem type matches at the same time, libvolume_id
-will, by default, not return any probing result. This is intended to prevent
-mis-detection with conflicting left-over signatures found from earlier
-file system formats. That way, we no longer depend on the probe-order
-in case of multiple competing signatures. In some setups the kernel allows
-to mount a volume with just the old filesystem signature still in place.
-This may damage the new filesystem and cause data-loss, just by mounting
-it. Because volume_id can not decide which one the correct signature is,
-the wrong signatures need to be removed manually from the volume, or the
-volume needs to be reformatted, to enable filesystem detection and possible
-auto-mounting.
-
-udev 132
-========
-Fix segfault if compiled without optimization and dbg() does not get
-compiled out and uses variables which are not available.
-
-udev 131
-========
-Bugfixes. (And maybe new bugs. :))
-
-The rule matching engine got converted from a rule list to a token
-array which reduced the in-memory rules representation of a full
-featured distros with thousends of udev rules from 1.2MB to 0.12 MB.
-Limits like 5 ENV and ATTR matches, and one single instance for most
-other keys per rule are gone.
-
-The NAME assignment is no longer special cased. If later rules assign
-a NAME value again, the former value will be overwritten. As usual
-for most other keys, the NAME value can be protected by doing a final
-assignment with NAME:="<value>".
-
-All udev code now uses libudev, which is also exported. The library
-is still under development, marked as experimental, and its interface
-may change as long as the DeviceKit integration is not finished.
-
-Many thanks to Alan Jenkins for his continuous help, and finding and
-optimizing some of the computing expensive parts.
-
-udev 130
-========
-Bugfixes.
-
-Kernel devices and device nodes are connected now by reverse indizes in
-/sys and /dev. A device number retrieved by a stat() or similar, the
-kernel device directory can be found by looking up:
-  /sys/dev/{block,char}/<maj>:<min>
-and the device node of the same device by looking up:
-  /dev/{block,char}/<maj>:<min>
-
-udev 129
-========
-Fix recently introduced bug, which caused a compilation without large
-file support, where vol_id does not recognize raid signatures at the end
-of a volume.
-
-Firewire disks now create both, by-id/scsi-* and by-id/ieee-* links.
-Seems some kernel versions prevent the creation of the ieee-* links,
-so people used the scsi-* link which disappeared now.
-
-More libudev work. Almost all udevadm functionality comes from libudev
-now.
-
-udevadm trigger has a new option --type, which allows to trigger events
-for "devices", for "subsystems", or "failed" devices. The old option
---retry-failed" still works, but is no longer mentioned in the man page.
-
-udev 128
-========
-Bugfixes.
-
-The udevadm info --device-id-of-file= output has changed to use
-the obvious format. Possible current users should use the --export
-option which is not affected.
-
-The old udev commands symlinks to udevadm are not installed, if
-these symlinks are used, a warning is printed.
-
-udev 127
-========
-Bugfixes.
-
-Optical drive's media is no longer probed for raid signatures,
-reading the end of the device causes some devices to malfunction.
-Also the offset of the last session found is used now to probe
-for the filesystem.
-
-The volume_id library got a major version number update to 1,
-some deprecated functions are removed.
-
-A shared library "libudev" gets installed now to provide access
-to udev device information. DeviceKit, the successor of HAL, will
-need this library to access the udev database and search sysfs for
-devices.
-The library is currently in an experimental state, also the API is
-expected to change, as long as the DeviceKit integration is not
-finished.
-
-udev 126
-========
-We use ./configure now. See INSTALL for details. Current
-options are:
-    --prefix=
-        "/usr" - prefix for man pages, include files
-    --exec-prefix=
-        "" - the root filesystem, prefix for libs and binaries
-    --sysconfdir=
-        "/etc"
-    --with-libdir-name=
-        "lib" - directory name for libraries, not a path name
-        multilib 64bit systems may use "lib64" instead of "lib"
-    --enable-debug
-        compile-in verbose debug messages
-    --disable-logging
-        disable all logging and compile-out all log strings
-    --with-selinux
-        link against SELInux libraries, to set the expected context
-        for created files
-
-In the default rules, the group "disk" gets permissions 0660 instead
-of 0640. One small step closer to unify distro rules. Some day, all
-distros hopefully end up with the same set of rules.
-
-No symlinks to udevadm are installed anymore, if they are still needed,
-they should be provided by the package.
-
-udev 125
-========
-Bugfixes.
-
-Default udev rules, which are not supposed to be edited by the user, should
-be placed in /lib/udev/rules.d/ now, to make it clear that they are private to
-the udev package and will be replaced with an update. Udev will pick up rule
-files from:
-  /lib/udev/rules.d/  - default installed rules
-  /etc/udev/rules.d/  - user rules + on-the-fly generated rules
-  /dev/.udev/rules.d/ - temporary non-persistent rules created after bootup
-It does not matter in which directory a rule file lives, all files are sorted
-in lexical order.
-
-To help creating /dev/root, we have now:
-  $ udevadm info --export --export-prefix="ROOT_" --device-id-of-file=/
-  ROOT_MAJOR=8
-  ROOT_MINOR=5
-In case the current --device-id-of-file is already used, please switch to
-the --export format version, it saves the output parsing and the old
-format will be changed to use ':' as a separator, like the format in the
-sysfs 'dev' file.
-
-udev 124
-========
-Fix cdrom_id to properly recognize blank media.
-
-udev 123
-========
-Bugfixes.
-
-Tape drive id-data is queried from /dev/bsg/* instead of the tape
-nodes. This avoids rewinding tapes on open().
-
-udev 122
-========
-Bugfixes.
-
-The symlinks udevcontrol and udevtrigger are no longer installed by
-the Makefile.
-
-The scsi_id program does not depend on sysfs anymore. It can speak
-SGv4 now, so /dev/bsg/* device nodes can be used, to query SCSI device
-data, which should solve some old problems with tape devices, where
-we better do not open all tape device nodes to identify the device.
-
-udev 121
-========
-Many bugfixes.
-
-The cdrom_id program is replaced by an advanced version, which can
-detect most common device types, and also properties of the inserted
-media. This is part of moving some basic functionality from HAL into
-udev (and the kernel).
-
-udev 120
-========
-Bugfixes.
-
-The last WAIT_FOR_SYSFS rule is removed from the default rules.
-
-The symlinks to udevadm for the debugging tools: udevmonitor and
-udevtest are no longer created.
-
-The symlinks to the udevadm man page for the old tool names are
-no longer created.
-
-Abstract namespace sockets paths in RUN+="socket:@<path>" rules,
-should be prefixed with '@' to indicate that the path is not a
-real file.
-
-udev 119
-========
-Bugfixes.
-
-udev 118
-========
-Bugfixes.
-
-Udevstart is removed from the tree, it did not get installed for
-a long time now, and is long replaced by trigger and settle.
-
-udev 117
-========
-Bugfixes.
-
-All udev tools are merged into a single binary called udevadm.
-The old names of the tools are built-in commands in udevadm now.
-Symlinks to udevadm, with the names of the old tools, provide
-the same functionality as the standalone tools. There is also
-only a single udevadm.8 man page left for all tools.
-
-Tools like mkinitramfs should be checked, if they need to include
-udevadm in the list of files.
-
-udev 116
-========
-Bugfixes.
-
-udev 115
-========
-Bugfixes.
-
-The etc/udev/rules.d/ directory now contains a default set of basic
-udev rules. This initial version is the result of a rules file merge
-of Fedora and openSUSE. For these both distros only a few specific
-rules are left in their own file, named after the distro. Rules which
-are optionally installed, because they are only valid for a specific
-architecture, or rules for subsystems which are not always used are
-in etc/udev/packages/.
-
-udev 114
-========
-Bugfixes.
-
-Dynamic rules can be created in /dev/.udev/rules.d/ to trigger
-actions by dynamically created rules.
-
-SYMLINK=="<value>" matches agains the entries in the list of
-currently defined symlinks. The links are not created in the
-filesystem at that point in time, but the values can be matched.
-
-RUN{ignore_error}+="<program>" will ignore any exit code from the
-program and not record as a failed event.
-
-udev 113
-========
-Bugfixes.
-
-Final merge of patches/features from the Ubuntu package.
-
-udev 112
-========
-Bugfixes.
-
-Control characters in filesystem label strings are no longer silenty
-removed, but hex-encoded, to be able to uniquely identify the device
-by its symlink in /dev/disk/by-label/.
-If libvolume_id is used by mount(8), LABEL= will work as expected,
-if slashes or other characters are used in the label string.
-
-To test the existence of a file, TEST=="<file>" and TEST!="<file>"
-can be specified now. The TEST key accepts an optional mode mask
-TEST{0100}=="<is executable file>".
-
-Scsi_id now supports a mode without expecting scsi-specific sysfs
-entries to allow the extraction of cciss-device persistent properties.
-
-udev 111
-========
-Bugfixes.
-
-In the future, we may see uuid's which are just simple character
-strings (see the DDF Raid Specification). For that reason vol_id now
-exports ID_FS_UUID_SAFE, just like ID_FS_LABEL_SAFE. For things like
-the creation of symlinks, the *_SAFE values ensure, that no control
-or whitespace characters are used in the filename.
-
-Possible users of libvolume_id, please use the volume_id_get_* functions.
-The public struct will go away in a future release of the library.
-
-udev 110
-========
-Bugfixes.
-
-Removal of useless extras/eventrecorder.sh.
-
-udev 109
-========
-Bugfixes.
-
-udev 108
-========
-Bugfixes.
-
-The directory multiplexer for dev.d/ and hotplug.d are finally removed
-from the udev package.
-
-udev 107
-========
-Bugfixes.
-
-Symlinks can have priorities now, the priority is assigned to the device
-and specified with OPTIONS="link_priority=100". Devices with higher
-priorities overwrite the symlinks of devices with lower priorities.
-If the device that currently owns the link, goes away, the symlink
-will be removed, and recreated, pointing to the next device with the
-highest actual priority. This should make /dev/disk/by-{label,uuid,id}
-more reliable, if multiple devices contain the same metadata and overwrite
-these symlinks.
-
-The dasd_id program is removed from the udev tree, and dasdinfo, with the
-needed rules, are part of the s390-tools now.
-
-Please add KERNEL=="[0-9]*:[0-9]*" to the scsi wait-for-sysfs rule,
-we may get the scsi sysfs mess fixed some day, and this will only catch
-the devices we are looking for.
-
-USB serial numbers for storage devices have the target:lun now appended,
-to make it possibble to distinguish broken multi-lun devices with all
-the same SCSI identifiers.
-
-Note: The extra "run_directory" which searches and executes stuff in
-/etc/hotplug.d/ and /etc/dev.d/ is long deprecated, and will be removed
-with the next release. Make sure, that you don't use it anymore, or
-provides your own implementation of that inefficient stuff.
-We are tired of reports about a "slow udev", because these directories
-contain stuff, that runs with _every_ event, instead of using rules,
-that run programs only for the matching events.
-
-udev 106
-========
-Bugfixes.
-
-udev 105
-========
-Bugfixes.
-
-DRIVER== will match only for devices that actually have a real
-driver. DRIVERS== must be used, if parent devices should be
-included in the match.
-
-Libvolume_id's "linux_raid" detection needed another fix.
-
-udev 104
-========
-Bugfixes.
-
-udev 103
-========
-Add additional check to volume_id detection of via_raid, cause
-some company decided to put a matching pattern all over the empty
-storage area of their music players.
-
-udev 102
-========
-Fix path_id for SAS devices.
-
-udev 101
-========
-The udev daemon can be started with --debug-trace now, which will
-execute all events serialized to get a chance to catch a possible
-action that crashes the box.
-
-A warning is logged, if PHYSDEV* keys, the "device" link, or a parent
-device attribute like $attr{../file} is used, only WAIT_FOR_SYSFS rules
-are excluded from the warning. Referencing parent attributes directly
-may break when something in the kernel driver model changes. Udev will
-just find the attribute by walking up the parent chain.
-
-Udevtrigger now sorts the list of devices depending on the device
-dependency, so a "usb" device is triggered after the parent "pci"
-device.
-
-udev 100
-========
-Revert persistent-storage ata-serial '_' '-' replacement.
-
-udev 099
-========
-Bugfixes.
-
-Udevtrigger can now filter the list of devices to be triggered. Matches
-for subsystems or sysfs attributes can be specified.
-
-The entries in /dev/.udev/queue and /dev/.udev/failed have changed to
-zero-sized files to avoid pointing to /sys and confuse broken tools which
-scan the /dev directory. To retry failed events, udevtrigger --retry-failed
-should be used now.
-
-The rules and scripts to create udev rules for persistent network
-devices and optical drives are in the extras/rules_generator directory
-now. If you use something similar, please consider replacing your own
-version with this, to share the support effort. The rule_generator
-installs its own rules into /etc/udev/rules.d.
-
-The cdrom_id tool installs its own rule now in /etc/udev/rules.d, cause
-the rule_generator depends on cdrom_id to be called in an earlier rule.
-
-udev 098
-========
-Bugfixes.
-
-Renaming of some key names (the old names still work):
-BUS -> SUBSYSTEMS, ID -> KERNELS, SYSFS -> ATTRS, DRIVER -> DRIVERS.
-(The behavior of the key DRIVER will change soon in one of the next
-releases, to match only the event device, please switch to DRIVERS
-instead. If DRIVER is used, it will behave like DRIVERS, but an error
-is logged.
-With the new key names, we have a more consistent and simpler scheme.
-We can match the properties of the event device only, with: KERNEL,
-SUBSYSTEM, ATTR, DRIVER. Or include all the parent devices in the match,
-with: KERNELS, SUBSYSTEMS, ATTRS, DRIVERS. ID, BUS, SYSFS, DRIVER are no
-longer mentioned in the man page and should be switched in the rule
-files.
-
-ATTR{file}="value" can be used now, to write to a sysfs file of the
-event device. Instead of:
-  ..., SYSFS{type}=="0|7|14", RUN+="/bin/sh -c 'echo 60 > /sys$$DEVPATH/timeout'"
-we now can do:
-  ..., ATTR{type}=="0|7|14", ATTR{timeout}="60"
-
-All the PHYSDEV* keys are deprecated and will be removed from a
-future kernel:
-  PHYDEVPATH -    is the path of a parent device and should not be
-                  needed at all.
-  PHYSDEVBUS -    is just a SUBSYSTEM value of a parent, and can be
-                  matched with SUBSYSTEMS==
-  PHYSDEVDRIVER - for bus devices it is available as ENV{DRIVER}.
-                  Newer kernels will have DRIVER in the environment,
-                  for older kernels udev puts in. Class device will
-                  no longer carry this property of a parent and
-                  DRIVERS== can be used to match such a parent value.
-Note that ENV{DRIVER} is only available for a few bus devices, where
-the driver is already bound at device event time. On coldplug, the
-events for a lot devices are already bound to a driver, and they will have
-that value set. But on hotplug, at the time the kernel creates the device,
-it can't know what driver may claim the device after that, therefore
-in most cases it will be empty.
-
-Failed events should now be re-triggered with:
-   udevtrigger --retry-failed.
-Please switch to this command, so we keep the details of the /dev/.udev/failed/
-files private to the udev tools. We may need to switch the current symlink
-target, cause some obviously broken tools try to scan all files in /dev
-including /dev/.udev/, find the links to /sys and end up stat()'ing sysfs files
-million times. This takes ages on slow boxes.
-
-The udevinfo attribute walk (-a) now works with giving a device node
-name (-n) instead of a devpath (-p). The query now always works, also when
-no database file was created by udev.
-
-The built-in /etc/passwd /etc/group parser is removed, we always depend on
-getpwnam() and getgrnam() now. One of the next releases will depend on
-fnmatch() and may use getopt_long().
-
-udev 097
-========
-Bugfixes and small improvements.
-
-udev 096
-========
-Fix path_id for recent kernels.
-
-udev 095
-========
-%e is finally gone.
-
-Added support for swapping network interface names, by temporarily
-renaming the device and wait for the target name to become free.
-
-udev 094
-========
-The built-in MODALIAS key and substitution is removed.
-
-udev 093
-========
-The binary firmware helper is replaced by the usual simple
-shell script. Udevsend is removed from the tree.
-
-udev 092
-========
-Bugfix release.
-
-udev 091
-========
-Some more keys require the correct use of '==' and '=' depending
-on the kind of operation beeing an assignment or a match. Rules
-with invalid operations are skipped and logged to syslog. Please
-test with udevtest if the parsing of your rules throws errors and
-fix possibly broken rules.
-
-udev 090
-========
-Provide "udevsettle" to wait for all current udev events to finish.
-It also watches the current kernel netlink queue by comparing the
-even sequence number to make sure that there are no current pending
-events that have not already arrived in the daemon.
-
-udev 089
-========
-Fix rule to skip persistent rules for removable IDE devices, which
-also skipped optical IDE drives.
-
-All *_id program are installed in /lib/udev/ by default now.
-
-No binary is stripped anymore as this should be done in the
-packaging process and not at build time.
-
-libvolume_id is provided as a shared library now and vol_id is
-linked against it. Also one of the next HAL versions will require
-this library, and the HAL build process will also require the
-header file to be installed. The copy of the same code in HAL will
-be removed to have only a single copy left on the system.
-
-udev 088
-========
-Add persistent links for SCSI tapes. The rules file is renamed
-to 60-persistent-storage.rules.
-
-Create persistent path for usb devices. Can be used for all sorts
-of devices that can't be distinguished by other properties like
-multiple identical keyboards and mice connected to the same box.
-
-Provide "udevtrigger" program to request events on coldplug. The
-shell script is much too slow with thousends of devices.
-
-udev 087
-========
-Fix persistent disk rules to exclude removable IDE drives.
-
-Warn if %e, $modalias or MODALIAS is used.
-
-udev 086
-========
-Fix queue export, which wasn't correct for subsequent add/remove
-events for the same device.
-
-udev 085
-========
-Fix cramfs detection on big endian.
-
-Make WAIT_FOR_SYSFS usable in "normal" rules and silent if the whole
-device goes away.
-
-udev 084
-========
-If BUS== and SYSFS{}== have been used in the same rule, the sysfs
-attributes were only checked at the parent device that matched the
-by BUS requested subsystem. Fix it to also look at the device we
-received the event for.
-
-Build variable CROSS has changed to CROSS_COMPILE to match the kernel
-build name.
-
-udev 083
-========
-Fix a bug where NAME="" would prevent RUN from beeing executed.
-
-RUN="/bin/program" does not longer automatically add the subsystem
-as the first parameter. This is from the days of /sbin/hotplug
-which is dead now and it's just confusing to need to add a space at
-the end of the program name to prevent this.
-If you use rules that need the subsystem as the first parameter,
-like the old "udev_run_hotlugd" and "udev_run_devd", add the subsystem
-to the key like RUN+="/bin/program $env{SUBSYSTEM}".
-
-udev 082
-========
-The udev man page has moved to udev(7) as it does not describe a command
-anymore. The programs udev, udevstart and udevsend are no longer installed
-by default and must be copied manually, if they should be installed or
-included in a package.
-
-Fix a bug where "ignore_device" could run earlier collected RUN keys before
-the ignore rule was applied.
-
-More preparation for future sysfs changes. usb_id and scsi_id no longer
-depend on a magic order of devices in the /devices chain. Specific devices
-should be requested by their subsytem.
-
-This will always find the scsi parent device without depending on a specific
-path position:
-  dev = sysfs_device_get(devpath);
-  dev_usb = sysfs_device_get_parent_with_subsystem(dev, "scsi");
-
-The "device" link in the current sysfs layout will be automatically
-_resolved_ as a parent and in the new sysfs layout it will just _be_ the
-parent in the devpath. If a device is requested by it's symlink, like all
-class devices in the new sysfs layout will look like, it gets automatically
-resolved and substituted with the real devpath and not the symlink path.
-
-Note:
-A similar logic must be applied to _all_ sysfs users, including
-scripts, that search along parent devices in sysfs. The explicit use of
-the "device" link must be avoided. With the future sysfs layout all
-DEVPATH's will start with /devices/ and have a "subsystem" symlink poiting
-back to the "class" or the "bus". The layout of the parent devices in
-/devices is not necessarily expected to be stable across kernel releases and
-searching for parents by their subsystem should make sysfs users tolerant
-for changed parent chains.
-
-udev 081
-========
-Prepare udev to work with the experimental kernel patch, that moves
-/sys/class devices to /sys/devices and /sys/block to /sys/class/block.
-
-Clarify BUS, ID, $id usage and fix $id behavior. This prepares for
-moving the class devices to /sys/devices.
-
-Thanks again to Marco for help finding a hopefully nice compromise
-to make %b simpler and working again.
-
-udev 080
-========
-Complete removal of libsysfs, replaced by simple helper functions
-which are much simpler and a bit faster. The udev daemon operatesentirely
-on event parameters and does not use sysfs for simple rules anymore.
-Please report any new bugs/problems, that may be caused by this big
-change. They will be fixed immediately.
-
-The enumeration format character '%e' is deprecated and will be
-removed sometimes from a future udev version. It never worked correctly
-outside of udevstart, so we can't use it with the new parallel
-coldplug. A simple enumeration is as useless as the devfs naming
-scheme, just get rid of both if you still use it.
-
-MODALIAS and $modalias is not needed and will be removed from one of
-the next udev versions, replace it in all rules with ENV{MODALIAS} or
-the sysfs "modalias" value.
-
-Thanks a lot to Marco for all his help on finding and fixing bugs.
-
-udev 079
-========
-Let scsi_id request libata drive serial numbers from page 0x80.
-
-Renamed etc/udev/persistent.rules to persistent-disk.rules and
-added /dev/disk/by-name/* for device mapper device names.
-
-Removed %e from the man page. It never worked reliably outside
-of udevstart and udevstart is no longer recommended to use.
-
-udev 078
-========
-Symlinks are now exported to the event environment. Hopefully it's no
-longer needed to run udevinfo from an event process, like it was
-mentioned on the hotplug list:
-  UDEV  [1134776873.702967] add@/block/sdb
-  ...
-  DEVNAME=/dev/sdb
-  DEVLINKS=/dev/disk/by-id/usb-IBM_Memory_Key_0218B301030027E8 /dev/disk/by-path/usb-0218B301030027E8:0:0:0
-
-udev 077
-========
-Fix a problem if udevsend is used as the hotplug handler and tries to use
-syslog, which causes a "vc" event loop. 2.6.15 will make udevsend obsolete
-and this kind of problems will hopefully go away soon.
-
-udev 076
-========
-All built-in logic to work around bad sysfs timing is removed with this
-version. The need to wait for sysfs files is almost fixed with a kernel
-version that doesn't work with this udev version anyway. Until we fix
-the timing of the "bus" link creation, the former integrated logic should
-be emulated by a rule placed before all other rules:
-  ACTION=="add", DEVPATH=="/devices/*", ENV{PHYSDEVBUS}=="?*", WAIT_FOR_SYSFS="bus"
-
-The option "udev_db" does no longer exist. All udev state will be in
-/$udev_root/.udev/ now, there is no longer an option to set this
-to anything else.
-If the init script or something else used this value, just depend on
-this hardcoded path. But remember _all_content_ of this directory is
-still private to udev and can change at any time.
-
-Default location for rule sripts and helper programs is now: /lib/udev/.
-Everything that is not useful on the commandline should go into this
-directory. Some of the helpers in the extras folder are installed there
-now. The rules need to be changed, to find the helpers there.
-
-Also /lib/udev/devices is recommended as a directory where packages or
-the user can place real device nodes, which get copied over to /dev at
-every boot. This should replace the various solutions with custom config
-files.
-
-Udevsend does no longer start the udev daemon. This must be done with
-the init script that prepares /dev on tmpfs and creates the initial nodes,
-before starting the daemon.
-
-udev 075
-========
-Silent a too verbose error logging for the old hotplug.d/ dev.d/
-emulation.
-
-The copy of klibc is removed. A systemwide installed version of klibc
-should be used to build a klibc udev now.
-
-udev 074
-========
-NAME="" will not create any nodes, but execute RUN keys. To completely
-ignore an event the OPTION "ignore_device" should be used.
-
-After removal of the reorder queue, events with a TIMEOUT can be executed
-without any queuing now.
-
-udev 073
-========
-Fixed bug in udevd, if inotify is not available. We depend on netlink
-uevents now, kernels without that event source will not work with that
-version of udev anymore.
-
-udev 072
-========
-The rule parsing happens now in the daemon once at startup, all udev
-event processes inherit the already parsed rules from the daemon.
-It is shipped with SUSE10.0 and reduces heavily the system load at
-startup. The option to save precompiled rules and let the udev process
-pick the them up is removed, as it's no longer needed.
-
-Kernel 2.6.15 will have symlinks at /class/input pointing to the real
-device. Libsysfs is changed to "translate" the requested link into the
-real device path, as it would happen with the hotplug event. Otherwise
-device removal and the udev database will not work.
-
-Using 'make STRIPCMD=' will leave the binaries unstripped for debugging
-and packaging.
-
-A few improvements for vol_id, the filesytem probing code.
-
-udev 071
-========
-Fix a stupid typo in extras/run_directory for "make install".
-
-scsi_id creates the temporary devnode now in /dev for usage with a
-non-writable /tmp directory.
-
-The uevent kernel socket buffer can carry app. 50.000 events now,
-let's see who can break this again. :)
-
-The upcoming kernel will have a new input driver core integration.
-Some class devices are now symlinks to the real device. libsysfs
-needs a fix for this to work correctly. Udevstart of older udev
-versions will _not_ create these devices!
-
-udev 070
-========
-Fix a 'install' target in the Makefile, that prevents EXTRAS from
-beeing installed.
-
-udev 069
-========
-A bunch of mostly trivial bugfixes. From now on no node name or
-symlink name can contain any character than plain whitelisted ascii
-characters or validated utf8 byte-streams. This is needed for the
-/dev/disk/by-label/* links, because we import untrusted data and
-export it to the filesystem.
-
-udev 068
-========
-More bugfixes. If udevd was started from the kernel, we don't
-have stdin/stdout/stderr, which broke the forked tools in some
-situations.
-
-udev 067
-========
-Bugfix. udevstart event ordering was broken for a long time.
-The new run_program() uncovered it, because /dev/null was not
-available while we try to run external programs.
-Now udevstart should create it before we run anything.
-
-udev 066
-========
-Minor bugfixes and some distro rules updates. If you don't have the
-persistent disk rules in /dev/disk/by-*/* on your distro, just
-grab it from here. :)
-
-udev 065
-========
-We can use socket communication now to pass events from udev to
-other programs:
-  RUN+="socket:/org/freedesktop/hal/udev_event"
-will pass the whole udev event to the HAL daemon without the need
-for a forked helper. (See ChangeLog for udevmonitor, as an example)
-
-udev 064
-========
-Mostly bugfixes and see ChangeLog.
-
-The test for the existence of an environment value should be
-switched from:
-  ENV{KEY}=="*" to ENV{KEY}=="?*"
-because "*" will not fail anymore, if the key does not exist or
-is empty.
-
-udev 063
-========
-Bugfixes and a few tweaks described in the ChangeLog.
-
-udev 062
-========
-Mostly a Bugfix release.
-
-Added WAIT_FOR_SYSFS="<attribute>" to be able to fight against the sysfs
-timing with custom rules.
-
-udev 061
-========
-We changed the  internal rule storage format. Our large rule files took
-2 MB of RAM, with the change we are down to 99kB.
-
-If the device-node has been created with default name and no symlink or
-options are to remenber, it is not longer stored in the udevdb. HAL will
-need to be updated to work correctly with that change.
-
-To overrride optimization flags, OPTFLAGS may be used now.
-
-udev 060
-========
-Bugfix release.
-
-udev 059
-========
-Major changes happened with this release. The goal is to take over the
-complete kernel-event handling and provide a more efficient way to dispatch
-kernel events. Replacing most of the current shell script logic and the
-kernel forked helper with a netlink-daemon and a rule-based event handling.
-
-o udevd listens to netlink events now. The first valid netlink event
-  will make udevd ignore any message from udevsend that contains a
-  SEQNUM, to avoid duplicate events. The forked events can be disabled
-  with:
-    echo "" > /proc/sys/kernel/hotplug
-  For full support, the broken input-subsytem needs to be fixed, not to
-  bypass the driver core.
-
-o /etc/dev.d/ + /etc/hotplug.d/ directory multiplexing is completely
-  removed from udev itself and must be emulated by calling small
-  helper binaries provided in the extras folder:
-    make EXTRAS=extras/run_directory/
-  will build udev_run_devd and udev_run_hotplugd, which can be called
-  from a rule if needed:
-    RUN+="/sbin/udev_run_hotplugd"
-  The recommended way to handle this is to convert all the calls from
-  the directories to explicit udev rules and get completely rid of the
-  multiplexing. (To catch a ttyUSB event, you now no longer need to
-  fork and exit 300 tty script instances you are not interested in, it
-  is just one rule that matches exactly the device.)
-
-o udev handles now _all_ events not just events for class and block
-  devices, this way it is possible to control the complete event
-  behavior with udev rules. Especially useful for rules like:
-    ACTION="add", DEVPATH="/devices/*", MODALIAS=="?*", RUN+="/sbin/modprobe $modalias"
-
-o As used in the modalias rule, udev supports now textual
-  substitution placeholder along with the usual format chars. This
-  needs to be documented, for now it's only visible in udev_rules_parse.c.
-
-o The rule keys support now more operations. This is documented in the
-  man page. It is possible to add values to list-keys like the SYMLINK
-  and RUN list with KEY+="value" and to clear the list by assigning KEY="".
-  Also "final"-assignments are supported by using KEY:="value", which will
-  prevent changing the key by any later rule.
-
-o kernel 2.6.12 has the "detached_state" attribute removed from
-  sysfs, which was used to recognize sysfs population. We switched that
-  to wait for the "bus" link, which is only available in kernels after 2.6.11.
-  Running this udev version on older kernels may cause a short delay for
-  some events.
-
-o To provide infrastructure for persistent device naming, the id programs:
-  scsi_id, vol_id (former udev_volume_id), and ata_id (new) are able now
-  to export the probed data in environment key format:
-    pim:~ # /sbin/ata_id --export /dev/hda
-    ID_MODEL=HTS726060M9AT00
-    ID_SERIAL=MRH401M4G6UM9B
-    ID_REVISION=MH4OA6BA
-
-  The following rules:
-    KERNEL="hd*[!0-9]", IMPORT="/sbin/ata_id --export $tempnode"
-    KERNEL="hd*[!0-9]", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/$env{ID_MODEL}_$env{ID_SERIAL}"
-
-  Will create:
-    kay@pim:~> tree /dev/disk
-    /dev/disk
-    |-- by-id
-    |   |-- HTS726060M9AT00_MRH401M4G6UM9B -> ../../hda
-    |   `-- IBM-Memory_Key -> ../../sda
-    |-- by-label
-    |   |-- swap -> ../../hda1
-    |   |-- date -> ../../sda1
-    |   `-- home -> ../../hda3
-    `-- by-uuid
-        |-- 2E08712B0870F2E7 -> ../../hda3
-        |-- 9352cfef-7687-47bc-a2a3-34cf136f72e1 -> ../../hda1
-        |-- E845-7A89 -> ../../sda1
-        `-- b2a61681-3812-4f13-a4ff-920d70604299 -> ../../hda2
-
-  The IMPORT= operation will import these keys in the environment and make
-  it available for later PROGRAM= and RUN= executed programs. The keys are
-  also stored in the udevdb and can be queried from there with one of the
-  next udev versions.
-
-o A few binaries are silently added to the repository, which can be used
-  to replay kernel events from initramfs instead of using coldplug. udevd
-  can be instructed now to queue-up events while the stored events from
-  initramfs are filled into the udevd-queue. This code is still under
-  development and there is no documentation now besides the code itself.
-  The additional binaries get compiled, but are not installed by default.
-
-o There is also a temporary fix for a performance problem where too many
-  events happen in parallel and every event needs to parse the rules.
-  udev can now read precompiled rules stored on disk. This is likely to be
-  replaced by a more elegant solution in a future udev version.
-
-udev 058
-========
-With kernel version 2.6.12, the sysfs file "detached_state" was removed.
-Fix for libsysfs not to expect this file was added.
-
-udev 057
-========
-All rules are applied now, but only the first matching rule with a NAME-key
-will be applied. All later rules with NAME-key are completely ignored. This
-way system supplied symlinks or permissions gets applied to user-defined
-naming rules.
-
-Note:
-Please check your rules setup, if you may need to add OPTIONS="last_rule"
-to some rules, to keep the old behavior.
-
-The rules are read on "remove"-events too. That makes is possible to match
-with keys that are available on remove (KERNEL, SUBSYSTEM, ID, ENV, ...) to
-instruct udev to ignore an event (OPTIONS="ignore_device").
-The new ACTION-key may be used to let a rule act only at a "remove"-event.
-
-The new RUN-key supports rule-based execution of programs after device-node
-handling. This is meant as a general replacement for the dev.d/-directories
-to give fine grained control over the execution of programs.
-
-The %s{}-sysfs format char replacement values are searched at any of the
-devices in the device chain now, not only at the class-device.
-
-We support log priority levels now. The value udev_log in udev.conf is used
-to determine what is printed to syslog. This makes it possible to
-run a version with compiled-in debug messages in a production environment
-which is sometimes needed to find a bug.
-It is still possible to supress the inclusion of _any_ syslog usage with
-USE_LOG=false to create the smallest possible binaries if needed.
-The configured udev_log value can be overridden with the environment variable
-UDEV_LOG.
-
-udev 056
-========
-Possible use of a system-wide klibc:
-  make USE_KLIBC=true KLCC=/usr/bin/klcc all
-will link against an external klibc and our own version will be ignored.
-
-udev 055
-========
-We support an unlimited count of symlinks now.
-
-If USE_STATIC=true is passed to a glibc build, we link statically and use
-a built-in userdb parser to resolve user and group names.
-
-The PLACE= key is gone. It can be replaced by an ID= for a long time, because
-we walk up the chain of physical devices to find a match.
-
-The KEY="<value>" format supports '=', '==', '!=,' , '+=' now. This makes it
-easy to skip certain attribute matches without composing rules with weird
-character class negations like:
-  KERNEL="[!s][!c][!d]*"
-this can now be replaced with:
-  KERNEL!="scd*"
-The current simple '=' is still supported, and should work as it does today,
-but existing rules should be converted if possible, to be better readable.
-
-We have new ENV{}== key now, to match against a maximum of 5 environment
-variables.
-
-udevstart is its own binary again, because we don't need co carry this araound
-with every forked event.
diff --git a/src/udev/README b/src/udev/README
deleted file mode 100644 (file)
index 38459c6..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-udev - Linux userspace device management
-
-Integrating udev in the system has complex dependencies and may differ from
-distribution to distribution. A system may not be able to boot up or work
-reliably without a properly installed udev version. The upstream udev project
-does not recommend replacing a distro's udev installation with the upstream
-version.
-
-The upstream udev project's set of default rules may require a most recent
-kernel release to work properly.
-
-Tools and rules shipped by udev are not public API and may change at any time.
-Never call any private tool in /usr/lib/udev from any external application; it
-might just go away in the next release. Access to udev information is only offered
-by udevadm and libudev. Tools and rules in /usr/lib/udev and the entire contents
-of the /run/udev directory are private to udev and do change whenever needed.
-
-Requirements:
-  - Version 2.6.34 of the Linux kernel with sysfs, procfs, signalfd, inotify,
-    unix domain sockets, networking and hotplug enabled
-
-  - Some architectures might need a later kernel, that supports accept4(),
-    or need to backport the accept4() syscall wiring in the kernel.
-
-  - These options are required:
-      CONFIG_DEVTMPFS=y
-      CONFIG_HOTPLUG=y
-      CONFIG_INOTIFY_USER=y
-      CONFIG_NET=y
-      CONFIG_PROC_FS=y
-      CONFIG_SIGNALFD=y
-      CONFIG_SYSFS=y
-      CONFIG_SYSFS_DEPRECATED*=n
-      CONFIG_UEVENT_HELPER_PATH=""
-
-  - These options might be needed:
-      CONFIG_BLK_DEV_BSG=y (SCSI devices)
-      CONFIG_TMPFS_POSIX_ACL=y (user ACLs for device nodes)
-
-  - The /dev directory needs the 'devtmpfs' filesystem mounted.
-    Udev only manages the permissions and ownership of the
-    kernel-provided device nodes, and possibly creates additional symlinks.
-
-  - Udev requires /run to be writable, which is usually done by mounting a
-    'tmpfs' filesystem.
-
-  - This version of udev does not work properly with the CONFIG_SYSFS_DEPRECATED*
-    option enabled.
-
-  - The deprecated hotplug helper /sbin/hotplug should be disabled in the
-    kernel configuration, it is not needed today, and may render the system
-    unusable because the kernel may create too many processes in parallel
-    so that the system runs out-of-memory.
-
-  - The proc filesystem must be mounted on /proc, and the sysfs filesystem must
-    be mounted at /sys. No other locations are supported by a standard
-    udev installation.
-
-  - The default rule sset requires the following group names resolvable at udev startup:
-      disk, cdrom, floppy, tape, audio, video, lp, tty, dialout, and kmem.
-    Especially in LDAP setups, it is required that getgrnam() be able to resolve
-    these group names with only the rootfs mounted and while no network is
-    available.
-
-  - Some udev extras have external dependencies like:
-      libglib2, usbutils, pciutils, and gperf.
-    All these extras can be disabled with configure options.
-
-Setup:
-  - The udev daemon should be started to handle device events sent by the kernel.
-    During bootup, the events for already existing devices can be replayed, so
-    that they are configured by udev. The systemd service files contain the
-    needed commands to start the udev daemon and the coldplug sequence.
-
-  - Restarting the daemon never applies any rules to existing devices.
-
-  - New/changed rule files are picked up automatically; there is usually no
-    daemon restart or signal needed.
-
-Operation:
-  - Based on events the kernel sends out on device creation/removal, udev
-    creates/removes device nodes and symlinks in the /dev directory.
-
-  - All kernel events are matched against a set of specified rules, which
-    possibly hook into the event processing and load required kernel
-    modules to set up devices. For all devices, the kernel exports a major/minor
-    number; if needed, udev creates a device node with the default kernel
-    device name. If specified, udev applies permissions/ownership to the device
-    node, creates additional symlinks pointing to the node, and executes
-    programs to handle the device.
-
-  - The events udev handles, and the information udev merges into its device
-    database, can be accessed with libudev:
-      http://www.kernel.org/pub/linux/utils/kernel/hotplug/libudev/
-      http://www.kernel.org/pub/linux/utils/kernel/hotplug/gudev/
-
-For more details about udev and udev rules, see the udev man pages:
-      http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev/
-
-Please direct any comment/question to the linux-hotplug mailing list at:
-  linux-hotplug@vger.kernel.org
diff --git a/src/udev/TODO b/src/udev/TODO
deleted file mode 100644 (file)
index 8b8b9c8..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
- - find a way to tell udev to not cancel firmware
-   requests in initramfs
-
- - scsi_id -> sg3_utils?
-
- - make gtk-doc optional like kmod
-
- - move /usr/lib/udev/devices/ to tmpfiles
-
- - trigger --subsystem-match=usb/usb_device
-
- - kill rules_generator
-
- - have a $attrs{} ?
-
- - remove RUN+="socket:"
-
- - libudev.so.1
-     - symbol versioning
-     - return object with *_unref()
-     - udev_monitor_from_socket()
-     - udev_queue_get_failed_list_entry()
diff --git a/src/udev/accelerometer/61-accelerometer.rules b/src/udev/accelerometer/61-accelerometer.rules
new file mode 100644 (file)
index 0000000..a6a2bfd
--- /dev/null
@@ -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/src/udev/accelerometer/accelerometer.c b/src/udev/accelerometer/accelerometer.c
new file mode 100644 (file)
index 0000000..bc9715b
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ * 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 <hadess@hadess.net>
+ *
+ * orientation_calc() from the sensorfw package
+ * Copyright (C) 2009-2010 Nokia Corporation
+ * Authors:
+ *   Üstün Ergenoglu <ext-ustun.ergenoglu@nokia.com>
+ *   Timo Rongas <ext-timo.2.rongas@nokia.com>
+ *   Lihan Guo <lihan.guo@digia.com>
+ *
+ * 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 keymap; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <limits.h>
+#include <linux/limits.h>
+#include <linux/input.h>
+
+#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(x))
+#define LONG(x) ((x)/BITS_PER_LONG)
+#define test_bit(bit, array)    ((array[LONG(bit)] >> OFF(bit)) & 1)
+
+static int debug = 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 (strcmp (orientation, orientations[i]) == 0)
+                        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 = 1; } }
+
+/* accelerometers */
+static void test_orientation(struct udev *udev,
+                             struct udev_device *dev,
+                             const char *devpath)
+{
+        OrientationUp old, new;
+        int fd, r;
+        struct input_event ev[64];
+        int got_syn = 0;
+        int got_x, got_y, got_z;
+        int x = 0, y = 0, z = 0;
+        char text[64];
+
+        old = get_prev_orientation(dev);
+
+        if ((fd = open(devpath, O_RDONLY)) < 0)
+                return;
+
+        got_x = got_y = got_z = 0;
+
+        while (1) {
+                int i;
+
+                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 == 1) {
+                                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 = 1;
+                        }
+                        if (got_x && got_y && got_z)
+                                goto read_dev;
+                }
+        }
+
+read_dev:
+        close(fd);
+
+        if (!got_x || !got_y || !got_z)
+                return;
+
+        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] <device path>\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;
+        const char *id_path;
+        struct udev_enumerate *enumerate;
+        struct udev_list_entry *list_entry;
+
+        udev = udev_new();
+        if (udev == NULL)
+                return 1;
+
+        udev_log_init("input_id");
+        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;
+                        if (udev_get_log_priority(udev) < LOG_INFO)
+                                udev_set_log_priority(udev, LOG_INFO);
+                        break;
+                case 'h':
+                        help();
+                        exit(0);
+                default:
+                        exit(1);
+                }
+        }
+
+        if (argv[optind] == NULL) {
+                help();
+                exit(1);
+        }
+
+        /* get the device */
+        snprintf(devpath, sizeof(devpath), "%s/%s", udev_get_sys_path(udev), argv[optind]);
+        dev = udev_device_new_from_syspath(udev, devpath);
+        if (dev == NULL) {
+                fprintf(stderr, "unable to access '%s'\n", devpath);
+                return 1;
+        }
+
+        id_path = udev_device_get_property_value(dev, "ID_PATH");
+        if (id_path == NULL) {
+                fprintf (stderr, "unable to get property ID_PATH for '%s'", devpath);
+                return 0;
+        }
+
+        /* Get the children devices and find the devnode
+         * FIXME: use udev_enumerate_add_match_children() instead
+         * when it's available */
+        devnode = NULL;
+        enumerate = udev_enumerate_new(udev);
+        udev_enumerate_add_match_property(enumerate, "ID_PATH", id_path);
+        udev_enumerate_add_match_subsystem(enumerate, "input");
+        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;
+        }
+
+        info(udev, "Opening accelerometer device %s\n", devnode);
+        test_orientation(udev, dev, devnode);
+        free(devnode);
+
+        return 0;
+}
diff --git a/src/udev/ata_id/ata_id.c b/src/udev/ata_id/ata_id.c
new file mode 100644 (file)
index 0000000..846a73b
--- /dev/null
@@ -0,0 +1,721 @@
+/*
+ * ata_id - reads product/serial number from ATA drives
+ *
+ * Copyright (C) 2005-2008 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2009 Lennart Poettering <lennart@poettering.net>
+ * Copyright (C) 2009-2010 David Zeuthen <zeuthen@gmail.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+#include <scsi/scsi.h>
+#include <scsi/sg.h>
+#include <scsi/scsi_ioctl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <linux/types.h>
+#include <linux/hdreg.h>
+#include <linux/fs.h>
+#include <linux/cdrom.h>
+#include <linux/bsg.h>
+#include <arpa/inet.h>
+
+#include "libudev.h"
+#include "libudev-private.h"
+
+#define COMMAND_TIMEOUT_MSEC (30 * 1000)
+
+static int disk_scsi_inquiry_command(int      fd,
+                                     void    *buf,
+                                     size_t   buf_len)
+{
+        struct sg_io_v4 io_v4;
+        uint8_t cdb[6];
+        uint8_t sense[32];
+        int ret;
+
+        /*
+         * INQUIRY, see SPC-4 section 6.4
+         */
+        memset(cdb, 0, sizeof(cdb));
+        cdb[0] = 0x12;                         /* OPERATION CODE: INQUIRY */
+        cdb[3] = (buf_len >> 8);         /* ALLOCATION LENGTH */
+        cdb[4] = (buf_len & 0xff);
+
+        memset(sense, 0, sizeof(sense));
+
+        memset(&io_v4, 0, 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 (cdb);
+        io_v4.request = (uintptr_t) cdb;
+        io_v4.max_response_len = sizeof (sense);
+        io_v4.response = (uintptr_t) sense;
+        io_v4.din_xfer_len = buf_len;
+        io_v4.din_xferp = (uintptr_t) buf;
+        io_v4.timeout = COMMAND_TIMEOUT_MSEC;
+
+        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;
+
+                        memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+                        io_hdr.interface_id = 'S';
+                        io_hdr.cmdp = (unsigned char*) cdb;
+                        io_hdr.cmd_len = sizeof (cdb);
+                        io_hdr.dxferp = buf;
+                        io_hdr.dxfer_len = buf_len;
+                        io_hdr.sbp = sense;
+                        io_hdr.mx_sb_len = sizeof (sense);
+                        io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+                        io_hdr.timeout = COMMAND_TIMEOUT_MSEC;
+
+                        ret = ioctl(fd, SG_IO, &io_hdr);
+                        if (ret != 0)
+                                goto out;
+
+                        /* 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;
+                                ret = -1;
+                                goto out;
+                        }
+                } else {
+                        goto out;
+                }
+        }
+
+        /* 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;
+                ret = -1;
+                goto out;
+        }
+
+ out:
+        return ret;
+}
+
+static int disk_identify_command(int          fd,
+                                 void         *buf,
+                                 size_t          buf_len)
+{
+        struct sg_io_v4 io_v4;
+        uint8_t cdb[12];
+        uint8_t sense[32];
+        uint8_t *desc = sense+8;
+        int ret;
+
+        /*
+         * 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
+         */
+        memset(cdb, 0, sizeof(cdb));
+        cdb[0] = 0xa1;                        /* OPERATION CODE: 12 byte pass through */
+        cdb[1] = 4 << 1;                /* PROTOCOL: PIO Data-in */
+        cdb[2] = 0x2e;                        /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */
+        cdb[3] = 0;                        /* FEATURES */
+        cdb[4] = 1;                        /* SECTORS */
+        cdb[5] = 0;                        /* LBA LOW */
+        cdb[6] = 0;                        /* LBA MID */
+        cdb[7] = 0;                        /* LBA HIGH */
+        cdb[8] = 0 & 0x4F;                /* SELECT */
+        cdb[9] = 0xEC;                        /* Command: ATA IDENTIFY DEVICE */;
+        memset(sense, 0, sizeof(sense));
+
+        memset(&io_v4, 0, 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 (cdb);
+        io_v4.request = (uintptr_t) cdb;
+        io_v4.max_response_len = sizeof (sense);
+        io_v4.response = (uintptr_t) sense;
+        io_v4.din_xfer_len = buf_len;
+        io_v4.din_xferp = (uintptr_t) buf;
+        io_v4.timeout = COMMAND_TIMEOUT_MSEC;
+
+        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;
+
+                        memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+                        io_hdr.interface_id = 'S';
+                        io_hdr.cmdp = (unsigned char*) cdb;
+                        io_hdr.cmd_len = sizeof (cdb);
+                        io_hdr.dxferp = buf;
+                        io_hdr.dxfer_len = buf_len;
+                        io_hdr.sbp = sense;
+                        io_hdr.mx_sb_len = sizeof (sense);
+                        io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+                        io_hdr.timeout = COMMAND_TIMEOUT_MSEC;
+
+                        ret = ioctl(fd, SG_IO, &io_hdr);
+                        if (ret != 0)
+                                goto out;
+                } else {
+                        goto out;
+                }
+        }
+
+        if (!(sense[0] == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c)) {
+                errno = EIO;
+                ret = -1;
+                goto out;
+        }
+
+ out:
+        return ret;
+}
+
+static int disk_identify_packet_device_command(int          fd,
+                                               void         *buf,
+                                               size_t          buf_len)
+{
+        struct sg_io_v4 io_v4;
+        uint8_t cdb[16];
+        uint8_t sense[32];
+        uint8_t *desc = sense+8;
+        int ret;
+
+        /*
+         * 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
+         */
+        memset(cdb, 0, sizeof(cdb));
+        cdb[0] = 0x85;                        /* OPERATION CODE: 16 byte pass through */
+        cdb[1] = 4 << 1;                /* PROTOCOL: PIO Data-in */
+        cdb[2] = 0x2e;                        /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */
+        cdb[3] = 0;                        /* FEATURES */
+        cdb[4] = 0;                        /* FEATURES */
+        cdb[5] = 0;                        /* SECTORS */
+        cdb[6] = 1;                        /* SECTORS */
+        cdb[7] = 0;                        /* LBA LOW */
+        cdb[8] = 0;                        /* LBA LOW */
+        cdb[9] = 0;                        /* LBA MID */
+        cdb[10] = 0;                        /* LBA MID */
+        cdb[11] = 0;                        /* LBA HIGH */
+        cdb[12] = 0;                        /* LBA HIGH */
+        cdb[13] = 0;                        /* DEVICE */
+        cdb[14] = 0xA1;                        /* Command: ATA IDENTIFY PACKET DEVICE */;
+        cdb[15] = 0;                        /* CONTROL */
+        memset(sense, 0, sizeof(sense));
+
+        memset(&io_v4, 0, 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 (cdb);
+        io_v4.request = (uintptr_t) cdb;
+        io_v4.max_response_len = sizeof (sense);
+        io_v4.response = (uintptr_t) sense;
+        io_v4.din_xfer_len = buf_len;
+        io_v4.din_xferp = (uintptr_t) buf;
+        io_v4.timeout = COMMAND_TIMEOUT_MSEC;
+
+        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;
+
+                        memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+                        io_hdr.interface_id = 'S';
+                        io_hdr.cmdp = (unsigned char*) cdb;
+                        io_hdr.cmd_len = sizeof (cdb);
+                        io_hdr.dxferp = buf;
+                        io_hdr.dxfer_len = buf_len;
+                        io_hdr.sbp = sense;
+                        io_hdr.mx_sb_len = sizeof (sense);
+                        io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+                        io_hdr.timeout = COMMAND_TIMEOUT_MSEC;
+
+                        ret = ioctl(fd, SG_IO, &io_hdr);
+                        if (ret != 0)
+                                goto out;
+                } else {
+                        goto out;
+                }
+        }
+
+        if (!(sense[0] == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c)) {
+                errno = EIO;
+                ret = -1;
+                goto out;
+        }
+
+ out:
+        return ret;
+}
+
+/**
+ * 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;
+
+        assert(identify != NULL);
+        assert(dest != NULL);
+        assert((dest_len & 1) == 0);
+
+        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;
+
+        assert(out_identify != NULL);
+
+        /* init results */
+        ret = -1;
+        memset(out_identify, '\0', 512);
+        is_packet_device = 0;
+
+        /* 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;
+}
+
+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;
+
+        udev_log_init("ata_id");
+        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] <device>\n"
+                               "  --export    print values as environment keys\n"
+                               "  --help      print this help text\n\n");
+                        goto exit;
+                }
+        }
+
+        node = argv[optind];
+        if (node == NULL) {
+                err(udev, "no node specified\n");
+                rc = 1;
+                goto exit;
+        }
+
+        fd = open(node, O_RDONLY|O_NONBLOCK);
+        if (fd < 0) {
+                err(udev, "unable to open '%s'\n", 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,  6); /* 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) {
+                        info(udev, "HDIO_GET_IDENTITY failed for '%s': %m\n", 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);
+        udev_log_close();
+        return rc;
+}
diff --git a/src/udev/autogen.sh b/src/udev/autogen.sh
deleted file mode 100755 (executable)
index 55ee03a..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/bin/sh -e
-
-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."
-fi
-
-gtkdocize
-autoreconf --install --symlink
-
-libdir() {
-        echo $(cd $1/$(gcc -print-multi-os-directory); pwd)
-}
-
-args="$args \
---prefix=/usr \
---sysconfdir=/etc \
---libdir=$(libdir /usr/lib) \
---with-selinux \
---enable-gtk-doc"
-
-if [ -L /bin ]; then
-args="$args \
---libexecdir=/usr/lib \
---with-systemdsystemunitdir=/usr/lib/systemd/system \
-"
-else
-args="$args \
---with-rootprefix= \
----with-rootlibdir=$(libdir /lib) \
---bindir=/sbin \
---libexecdir=/lib \
---with-systemdsystemunitdir=/lib/systemd/system \
-"
-fi
-
-echo
-echo "----------------------------------------------------------------"
-echo "Initialized build system. For a common configuration please run:"
-echo "----------------------------------------------------------------"
-echo
-echo "./configure CFLAGS='-g -O1' $args"
-echo
diff --git a/src/udev/cdrom_id/60-cdrom_id.rules b/src/udev/cdrom_id/60-cdrom_id.rules
new file mode 100644 (file)
index 0000000..6eaf76a
--- /dev/null
@@ -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/src/udev/cdrom_id/cdrom_id.c b/src/udev/cdrom_id/cdrom_id.c
new file mode 100644 (file)
index 0000000..f90d52e
--- /dev/null
@@ -0,0 +1,1099 @@
+/*
+ * cdrom_id - optical drive and media information prober
+ *
+ * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <getopt.h>
+#include <time.h>
+#include <scsi/sg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <linux/cdrom.h>
+
+#include "libudev.h"
+#include "libudev-private.h"
+
+static bool debug;
+
+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", "r");
+        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, char *cmd, int err)
+{
+        if (err == -1) {
+                info(udev, "%s failed\n", cmd);
+                return;
+        }
+        info(udev, "%s failed with SK=%Xh/ASC=%02Xh/ACQ=%02Xh\n", 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)
+{
+        memset(cmd, 0x00, 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)
+                info(udev, "CDROM_CLEAR_OPTIONS, CDO_LOCK failed\n");
+
+        err = ioctl(fd, CDROM_LOCKDOOR, lock ? 1 : 0);
+        if (err < 0)
+                info(udev, "CDROM_LOCKDOOR failed\n");
+
+        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) {
+                info(udev, "CDROM_GET_CAPABILITY failed\n");
+                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) {
+                info(udev, "CDROM_DRIVE_STATUS != CDS_DISC_OK\n");
+                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) {
+                info(udev, "not an MMC unit\n");
+                return -1;
+        }
+
+        info(udev, "INQUIRY: [%.8s][%.16s][%.4s]\n", 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:
+                info(udev, "profile 0x%02x \n", cur_profile);
+                cd_media = 1;
+                cd_media_mo = 1;
+                break;
+        case 0x08:
+                info(udev, "profile 0x%02x media_cd_rom\n", cur_profile);
+                cd_media = 1;
+                cd_media_cd_rom = 1;
+                break;
+        case 0x09:
+                info(udev, "profile 0x%02x media_cd_r\n", cur_profile);
+                cd_media = 1;
+                cd_media_cd_r = 1;
+                break;
+        case 0x0a:
+                info(udev, "profile 0x%02x media_cd_rw\n", cur_profile);
+                cd_media = 1;
+                cd_media_cd_rw = 1;
+                break;
+        case 0x10:
+                info(udev, "profile 0x%02x media_dvd_ro\n", cur_profile);
+                cd_media = 1;
+                cd_media_dvd_rom = 1;
+                break;
+        case 0x11:
+                info(udev, "profile 0x%02x media_dvd_r\n", cur_profile);
+                cd_media = 1;
+                cd_media_dvd_r = 1;
+                break;
+        case 0x12:
+                info(udev, "profile 0x%02x media_dvd_ram\n", cur_profile);
+                cd_media = 1;
+                cd_media_dvd_ram = 1;
+                break;
+        case 0x13:
+                info(udev, "profile 0x%02x media_dvd_rw_ro\n", cur_profile);
+                cd_media = 1;
+                cd_media_dvd_rw = 1;
+                cd_media_dvd_rw_ro = 1;
+                break;
+        case 0x14:
+                info(udev, "profile 0x%02x media_dvd_rw_seq\n", cur_profile);
+                cd_media = 1;
+                cd_media_dvd_rw = 1;
+                cd_media_dvd_rw_seq = 1;
+                break;
+        case 0x1B:
+                info(udev, "profile 0x%02x media_dvd_plus_r\n", cur_profile);
+                cd_media = 1;
+                cd_media_dvd_plus_r = 1;
+                break;
+        case 0x1A:
+                info(udev, "profile 0x%02x media_dvd_plus_rw\n", cur_profile);
+                cd_media = 1;
+                cd_media_dvd_plus_rw = 1;
+                break;
+        case 0x2A:
+                info(udev, "profile 0x%02x media_dvd_plus_rw_dl\n", cur_profile);
+                cd_media = 1;
+                cd_media_dvd_plus_rw_dl = 1;
+                break;
+        case 0x2B:
+                info(udev, "profile 0x%02x media_dvd_plus_r_dl\n", cur_profile);
+                cd_media = 1;
+                cd_media_dvd_plus_r_dl = 1;
+                break;
+        case 0x40:
+                info(udev, "profile 0x%02x media_bd\n", cur_profile);
+                cd_media = 1;
+                cd_media_bd = 1;
+                break;
+        case 0x41:
+        case 0x42:
+                info(udev, "profile 0x%02x media_bd_r\n", cur_profile);
+                cd_media = 1;
+                cd_media_bd_r = 1;
+                break;
+        case 0x43:
+                info(udev, "profile 0x%02x media_bd_re\n", cur_profile);
+                cd_media = 1;
+                cd_media_bd_re = 1;
+                break;
+        case 0x50:
+                info(udev, "profile 0x%02x media_hddvd\n", cur_profile);
+                cd_media = 1;
+                cd_media_hddvd = 1;
+                break;
+        case 0x51:
+                info(udev, "profile 0x%02x media_hddvd_r\n", cur_profile);
+                cd_media = 1;
+                cd_media_hddvd_r = 1;
+                break;
+        case 0x52:
+                info(udev, "profile 0x%02x media_hddvd_rw\n", cur_profile);
+                cd_media = 1;
+                cd_media_hddvd_rw = 1;
+                break;
+        default:
+                info(udev, "profile 0x%02x <ignored>\n", 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:
+                        info(udev, "profile 0x%02x mo\n", profile);
+                        cd_mo = 1;
+                        break;
+                case 0x08:
+                        info(udev, "profile 0x%02x cd_rom\n", profile);
+                        cd_cd_rom = 1;
+                        break;
+                case 0x09:
+                        info(udev, "profile 0x%02x cd_r\n", profile);
+                        cd_cd_r = 1;
+                        break;
+                case 0x0A:
+                        info(udev, "profile 0x%02x cd_rw\n", profile);
+                        cd_cd_rw = 1;
+                        break;
+                case 0x10:
+                        info(udev, "profile 0x%02x dvd_rom\n", profile);
+                        cd_dvd_rom = 1;
+                        break;
+                case 0x12:
+                        info(udev, "profile 0x%02x dvd_ram\n", profile);
+                        cd_dvd_ram = 1;
+                        break;
+                case 0x13:
+                case 0x14:
+                        info(udev, "profile 0x%02x dvd_rw\n", profile);
+                        cd_dvd_rw = 1;
+                        break;
+                case 0x1B:
+                        info(udev, "profile 0x%02x dvd_plus_r\n", profile);
+                        cd_dvd_plus_r = 1;
+                        break;
+                case 0x1A:
+                        info(udev, "profile 0x%02x dvd_plus_rw\n", profile);
+                        cd_dvd_plus_rw = 1;
+                        break;
+                case 0x2A:
+                        info(udev, "profile 0x%02x dvd_plus_rw_dl\n", profile);
+                        cd_dvd_plus_rw_dl = 1;
+                        break;
+                case 0x2B:
+                        info(udev, "profile 0x%02x dvd_plus_r_dl\n", profile);
+                        cd_dvd_plus_r_dl = 1;
+                        break;
+                case 0x40:
+                        cd_bd = 1;
+                        info(udev, "profile 0x%02x bd\n", profile);
+                        break;
+                case 0x41:
+                case 0x42:
+                        cd_bd_r = 1;
+                        info(udev, "profile 0x%02x bd_r\n", profile);
+                        break;
+                case 0x43:
+                        cd_bd_re = 1;
+                        info(udev, "profile 0x%02x bd_re\n", profile);
+                        break;
+                case 0x50:
+                        cd_hddvd = 1;
+                        info(udev, "profile 0x%02x hddvd\n", profile);
+                        break;
+                case 0x51:
+                        cd_hddvd_r = 1;
+                        info(udev, "profile 0x%02x hddvd_r\n", profile);
+                        break;
+                case 0x52:
+                        cd_hddvd_rw = 1;
+                        info(udev, "profile 0x%02x hddvd_rw\n", profile);
+                        break;
+                default:
+                        info(udev, "profile 0x%02x <ignored>\n", 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) {
+                        info(udev, "no current profile, but disc is present; assuming CD-ROM\n");
+                        cd_media_cd_rom = 1;
+                        return 0;
+                } else {
+                        info(udev, "no current profile, assuming no media\n");
+                        return -1;
+                }
+        };
+
+        cd_media = 1;
+
+        if (header[2] & 16) {
+                cd_media_cd_rw = 1;
+                info(udev, "profile 0x0a media_cd_rw\n");
+        } else if ((header[2] & 3) < 2 && cd_cd_r) {
+                cd_media_cd_r = 1;
+                info(udev, "profile 0x09 media_cd_r\n");
+        } else {
+                cd_media_cd_rom = 1;
+                info(udev, "profile 0x08 media_cd_rom\n");
+        }
+        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) {
+                        info(udev, "drive is pre-MMC2 and does not support 46h get configuration command\n");
+                        info(udev, "trying to work around the problem\n");
+                        ret = cd_profiles_old_mmc(udev, fd);
+                }
+                goto out;
+        }
+
+        cur_profile = features[6] << 8 | features[7];
+        if (cur_profile > 0) {
+                info(udev, "current profile 0x%02x\n", cur_profile);
+                feature_profile_media (udev, cur_profile);
+                ret = 0; /* we have media */
+        } else {
+                info(udev, "no current profile, assuming no media\n");
+        }
+
+        len = features[0] << 24 | features[1] << 16 | features[2] << 8 | features[3];
+        info(udev, "GET CONFIGURATION: size of features buffer 0x%04x\n", len);
+
+        if (len > sizeof(features)) {
+                info(udev, "can not get features in a single query, truncating\n");
+                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];
+        info(udev, "GET CONFIGURATION: size of features buffer 0x%04x\n", len);
+
+        if (len > sizeof(features)) {
+                info(udev, "can not get features in a single query, truncating\n");
+                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:
+                        info(udev, "GET CONFIGURATION: feature 'profiles', with %i entries\n", features[i+3] / 4);
+                        feature_profiles(udev, &features[i]+4, features[i+3]);
+                        break;
+                default:
+                        info(udev, "GET CONFIGURATION: feature 0x%04x <ignored>, with 0x%02x bytes\n", 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;
+        info(udev, "disk type %02x\n", header[8]);
+        info(udev, "hardware reported media status: %s\n", 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];
+                                info(udev, "write-protected DVD-RAM media inserted\n");
+                                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) {
+                                info(udev, "invalid format capacities length\n");
+                                return -1;
+                        }
+
+                        switch(format[8] & 3) {
+                            case 1:
+                                info(udev, "unformatted DVD-RAM media inserted\n");
+                                /* 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:
+                                info(udev, "formatted DVD-RAM media inserted\n");
+                                break;
+
+                            case 3:
+                                cd_media = 0; //return no media
+                                info(udev, "format capacities returned no media\n");
+                                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];
+                        info(udev, "no data in blocks 0 or 16, assuming blank\n");
+                } else {
+                        info(udev, "data in blocks 0 or 16, assuming complete\n");
+                }
+        }
+
+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;
+        info(udev, "READ TOC: len: %d, start track: %d, end track: %d\n", 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];
+                info(udev, "track=%u info=0x%x(%s) start_block=%u\n",
+                     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];
+        info(udev, "last track %u starts at block %u\n", 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;
+
+        udev_log_init("cdrom_id");
+        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;
+                        if (udev_get_log_priority(udev) < LOG_INFO)
+                                udev_set_log_priority(udev, LOG_INFO);
+                        break;
+                case 'h':
+                        printf("Usage: cdrom_id [options] <device>\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) {
+                err(udev, "no device\n");
+                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|(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) {
+                info(udev, "unable to open '%s'\n", node);
+                fprintf(stderr, "unable to open '%s'\n", node);
+                rc = 1;
+                goto exit;
+        }
+        info(udev, "probing: '%s'\n", 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) {
+                info(udev, "PREVENT_ALLOW_MEDIUM_REMOVAL (lock)\n");
+                media_lock(udev, fd, true);
+        }
+
+        if (unlock && cd_media) {
+                info(udev, "PREVENT_ALLOW_MEDIUM_REMOVAL (unlock)\n");
+                media_lock(udev, fd, false);
+        }
+
+        if (eject) {
+                info(udev, "PREVENT_ALLOW_MEDIUM_REMOVAL (unlock)\n");
+                media_lock(udev, fd, false);
+                info(udev, "START_STOP_UNIT (eject)\n");
+                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);
+        udev_log_close();
+        return rc;
+}
diff --git a/src/udev/collect/collect.c b/src/udev/collect/collect.c
new file mode 100644 (file)
index 0000000..076fe47
--- /dev/null
@@ -0,0 +1,473 @@
+/*
+ * Collect variables across events.
+ *
+ * usage: collect [--add|--remove] <checkpoint> <id> <idlist>
+ *
+ * Adds ID <id> to the list governed by <checkpoint>.
+ * <id> must be part of the ID list <idlist>.
+ * If all IDs given by <idlist> are listed (ie collect has been
+ * invoked for each ID in <idlist>) collect returns 0, the
+ * number of missing IDs otherwise.
+ * A negative number is returned on error.
+ *
+ * Copyright(C) 2007, Hannes Reinecke <hare@suse.de>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "libudev.h"
+#include "libudev-private.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 struct _mate *node_to_mate(struct udev_list_node *node)
+{
+        char *mate;
+
+        mate = (char *)node;
+        mate -= offsetof(struct _mate, node);
+        return (struct _mate *)mate;
+}
+
+static void sig_alrm(int signo)
+{
+        exit(4);
+}
+
+static void usage(void)
+{
+        printf("usage: collect [--add|--remove] [--debug] <checkpoint> <id> <idlist>\n"
+               "\n"
+               "  Adds ID <id> to the list governed by <checkpoint>.\n"
+               "  <id> must be part of the list <idlist>.\n"
+               "  If all IDs given by <idlist> are listed (ie collect has been\n"
+               "  invoked for each ID in <idlist>) 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);
+
+        sprintf(buf, "%s/%s", dir, filename);
+
+        fd = open(buf,O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
+        if (fd < 0)
+                fprintf(stderr, "Cannot open %s: %s\n", buf, strerror(errno));
+
+        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: %s\n", buf, strerror(errno));
+                }
+        }
+
+        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 = calloc(1,bufsize + 1);
+        if (!buf) {
+                fprintf(stderr, "Out of memory\n");
+                return -1;
+        }
+        memset(buf, ' ', bufsize);
+        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));
+                                him->name = strdup(word);
+                                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 (!strcmp(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 (!strcmp(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 -1;
+
+        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 -1;
+                                }
+                                buf = tmpbuf;
+                        }
+                        snprintf(buf, strlen(him->name)+2, "%s ", him->name);
+                        write(fd, buf, strlen(buf));
+                }
+        }
+
+        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: %s\n", strerror(errno));
+                ret = 2;
+                goto exit;
+        }
+
+        udev_list_node_init(&bunch);
+
+        if (debug)
+                fprintf(stderr, "Using checkpoint '%s'\n", checkpoint);
+
+        util_strscpyl(tmpdir, sizeof(tmpdir), udev_get_run_path(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 (!strcmp(him->name, argv[i]))
+                                who = him;
+                }
+                if (!who) {
+                        struct _mate *him;
+
+                        if (debug)
+                                fprintf(stderr, "ID %s: not in database\n", argv[i]);
+                        him = malloc(sizeof (struct _mate));
+                        him->name = malloc(strlen(argv[i]) + 1);
+                        strcpy(him->name, argv[i]);
+                        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/configure.ac b/src/udev/configure.ac
deleted file mode 100644 (file)
index b31b62f..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-AC_PREREQ(2.60)
-AC_INIT([udev],
-       [182],
-       [linux-hotplug@vger.kernel.org],
-       [udev],
-       [http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html])
-AC_CONFIG_SRCDIR([src/udevd.c])
-AC_CONFIG_AUX_DIR([build-aux])
-AM_INIT_AUTOMAKE([check-news foreign 1.11 -Wall -Wno-portability silent-rules tar-pax no-dist-gzip dist-xz subdir-objects])
-AC_USE_SYSTEM_EXTENSIONS
-AC_SYS_LARGEFILE
-AC_CONFIG_MACRO_DIR([m4])
-AM_SILENT_RULES([yes])
-LT_INIT([disable-static])
-AC_PROG_AWK
-AC_PROG_SED
-AC_PROG_MKDIR_P
-GTK_DOC_CHECK(1.10)
-AC_PREFIX_DEFAULT([/usr])
-
-AC_PATH_PROG([XSLTPROC], [xsltproc])
-AM_CONDITIONAL(HAVE_XSLTPROC, test x"$XSLTPROC" != x)
-
-AC_SEARCH_LIBS([clock_gettime], [rt], [], [AC_MSG_ERROR([POSIX RT library not found])])
-
-PKG_CHECK_MODULES(BLKID, blkid >= 2.20)
-
-PKG_CHECK_MODULES(KMOD, libkmod >= 5)
-
-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_SUBST([rootprefix], [$with_rootprefix])
-
-AC_ARG_WITH([rootlibdir],
-       AS_HELP_STRING([--with-rootlibdir=DIR], [rootfs directory to install shared libraries]),
-       [], [with_rootlibdir=$libdir])
-AC_SUBST([rootlib_execdir], [$with_rootlibdir])
-
-AC_ARG_WITH([selinux],
-       AS_HELP_STRING([--with-selinux], [enable SELinux support]),
-       [], [with_selinux=no])
-AS_IF([test "x$with_selinux" = "xyes"], [
-       LIBS_save=$LIBS
-       AC_CHECK_LIB(selinux, getprevcon,
-              [],
-              AC_MSG_ERROR([SELinux selected but libselinux not found]))
-       LIBS=$LIBS_save
-       SELINUX_LIBS="-lselinux -lsepol"
-       AC_DEFINE(WITH_SELINUX, [1] ,[SELinux support.])
-])
-AC_SUBST([SELINUX_LIBS])
-AM_CONDITIONAL(WITH_SELINUX, [test "x$with_selinux" = "xyes"])
-
-AC_ARG_ENABLE([debug],
-       AS_HELP_STRING([--enable-debug], [enable debug messages @<:@default=disabled@:>@]),
-       [], [enable_debug=no])
-AS_IF([test "x$enable_debug" = "xyes"], [ AC_DEFINE(ENABLE_DEBUG, [1], [Debug messages.]) ])
-
-AC_ARG_ENABLE([logging],
-       AS_HELP_STRING([--disable-logging], [disable system logging @<:@default=enabled@:>@]),
-       [], enable_logging=yes)
-AS_IF([test "x$enable_logging" = "xyes"], [ AC_DEFINE(ENABLE_LOGGING, [1], [System logging.]) ])
-
-AC_ARG_ENABLE([manpages],
-        AS_HELP_STRING([--disable-manpages], [disable man pages @<:@default=enabled@:>@]),
-        [], enable_manpages=yes)
-AM_CONDITIONAL([ENABLE_MANPAGES], [test "x$enable_manpages" = "xyes"])
-
-if test "x$cross_compiling" = "xno" ; then
-       AC_CHECK_FILES([/usr/share/pci.ids], [pciids=/usr/share/pci.ids])
-       AC_CHECK_FILES([/usr/share/hwdata/pci.ids], [pciids=/usr/share/hwdata/pci.ids])
-       AC_CHECK_FILES([/usr/share/misc/pci.ids], [pciids=/usr/share/misc/pci.ids])
-fi
-
-AC_ARG_WITH(usb-ids-path,
-       [AS_HELP_STRING([--with-usb-ids-path=DIR], [Path to usb.ids file])],
-       [USB_DATABASE=${withval}],
-       [if test -n "$usbids" ; then
-              USB_DATABASE="$usbids"
-       else
-              PKG_CHECK_MODULES(USBUTILS, usbutils >= 0.82)
-              AC_SUBST([USB_DATABASE], [$($PKG_CONFIG --variable=usbids usbutils)])
-       fi])
-AC_MSG_CHECKING([for USB database location])
-AC_MSG_RESULT([$USB_DATABASE])
-AC_SUBST(USB_DATABASE)
-
-AC_ARG_WITH(pci-ids-path,
-       [AS_HELP_STRING([--with-pci-ids-path=DIR], [Path to pci.ids file])],
-       [PCI_DATABASE=${withval}],
-       [if test -n "$pciids" ; then
-              PCI_DATABASE="$pciids"
-       else
-              AC_MSG_ERROR([pci.ids not found, try --with-pci-ids-path=])
-       fi])
-AC_MSG_CHECKING([for PCI database location])
-AC_MSG_RESULT([$PCI_DATABASE])
-AC_SUBST(PCI_DATABASE)
-
-AC_ARG_WITH(firmware-path,
-       AS_HELP_STRING([--with-firmware-path=DIR[[[:DIR[...]]]]],
-          [Firmware search path (default=ROOTPREFIX/lib/firmware/updates:ROOTPREFIX/lib/firmware)]),
-       [], [with_firmware_path="$rootprefix/lib/firmware/updates:$rootprefix/lib/firmware"])
-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], [$FIRMWARE_PATH])
-
-AC_ARG_WITH([systemdsystemunitdir],
-       AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]),
-       [], [with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)])
-AS_IF([test "x$with_systemdsystemunitdir" != "xno"], [ AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir]) ])
-AM_CONDITIONAL(WITH_SYSTEMD, [test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != "xno" ])
-
-# ------------------------------------------------------------------------------
-# GUdev - libudev gobject interface
-# ------------------------------------------------------------------------------
-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]) ])
-
-AC_ARG_ENABLE([introspection],
-       AS_HELP_STRING([--disable-introspection], [disable GObject introspection @<:@default=enabled@:>@]),
-       [], [enable_introspection=yes])
-AS_IF([test "x$enable_introspection" = "xyes"], [
-       PKG_CHECK_MODULES([INTROSPECTION], [gobject-introspection-1.0 >= 0.6.2])
-       AC_DEFINE([ENABLE_INTROSPECTION], [1], [enable GObject introspection support])
-       AC_SUBST([G_IR_SCANNER], [$($PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0)])
-       AC_SUBST([G_IR_COMPILER], [$($PKG_CONFIG --variable=g_ir_compiler gobject-introspection-1.0)])
-       AC_SUBST([G_IR_GENERATE], [$($PKG_CONFIG --variable=g_ir_generate gobject-introspection-1.0)])
-       AC_SUBST([GIRDIR], [$($PKG_CONFIG --define-variable=datadir=${datadir} --variable=girdir gobject-introspection-1.0)])
-       AC_SUBST([GIRTYPELIBDIR], [$($PKG_CONFIG --define-variable=libdir=${libdir} --variable=typelibdir gobject-introspection-1.0)])
-])
-AM_CONDITIONAL([ENABLE_INTROSPECTION], [test "x$enable_introspection" = "xyes"])
-AM_CONDITIONAL([ENABLE_GUDEV], [test "x$enable_gudev" = "xyes"])
-
-# ------------------------------------------------------------------------------
-# keymap - map custom hardware's multimedia keys
-# ------------------------------------------------------------------------------
-AC_ARG_ENABLE([keymap],
-       AS_HELP_STRING([--disable-keymap], [disable keymap fixup support @<:@default=enabled@:>@]),
-       [], [enable_keymap=yes])
-AS_IF([test "x$enable_keymap" = "xyes"], [
-       AC_PATH_PROG([GPERF], [gperf])
-       if test -z "$GPERF"; then
-              AC_MSG_ERROR([gperf is needed])
-       fi
-
-       AC_CHECK_HEADER([linux/input.h], [:], AC_MSG_ERROR([kernel headers not found]))
-       AC_SUBST([INCLUDE_PREFIX], [$(echo '#include <linux/input.h>' | eval $ac_cpp -E - | sed -n '/linux\/input.h/ {s:.*"\(.*\)/linux/input.h".*:\1:; p; q}')])
-])
-AM_CONDITIONAL([ENABLE_KEYMAP], [test "x$enable_keymap" = "xyes"])
-
-# ------------------------------------------------------------------------------
-# mtd_probe - autoloads FTL module for mtd devices
-# ------------------------------------------------------------------------------
-AC_ARG_ENABLE([mtd_probe],
-       AS_HELP_STRING([--disable-mtd_probe], [disable MTD support @<:@default=enabled@:>@]),
-       [], [enable_mtd_probe=yes])
-AM_CONDITIONAL([ENABLE_MTD_PROBE], [test "x$enable_mtd_probe" = "xyes"])
-
-# ------------------------------------------------------------------------------
-# rule_generator - persistent network and optical device rule generator
-# ------------------------------------------------------------------------------
-AC_ARG_ENABLE([rule_generator],
-       AS_HELP_STRING([--enable-rule_generator], [enable persistent network + cdrom links support @<:@default=disabled@:>@]),
-       [], [enable_rule_generator=no])
-AM_CONDITIONAL([ENABLE_RULE_GENERATOR], [test "x$enable_rule_generator" = "xyes"])
-
-# ------------------------------------------------------------------------------
-# create_floppy_devices - historical floppy kernel device nodes (/dev/fd0h1440, ...)
-# ------------------------------------------------------------------------------
-AC_ARG_ENABLE([floppy],
-       AS_HELP_STRING([--enable-floppy], [enable legacy floppy support @<:@default=disabled@:>@]),
-       [], [enable_floppy=no])
-AM_CONDITIONAL([ENABLE_FLOPPY], [test "x$enable_floppy" = "xyes"])
-
-my_CFLAGS="-Wall \
--Wmissing-declarations -Wmissing-prototypes \
--Wnested-externs -Wpointer-arith \
--Wpointer-arith -Wsign-compare -Wchar-subscripts \
--Wstrict-prototypes -Wshadow \
--Wformat-security -Wtype-limits"
-AC_SUBST([my_CFLAGS])
-
-AC_CONFIG_HEADERS(config.h)
-AC_CONFIG_FILES([
-       Makefile
-       src/docs/Makefile
-       src/docs/version.xml
-       src/gudev/docs/Makefile
-       src/gudev/docs/version.xml
-])
-
-AC_OUTPUT
-AC_MSG_RESULT([
-        $PACKAGE $VERSION
-        ========
-
-        prefix:                  ${prefix}
-        rootprefix:              ${rootprefix}
-        sysconfdir:              ${sysconfdir}
-        bindir:                  ${bindir}
-        libdir:                  ${libdir}
-        rootlibdir:              ${rootlib_execdir}
-        libexecdir:              ${libexecdir}
-        datarootdir:             ${datarootdir}
-        mandir:                  ${mandir}
-        includedir:              ${includedir}
-        include_prefix:          ${INCLUDE_PREFIX}
-        systemdsystemunitdir:    ${systemdsystemunitdir}
-        firmware path:           ${FIRMWARE_PATH}
-        usb.ids:                 ${USB_DATABASE}
-        pci.ids:                 ${PCI_DATABASE}
-
-        compiler:                ${CC}
-        cflags:                  ${CFLAGS}
-        ldflags:                 ${LDFLAGS}
-        xsltproc:                ${XSLTPROC}
-        gperf:                   ${GPERF}
-
-        logging:                 ${enable_logging}
-        debug:                   ${enable_debug}
-        selinux:                 ${with_selinux}
-
-        man pages                ${enable_manpages}
-        gudev:                   ${enable_gudev}
-        gintrospection:          ${enable_introspection}
-        keymap:                  ${enable_keymap}
-        mtd_probe:               ${enable_mtd_probe}
-        rule_generator:          ${enable_rule_generator}
-        floppy:                  ${enable_floppy}
-])
diff --git a/src/udev/docs/.gitignore b/src/udev/docs/.gitignore
new file mode 100644 (file)
index 0000000..1fb9c51
--- /dev/null
@@ -0,0 +1,18 @@
+Makefile
+libudev-overrides.txt
+html/
+tmpl/
+xml/
+*.stamp
+*.bak
+version.xml
+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
diff --git a/src/udev/docs/Makefile.am b/src/udev/docs/Makefile.am
new file mode 100644 (file)
index 0000000..7cd4f97
--- /dev/null
@@ -0,0 +1,99 @@
+## Process this file with automake to produce Makefile.in
+
+# We require automake 1.10 at least.
+AUTOMAKE_OPTIONS = 1.10
+
+# 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/udev
+
+# 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=--sgml-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=
+
+# 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/udev/libudev*.h
+CFILE_GLOB=$(top_srcdir)/src/udev/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
+
+# 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=
+
+# 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)/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
+#TESTS_ENVIRONMENT = cd $(srcsrc)
+#TESTS = $(GTKDOC_CHECK)
+endif
diff --git a/src/udev/docs/libudev-docs.xml b/src/udev/docs/libudev-docs.xml
new file mode 100644 (file)
index 0000000..b7feb45
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
+               "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
+[
+  <!ENTITY version SYSTEM "version.xml">
+]>
+<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
+  <bookinfo>
+    <title>libudev Reference Manual</title>
+    <releaseinfo>for libudev version &version;</releaseinfo>
+    <copyright>
+      <year>2009-2011</year>
+      <holder>Kay Sievers &lt;kay.sievers@vrfy.org&gt;</holder>
+    </copyright>
+  </bookinfo>
+
+  <chapter>
+    <title>libudev</title>
+    <xi:include href="xml/libudev.xml"/>
+    <xi:include href="xml/libudev-list.xml"/>
+    <xi:include href="xml/libudev-device.xml"/>
+    <xi:include href="xml/libudev-monitor.xml"/>
+    <xi:include href="xml/libudev-enumerate.xml"/>
+    <xi:include href="xml/libudev-queue.xml"/>
+    <xi:include href="xml/libudev-util.xml"/>
+  </chapter>
+
+  <index id="api-index-full">
+    <title>API Index</title>
+    <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
+  </index>
+</book>
diff --git a/src/udev/docs/libudev-sections.txt b/src/udev/docs/libudev-sections.txt
new file mode 100644 (file)
index 0000000..15c3e93
--- /dev/null
@@ -0,0 +1,127 @@
+<SECTION>
+<FILE>libudev</FILE>
+<TITLE>udev</TITLE>
+udev
+udev_ref
+udev_unref
+udev_new
+udev_set_log_fn
+udev_get_log_priority
+udev_set_log_priority
+udev_get_sys_path
+udev_get_dev_path
+udev_get_run_path
+udev_get_userdata
+udev_set_userdata
+</SECTION>
+
+<SECTION>
+<FILE>libudev-list</FILE>
+<TITLE>udev_list</TITLE>
+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
+</SECTION>
+
+<SECTION>
+<FILE>libudev-device</FILE>
+<TITLE>udev_device</TITLE>
+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_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_get_sysattr_list_entry
+udev_device_get_seqnum
+udev_device_get_usec_since_initialized
+udev_device_has_tag
+</SECTION>
+
+<SECTION>
+<FILE>libudev-monitor</FILE>
+<TITLE>udev_monitor</TITLE>
+udev_monitor
+udev_monitor_ref
+udev_monitor_unref
+udev_monitor_get_udev
+udev_monitor_new_from_netlink
+udev_monitor_new_from_socket
+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
+</SECTION>
+
+<SECTION>
+<FILE>libudev-enumerate</FILE>
+<TITLE>udev_enumerate</TITLE>
+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
+</SECTION>
+
+<SECTION>
+<FILE>libudev-queue</FILE>
+<TITLE>udev_queue</TITLE>
+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
+</SECTION>
+
+<SECTION>
+<FILE>libudev-util</FILE>
+<TITLE>udev_util</TITLE>
+udev_util_encode_string
+</SECTION>
diff --git a/src/udev/docs/libudev.types b/src/udev/docs/libudev.types
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/udev/docs/version.xml.in b/src/udev/docs/version.xml.in
new file mode 100644 (file)
index 0000000..d78bda9
--- /dev/null
@@ -0,0 +1 @@
+@VERSION@
diff --git a/src/udev/gudev/.gitignore b/src/udev/gudev/.gitignore
new file mode 100644 (file)
index 0000000..d20fa52
--- /dev/null
@@ -0,0 +1,9 @@
+gtk-doc.make
+docs/version.xml
+gudev-1.0.pc
+gudevenumtypes.c
+gudevenumtypes.h
+gudevmarshal.c
+gudevmarshal.h
+GUdev-1.0.gir
+GUdev-1.0.typelib
diff --git a/src/udev/gudev/docs/.gitignore b/src/udev/gudev/docs/.gitignore
new file mode 100644 (file)
index 0000000..5d7d73d
--- /dev/null
@@ -0,0 +1,17 @@
+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.stamp
+html/*
+xml/*
+tmpl/*
+*.stamp
diff --git a/src/udev/gudev/docs/Makefile.am b/src/udev/gudev/docs/Makefile.am
new file mode 100644 (file)
index 0000000..036ef43
--- /dev/null
@@ -0,0 +1,106 @@
+## Process this file with automake to produce Makefile.in
+
+# We require automake 1.10 at least.
+AUTOMAKE_OPTIONS = 1.10
+
+# 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/udev/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=--sgml-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=
+
+# 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/udev/gudev/*.h
+CFILE_GLOB=$(top_srcdir)/src/udev/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=
+
+# 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=
+
+# 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 = \
+        $(DBUS_GLIB_CFLAGS) \
+        $(GLIB_CFLAGS) \
+        -I$(top_srcdir)/src/udev/gudev \
+        -I$(top_builddir)/src/udev/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)/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
+#TESTS_ENVIRONMENT = cd $(srcsrc)
+#TESTS = $(GTKDOC_CHECK)
+endif
diff --git a/src/udev/gudev/docs/gudev-docs.xml b/src/udev/gudev/docs/gudev-docs.xml
new file mode 100644 (file)
index 0000000..f876c3b
--- /dev/null
@@ -0,0 +1,93 @@
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
+               "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
+<!ENTITY version SYSTEM "version.xml">
+]>
+<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
+  <bookinfo>
+    <title>GUDev Reference Manual</title>
+    <releaseinfo>For GUdev version &version;</releaseinfo>
+    <authorgroup>
+      <author>
+        <firstname>David</firstname>
+        <surname>Zeuthen</surname>
+        <affiliation>
+          <address>
+            <email>davidz@redhat.com</email>
+          </address>
+        </affiliation>
+      </author>
+      <author>
+        <firstname>Bastien</firstname>
+        <surname>Nocera</surname>
+        <affiliation>
+          <address>
+            <email>hadess@hadess.net</email>
+          </address>
+        </affiliation>
+      </author>
+    </authorgroup>
+
+    <copyright>
+      <year>2011</year>
+      <holder>The GUDev Authors</holder>
+    </copyright>
+
+    <legalnotice>
+      <para>
+        Permission is granted to copy, distribute and/or modify this
+        document under the terms of the <citetitle>GNU Free
+        Documentation License</citetitle>, Version 1.1 or any later
+        version published by the Free Software Foundation with no
+        Invariant Sections, no Front-Cover Texts, and no Back-Cover
+        Texts. You may obtain a copy of the <citetitle>GNU Free
+        Documentation License</citetitle> from the Free Software
+        Foundation by visiting <ulink type="http"
+        url="http://www.fsf.org">their Web site</ulink> or by writing
+        to:
+
+        <address>
+          The Free Software Foundation, Inc.,
+          <street>59 Temple Place</street> - Suite 330,
+          <city>Boston</city>, <state>MA</state> <postcode>02111-1307</postcode>,
+          <country>USA</country>
+        </address>
+      </para>
+
+      <para>
+        Many of the names used by companies to distinguish their
+        products and services are claimed as trademarks. Where those
+        names appear in any freedesktop.org documentation, and those
+        trademarks are made aware to the members of the
+        freedesktop.org Project, the names have been printed in caps
+        or initial caps.
+      </para>
+    </legalnotice>
+  </bookinfo>
+
+  <reference id="ref-API">
+    <title>API Reference</title>
+    <partintro>
+      <para>
+        This part presents the class and function reference for the
+        <literal>libgudev</literal> library.
+      </para>
+    </partintro>
+    <xi:include href="xml/gudevclient.xml"/>
+    <xi:include href="xml/gudevdevice.xml"/>
+    <xi:include href="xml/gudevenumerator.xml"/>
+  </reference>
+
+  <chapter id="gudev-hierarchy">
+    <title>Object Hierarchy</title>
+      <xi:include href="xml/tree_index.sgml"/>
+  </chapter>
+  <index>
+    <title>Index</title>
+  </index>
+  <index role="165">
+    <title>Index of new symbols in 165</title>
+    <xi:include href="xml/api-index-165.xml"><xi:fallback /></xi:include>
+  </index>
+
+</book>
diff --git a/src/udev/gudev/docs/gudev-sections.txt b/src/udev/gudev/docs/gudev-sections.txt
new file mode 100644 (file)
index 0000000..213e1a7
--- /dev/null
@@ -0,0 +1,113 @@
+<SECTION>
+<FILE>gudevclient</FILE>
+<TITLE>GUdevClient</TITLE>
+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
+<SUBSECTION Standard>
+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
+<SUBSECTION Private>
+GUdevClientPrivate
+</SECTION>
+
+<SECTION>
+<FILE>gudevdevice</FILE>
+<TITLE>GUdevDevice</TITLE>
+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
+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
+<SUBSECTION Standard>
+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
+<SUBSECTION Private>
+GUdevDevicePrivate
+</SECTION>
+
+<SECTION>
+<FILE>gudevenumerator</FILE>
+<TITLE>GUdevEnumerator</TITLE>
+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
+<SUBSECTION Standard>
+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
+<SUBSECTION Private>
+GUdevEnumeratorPrivate
+</SECTION>
+
+<SECTION>
+<FILE>gudevmarshal</FILE>
+<SUBSECTION Private>
+g_udev_marshal_VOID__STRING_OBJECT
+</SECTION>
+
+<SECTION>
+<FILE>gudevenumtypes</FILE>
+<SUBSECTION Private>
+G_TYPE_UDEV_DEVICE_TYPE
+g_udev_device_type_get_type
+</SECTION>
diff --git a/src/udev/gudev/docs/gudev.types b/src/udev/gudev/docs/gudev.types
new file mode 100644 (file)
index 0000000..a89857a
--- /dev/null
@@ -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/src/udev/gudev/docs/version.xml.in b/src/udev/gudev/docs/version.xml.in
new file mode 100644 (file)
index 0000000..d78bda9
--- /dev/null
@@ -0,0 +1 @@
+@VERSION@
diff --git a/src/udev/gudev/gjs-example.js b/src/udev/gudev/gjs-example.js
new file mode 100755 (executable)
index 0000000..5586fd6
--- /dev/null
@@ -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/udev/gudev/gudev-1.0.pc.in b/src/udev/gudev/gudev-1.0.pc.in
new file mode 100644 (file)
index 0000000..058262d
--- /dev/null
@@ -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/udev/gudev/gudev.h b/src/udev/gudev/gudev.h
new file mode 100644 (file)
index 0000000..a313460
--- /dev/null
@@ -0,0 +1,33 @@
+/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __G_UDEV_H__
+#define __G_UDEV_H__
+
+#define _GUDEV_INSIDE_GUDEV_H 1
+#include <gudev/gudevenums.h>
+#include <gudev/gudevenumtypes.h>
+#include <gudev/gudevtypes.h>
+#include <gudev/gudevclient.h>
+#include <gudev/gudevdevice.h>
+#include <gudev/gudevenumerator.h>
+#undef _GUDEV_INSIDE_GUDEV_H
+
+#endif /* __G_UDEV_H__ */
diff --git a/src/udev/gudev/gudevclient.c b/src/udev/gudev/gudevclient.c
new file mode 100644 (file)
index 0000000..2b94102
--- /dev/null
@@ -0,0 +1,527 @@
+/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008-2010 David Zeuthen <davidz@redhat.com>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#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
+ * <literal>sysfs</literal> filesystem) and the udev daemon (through a
+ * <literal>tmpfs</literal> 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
+   * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
+   * 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
+ * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
+ * 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/udev/gudev/gudevclient.h b/src/udev/gudev/gudevclient.h
new file mode 100644 (file)
index 0000000..b425d03
--- /dev/null
@@ -0,0 +1,100 @@
+/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H)
+#error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents."
+#endif
+
+#ifndef __G_UDEV_CLIENT_H__
+#define __G_UDEV_CLIENT_H__
+
+#include <gudev/gudevtypes.h>
+
+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/udev/gudev/gudevdevice.c b/src/udev/gudev/gudevdevice.c
new file mode 100644 (file)
index 0000000..62a26f9
--- /dev/null
@@ -0,0 +1,963 @@
+/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#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(),
+ * 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 **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->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 <literal>/dev</literal>) 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:
+ * @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/udev/gudev/gudevdevice.h b/src/udev/gudev/gudevdevice.h
new file mode 100644 (file)
index 0000000..d4873ba
--- /dev/null
@@ -0,0 +1,128 @@
+/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H)
+#error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents."
+#endif
+
+#ifndef __G_UDEV_DEVICE_H__
+#define __G_UDEV_DEVICE_H__
+
+#include <gudev/gudevtypes.h>
+
+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        *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/udev/gudev/gudevenumerator.c b/src/udev/gudev/gudevenumerator.c
new file mode 100644 (file)
index 0000000..db09074
--- /dev/null
@@ -0,0 +1,431 @@
+/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008-2010 David Zeuthen <davidz@redhat.com>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#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/udev/gudev/gudevenumerator.h b/src/udev/gudev/gudevenumerator.h
new file mode 100644 (file)
index 0000000..3fddccf
--- /dev/null
@@ -0,0 +1,107 @@
+/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008-2010 David Zeuthen <davidz@redhat.com>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H)
+#error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents."
+#endif
+
+#ifndef __G_UDEV_ENUMERATOR_H__
+#define __G_UDEV_ENUMERATOR_H__
+
+#include <gudev/gudevtypes.h>
+
+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/udev/gudev/gudevenums.h b/src/udev/gudev/gudevenums.h
new file mode 100644 (file)
index 0000000..c3a0aa8
--- /dev/null
@@ -0,0 +1,49 @@
+/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H)
+#error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents."
+#endif
+
+#ifndef __G_UDEV_ENUMS_H__
+#define __G_UDEV_ENUMS_H__
+
+#include <glib-object.h>
+
+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/udev/gudev/gudevenumtypes.c.template b/src/udev/gudev/gudevenumtypes.c.template
new file mode 100644 (file)
index 0000000..fc30b39
--- /dev/null
@@ -0,0 +1,39 @@
+/*** BEGIN file-header ***/
+#include <gudev.h>
+
+/*** 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/udev/gudev/gudevenumtypes.h.template b/src/udev/gudev/gudevenumtypes.h.template
new file mode 100644 (file)
index 0000000..d0ab339
--- /dev/null
@@ -0,0 +1,24 @@
+/*** BEGIN file-header ***/
+#ifndef __GUDEV_ENUM_TYPES_H__
+#define __GUDEV_ENUM_TYPES_H__
+
+#include <glib-object.h>
+
+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/udev/gudev/gudevmarshal.list b/src/udev/gudev/gudevmarshal.list
new file mode 100644 (file)
index 0000000..7e66599
--- /dev/null
@@ -0,0 +1 @@
+VOID:STRING,OBJECT
diff --git a/src/udev/gudev/gudevprivate.h b/src/udev/gudev/gudevprivate.h
new file mode 100644 (file)
index 0000000..8866f52
--- /dev/null
@@ -0,0 +1,41 @@
+/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H)
+#error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents."
+#endif
+
+#ifndef __G_UDEV_PRIVATE_H__
+#define __G_UDEV_PRIVATE_H__
+
+#include <gudev/gudevtypes.h>
+
+#include <libudev.h>
+
+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/udev/gudev/gudevtypes.h b/src/udev/gudev/gudevtypes.h
new file mode 100644 (file)
index 0000000..8884827
--- /dev/null
@@ -0,0 +1,51 @@
+/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H)
+#error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents."
+#endif
+
+#ifndef __G_UDEV_TYPES_H__
+#define __G_UDEV_TYPES_H__
+
+#include <gudev/gudevenums.h>
+#include <sys/types.h>
+
+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/udev/gudev/seed-example-enum.js b/src/udev/gudev/seed-example-enum.js
new file mode 100755 (executable)
index 0000000..66206ad
--- /dev/null
@@ -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/udev/gudev/seed-example.js b/src/udev/gudev/seed-example.js
new file mode 100755 (executable)
index 0000000..e2ac324
--- /dev/null
@@ -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/udev/keymap/.gitignore b/src/udev/keymap/.gitignore
new file mode 100644 (file)
index 0000000..4567584
--- /dev/null
@@ -0,0 +1,5 @@
+keyboard-force-release.sh
+keys-from-name.gperf
+keys-from-name.h
+keys-to-name.h
+keys.txt
diff --git a/src/udev/keymap/95-keyboard-force-release.rules b/src/udev/keymap/95-keyboard-force-release.rules
new file mode 100644 (file)
index 0000000..03d56e8
--- /dev/null
@@ -0,0 +1,54 @@
+# Set model specific atkbd force_release quirk
+#
+# Several laptops have hotkeys which don't generate release events,
+# which can cause problems with software key repeat.
+# The atkbd driver has a quirk handler for generating synthetic
+# release events, which can be configured via sysfs since 2.6.32.
+# Simply add a file with a list of scancodes for your laptop model
+# in /usr/lib/udev/keymaps, and add a rule here.
+# If the hotkeys also need a keymap assignment you can copy the
+# scancodes from the keymap file, otherwise you can run
+# /usr/lib/udev/keymap -i /dev/input/eventX
+# on a Linux vt to find out.
+
+ACTION=="remove", GOTO="force_release_end"
+SUBSYSTEM!="serio", GOTO="force_release_end"
+KERNEL!="serio*", GOTO="force_release_end"
+DRIVER!="atkbd", GOTO="force_release_end"
+
+ENV{DMI_VENDOR}="$attr{[dmi/id]sys_vendor}"
+
+ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", RUN+="keyboard-force-release.sh $devpath samsung-other"
+ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", ATTR{[dmi/id]product_name}=="*90X3A*", RUN+="keyboard-force-release.sh $devpath samsung-90x3a"
+
+ENV{DMI_VENDOR}=="Dell Inc.", ATTR{[dmi/id]product_name}=="Studio 1557|Studio 1558", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
+ENV{DMI_VENDOR}=="Dell Inc.", ATTR{[dmi/id]product_name}=="Latitude E*|Precision M*", RUN+="keyboard-force-release.sh $devpath dell-touchpad"
+
+ENV{DMI_VENDOR}=="FUJITSU SIEMENS", ATTR{[dmi/id]product_name}=="AMILO Si 1848+u|AMILO Xi 2428", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
+
+ENV{DMI_VENDOR}=="FOXCONN", ATTR{[dmi/id]product_name}=="QBOOK", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
+
+ENV{DMI_VENDOR}=="MTC", ATTR{[dmi/id]product_version}=="A0", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
+
+ENV{DMI_VENDOR}=="PEGATRON CORP.", ATTR{[dmi/id]product_name}=="Spring Peak", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
+
+ENV{DMI_VENDOR}=="TOSHIBA", ATTR{[dmi/id]product_name}=="Satellite [uU]300*|Satellite Pro [uU]300*|Satellite [uU]305*|SATELLITE [uU]500*", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
+
+ENV{DMI_VENDOR}=="Viooo Corporation", ATTR{[dmi/id]product_name}=="PT17", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
+
+# These are all the HP laptops that setup a touchpad toggle key
+ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*[pP][aA][vV][iI][lL][iI][oO][nN]*", RUN+="keyboard-force-release.sh $devpath hp-other"
+ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*[tT][xX]2*", RUN+="keyboard-force-release.sh $devpath hp-other"
+ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*2510p*|*2530p*|HP G60 Notebook PC", RUN+="keyboard-force-release.sh $devpath hp-other"
+
+ENV{DMI_VENDOR}=="Zepto", ATTR{[dmi/id]product_name}=="Znote 6615WD", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
+
+ENV{DMI_VENDOR}=="Zepto", ATTR{[dmi/id]product_name}=="Znote", ATTR{[dmi/id]product_version}=="6625WD", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
+
+ENV{DMI_VENDOR}=="HANNspree", ATTR{[dmi/id]product_name}=="SN10E100", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
+
+ENV{DMI_VENDOR}=="GIGABYTE", ATTR{[dmi/id]product_name}=="i1520M", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
+
+ENV{DMI_VENDOR}=="BenQ", ATTR{[dmi/id]product_name}=="*nScreen*", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
+
+LABEL="force_release_end"
diff --git a/src/udev/keymap/95-keymap.rules b/src/udev/keymap/95-keymap.rules
new file mode 100644 (file)
index 0000000..bbf311a
--- /dev/null
@@ -0,0 +1,170 @@
+# Set model specific hotkey keycodes.
+#
+# Key map overrides can be specified by either giving scancode/keyname pairs
+# directly as keymap arguments (if there are just one or two to change), or as
+# a file name (in /usr/lib/udev/keymaps), which has to contain scancode/keyname
+# pairs.
+
+ACTION=="remove", GOTO="keyboard_end"
+KERNEL!="event*", GOTO="keyboard_end"
+ENV{ID_INPUT_KEY}=="", GOTO="keyboard_end"
+SUBSYSTEMS=="bluetooth", GOTO="keyboard_end"
+
+SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id"
+SUBSYSTEMS=="usb", GOTO="keyboard_usbcheck"
+GOTO="keyboard_modulecheck"
+
+#
+# The following are external USB keyboards
+#
+
+LABEL="keyboard_usbcheck"
+
+ENV{ID_VENDOR}=="Genius", ENV{ID_MODEL_ID}=="0708", ENV{ID_USB_INTERFACE_NUM}=="01", RUN+="keymap $name genius-slimstar-320"
+ENV{ID_VENDOR}=="Logitech*", ATTRS{name}=="Logitech USB Multimedia Keyboard", RUN+="keymap $name logitech-wave"
+ENV{ID_VENDOR}=="Logitech*", ATTRS{name}=="Logitech USB Receiver", RUN+="keymap $name logitech-wave-cordless"
+# Logitech Cordless Wave Pro looks slightly weird; some hotkeys are coming through the mouse interface
+ENV{ID_VENDOR_ID}=="046d", ENV{ID_MODEL_ID}=="c52[9b]", ATTRS{name}=="Logitech USB Receiver", RUN+="keymap $name logitech-wave-pro-cordless"
+
+ENV{ID_VENDOR}=="Lite-On_Technology_Corp*", ATTRS{name}=="Lite-On Technology Corp. ThinkPad USB Keyboard with TrackPoint", RUN+="keymap $name lenovo-thinkpad-usb-keyboard-trackpoint"
+ENV{ID_VENDOR_ID}=="04b3", ENV{ID_MODEL_ID}=="301[89]", RUN+="keymap $name ibm-thinkpad-usb-keyboard-trackpoint"
+
+ENV{ID_VENDOR}=="Microsoft", ENV{ID_MODEL_ID}=="00db", RUN+="keymap $name 0xc022d zoomin 0xc022e zoomout"
+
+GOTO="keyboard_end"
+
+#
+# The following are exposed as separate input devices with low key codes, thus
+# we need to check their input device product name
+#
+
+LABEL="keyboard_modulecheck"
+
+ENV{DMI_VENDOR}="$attr{[dmi/id]sys_vendor}"
+ENV{DMI_VENDOR}=="", GOTO="keyboard_end"
+
+ENV{DMI_VENDOR}=="LENOVO*", KERNELS=="input*", ATTRS{name}=="ThinkPad Extra Buttons", RUN+="keymap $name module-lenovo"
+ENV{DMI_VENDOR}=="LENOVO*", KERNELS=="input*", ATTRS{name}=="Lenovo ThinkPad SL Series extra buttons", RUN+="keymap $name 0x0E bluetooth"
+
+ENV{DMI_VENDOR}=="ASUS*", KERNELS=="input*", ATTRS{name}=="Asus Extra Buttons", ATTR{[dmi/id]product_name}=="W3J", RUN+="keymap $name module-asus-w3j"
+ENV{DMI_VENDOR}=="ASUS*", KERNELS=="input*", ATTRS{name}=="Eee PC WMI hotkeys|Asus Laptop Support|Asus*WMI*", RUN+="keymap $name 0x6B f21"
+ENV{DMI_VENDOR}=="ASUS*", KERNELS=="input*", ATTRS{name}=="Eee PC Hotkey Driver", RUN+="keymap $name 0x37 f21"
+
+ENV{DMI_VENDOR}=="IBM*", KERNELS=="input*", ATTRS{name}=="ThinkPad Extra Buttons", RUN+="keymap $name module-ibm"
+ENV{DMI_VENDOR}=="Sony*", KERNELS=="input*", ATTRS{name}=="Sony Vaio Keys", RUN+="keymap $name module-sony"
+ENV{DMI_VENDOR}=="Acer*", KERNELS=="input*", ATTRS{name}=="Acer WMI hotkeys", RUN+="keymap $name 0x82 f21"
+ENV{DMI_VENDOR}=="MICRO-STAR*|Micro-Star*", KERNELS=="input*", ATTRS{name}=="MSI Laptop hotkeys", RUN+="keymap $name 0x213 f22 0x214 f23"
+
+# Older Vaios have some different keys
+ENV{DMI_VENDOR}=="Sony*", ATTR{[dmi/id]product_name}=="*PCG-C1*|*PCG-K25*|*PCG-F1*|*PCG-F2*|*PCG-F3*|*PCG-F4*|*PCG-F5*|*PCG-F6*|*PCG-FX*|*PCG-FRV*|*PCG-GR*|*PCG-TR*|*PCG-NV*|*PCG-Z*|*VGN-S360*", ATTRS{name}=="Sony Vaio Keys", RUN+="keymap $name module-sony-old"
+
+# Some Sony VGN models have yet another one
+ENV{DMI_VENDOR}=="Sony*", ATTR{[dmi/id]product_name}=="VGN-AR71*|VGN-FW*|VGN-Z21*", ATTRS{name}=="Sony Vaio Keys", RUN+="keymap $name module-sony-vgn"
+
+
+#
+# The following rules belong to standard i8042 AT keyboard with high key codes.
+#
+
+DRIVERS=="atkbd", GOTO="keyboard_vendorcheck"
+GOTO="keyboard_end"
+
+LABEL="keyboard_vendorcheck"
+
+ENV{DMI_VENDOR}=="Dell*", RUN+="keymap $name dell"
+ENV{DMI_VENDOR}=="Dell*", ATTR{[dmi/id]product_name}=="Inspiron 910|Inspiron 1010|Inspiron 1011|Inspiron 1012|Inspiron 1110|Inspiron 1210", RUN+="keymap $name 0x84 wlan"
+ENV{DMI_VENDOR}=="Dell*", ATTR{[dmi/id]product_name}=="Latitude XT2", RUN+="keymap $name dell-latitude-xt2"
+
+ENV{DMI_VENDOR}=="Compaq*", ATTR{[dmi/id]product_name}=="*E500*|*Evo N*", RUN+="keymap $name compaq-e_evo"
+
+ENV{DMI_VENDOR}=="LENOVO*", ATTR{[dmi/id]product_version}=="*3000*", RUN+="keymap $name lenovo-3000"
+ENV{DMI_VENDOR}=="LENOVO*", ATTR{[dmi/id]product_version}=="ThinkPad X6*", ATTR{[dmi/id]product_version}=="* Tablet", RUN+="keymap $name lenovo-thinkpad_x6_tablet"
+ENV{DMI_VENDOR}=="LENOVO*", ATTR{[dmi/id]product_version}=="ThinkPad X2[02]* Tablet*", ATTR{[dmi/id]product_version}=="* Tablet", RUN+="keymap $name lenovo-thinkpad_x200_tablet"
+ENV{DMI_VENDOR}=="LENOVO*", ATTR{[dmi/id]product_version}=="*IdeaPad*", RUN+="keymap $name lenovo-ideapad"
+ENV{DMI_VENDOR}=="LENOVO*", ATTR{[dmi/id]product_name}=="S10-*", RUN+="keymap $name lenovo-ideapad"
+ENV{DMI_VENDOR}=="LENOVO", ATTR{[dmi/id]product_version}=="*IdeaPad Y550*", RUN+="keymap $name 0x95 media 0xA3 play"
+
+ENV{DMI_VENDOR}=="Hewlett-Packard*", RUN+="keymap $name hewlett-packard"
+ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*[tT][aA][bB][lL][eE][tT]*", RUN+="keymap $name hewlett-packard-tablet"
+ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*[pP][aA][vV][iI][lL][iI][oO][nN]*", RUN+="keymap $name hewlett-packard-pavilion"
+ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*Compaq*|*EliteBook*|*2230s*", RUN+="keymap $name hewlett-packard-compaq_elitebook"
+ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*2510p*|*2530p*|HP G60 Notebook PC", RUN+="keymap $name hewlett-packard-2510p_2530p"
+ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*[tT][xX]2*", RUN+="keymap $name hewlett-packard-tx2"
+ENV{DMI_VENDOR}=="Hewlett-Packard", ATTR{[dmi/id]product_name}=="Presario 2100*", RUN+="keymap $name hewlett-packard-presario-2100"
+ENV{DMI_VENDOR}=="Hewlett-Packard", ATTR{[dmi/id]product_name}=="HP G62 Notebook PC", RUN+="keymap $name 0xB2 www"
+ENV{DMI_VENDOR}=="Hewlett-Packard", ATTR{[dmi/id]product_name}=="HP ProBook*", RUN+="keymap $name 0xF8 rfkill"
+# HP Pavillion dv6315ea has empty DMI_VENDOR
+ATTR{[dmi/id]board_vendor}=="Quanta", ATTR{[dmi/id]board_name}=="30B7", ATTR{[dmi/id]board_version}=="65.2B", RUN+="keymap $name 0x88 media" # "quick play
+
+# Gateway clone of Acer Aspire One AOA110/AOA150
+ENV{DMI_VENDOR}=="Gateway*", ATTR{[dmi/id]product_name}=="*AOA1*", RUN+="keymap $name acer"
+
+ENV{DMI_VENDOR}=="Acer*", RUN+="keymap $name acer"
+ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="Extensa*", ATTR{[dmi/id]product_name}=="*5210*|*5220*|*5610*|*5620*|*5720*", RUN+="keymap $name 0xEE screenlock"
+ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="TravelMate*C3[01]0*", RUN+="keymap $name acer-travelmate_c300"
+ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="TravelMate*6292*|TravelMate*8471*|TravelMate*4720*|TravelMate*7720*|Aspire 1810T*|AO751h|AO531h", RUN+="keymap $name 0xD9 bluetooth"
+ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="TravelMate*4720*", RUN+="keymap $name 0xB2 www 0xEE screenlock"
+ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="TravelMate 6593|Aspire 1640", RUN+="keymap $name 0xB2 www 0xEE screenlock"
+ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="Aspire 6920", RUN+="keymap $name acer-aspire_6920"
+ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="Aspire 5920G", RUN+="keymap $name acer-aspire_5920g"
+ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="Aspire 5720*", RUN+="keymap $name acer-aspire_5720"
+ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="Aspire 8930", RUN+="keymap $name acer-aspire_8930"
+ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_serial}=="ZG8*", RUN+="keymap $name acer-aspire_5720"
+
+ENV{DMI_VENDOR}=="*BenQ*", ATTR{[dmi/id]product_name}=="*Joybook R22*", RUN+="keymap $name 0x6E wlan"
+
+ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="*AMILO Pro V3205*", RUN+="keymap $name fujitsu-amilo_pro_v3205"
+ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="*AMILO Pa 2548*", RUN+="keymap $name fujitsu-amilo_pa_2548"
+ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="*ESPRIMO Mobile V5*", RUN+="keymap $name fujitsu-esprimo_mobile_v5"
+ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="*ESPRIMO Mobile V6*", RUN+="keymap $name fujitsu-esprimo_mobile_v6"
+ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="*AMILO Pro Edition V3505*", RUN+="keymap $name fujitsu-amilo_pro_edition_v3505"
+ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="*Amilo Si 1520*", RUN+="keymap $name fujitsu-amilo_si_1520"
+ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="AMILO*M*", RUN+="keymap $name 0x97 prog2 0x9F prog1"
+ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="Amilo Li 1718", RUN+="keymap $name 0xD6 wlan"
+ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="AMILO Li 2732", RUN+="keymap $name fujitsu-amilo_li_2732"
+
+ENV{DMI_VENDOR}=="LG*", ATTR{[dmi/id]product_name}=="*X110*", RUN+="keymap $name lg-x110"
+
+ENV{DMI_VENDOR}=="MEDION*", ATTR{[dmi/id]product_name}=="*FID2060*", RUN+="keymap $name medion-fid2060"
+ENV{DMI_VENDOR}=="MEDIONNB", ATTR{[dmi/id]product_name}=="A555*", RUN+="keymap $name medionnb-a555"
+
+ENV{DMI_VENDOR}=="MICRO-STAR*|Micro-Star*", RUN+="keymap $name micro-star"
+
+# some MSI models generate ACPI/input events on the LNXVIDEO input devices,
+# plus some extra synthesized ones on atkbd as an echo of actually changing the
+# brightness; so ignore those atkbd ones, to avoid loops
+ENV{DMI_VENDOR}=="MICRO-STAR*", ATTR{[dmi/id]product_name}=="*U-100*|*U100*|*N033", RUN+="keymap $name 0xF7 reserved 0xF8 reserved"
+
+ENV{DMI_VENDOR}=="INVENTEC", ATTR{[dmi/id]product_name}=="SYMPHONY 6.0/7.0", RUN+="keymap $name inventec-symphony_6.0_7.0"
+
+ENV{DMI_VENDOR}=="MAXDATA", ATTR{[dmi/id]product_name}=="Pro 7000*", RUN+="keymap $name maxdata-pro_7000"
+
+ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", RUN+="keymap $name samsung-other"
+ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", ATTR{[dmi/id]product_name}=="*SX20S*", RUN+="keymap $name samsung-sx20s"
+ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", ATTR{[dmi/id]product_name}=="SQ1US", RUN+="keymap $name samsung-sq1us"
+ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", ATTR{[dmi/id]product_name}=="*700Z*", RUN+="keymap $name 0xBA ejectcd 0x96 keyboardbrightnessup 0x97 keyboardbrightnessdown"
+ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", ATTR{[dmi/id]product_name}=="*90X3A*", RUN+="keymap $name samsung-90x3a"
+
+ENV{DMI_VENDOR}=="TOSHIBA", ATTR{[dmi/id]product_name}=="SATELLITE A100", RUN+="keymap $name toshiba-satellite_a100"
+ENV{DMI_VENDOR}=="TOSHIBA", ATTR{[dmi/id]product_name}=="Satellite A110", RUN+="keymap $name toshiba-satellite_a110"
+ENV{DMI_VENDOR}=="TOSHIBA", ATTR{[dmi/id]product_name}=="Satellite M30X", RUN+="keymap $name toshiba-satellite_m30x"
+
+ENV{DMI_VENDOR}=="OQO Inc.*", ATTR{[dmi/id]product_name}=="OQO Model 2*", RUN+="keymap $name oqo-model2"
+
+ENV{DMI_VENDOR}=="ONKYO CORPORATION", ATTR{[dmi/id]product_name}=="ONKYOPC", RUN+="keymap $name onkyo"
+
+ENV{DMI_VENDOR}=="ASUS", RUN+="keymap $name asus"
+
+ENV{DMI_VENDOR}=="VIA", ATTR{[dmi/id]product_name}=="K8N800", ATTR{[dmi/id]product_version}=="VT8204B", RUN+="keymap $name 0x81 prog1"
+
+ENV{DMI_VENDOR}=="Zepto", ATTR{[dmi/id]product_name}=="Znote", ATTR{[dmi/id]product_version}=="62*|63*", RUN+="keymap $name zepto-znote"
+
+ENV{DMI_VENDOR}=="Everex", ATTR{[dmi/id]product_name}=="XT5000*", RUN+="keymap $name everex-xt5000"
+
+ENV{DMI_VENDOR}=="COMPAL", ATTR{[dmi/id]product_name}=="HEL80I", RUN+="keymap $name 0x84 wlan"
+
+ENV{DMI_VENDOR}=="OLPC", ATTR{[dmi/id]product_name}=="XO", RUN+="keymap $name olpc-xo"
+
+ENV{DMI_VENDOR}=="Alienware*", ATTR{[dmi/id]product_name}=="M14xR1", RUN+="keymap $name 0x8A ejectcd"
+
+LABEL="keyboard_end"
diff --git a/src/udev/keymap/README.keymap.txt b/src/udev/keymap/README.keymap.txt
new file mode 100644 (file)
index 0000000..52d50ed
--- /dev/null
@@ -0,0 +1,101 @@
+= The udev keymap tool =
+
+== Introduction ==
+
+This udev extension configures computer model specific key mappings. This is
+particularly necessary for the non-standard extra keys found on many laptops,
+such as "brightness up", "next song", "www browser", or "suspend". Often these
+are accessed with the Fn key.
+
+Every key produces a "scan code", which is highly vendor/model specific for the
+nonstandard keys. This tool maintains mappings for these scan codes to standard
+"key codes", which denote the "meaning" of the key. The key codes are defined
+in /usr/include/linux/input.h.
+
+If some of your keys on your keyboard are not working at all, or produce the
+wrong effect, then a very likely cause of this is that the scan code -> key
+code mapping is incorrect on your computer.
+
+== Structure ==
+
+udev-keymap consists of the following parts:
+
+ keymaps/*:: mappings of scan codes to key code names
+
+ 95-keymap.rules:: udev rules for mapping system vendor/product names and
+ input module names to one of the keymaps above
+
+ keymap:: manipulate an evdev input device:
+  * write a key map file into a device (used by udev rules)
+  * dump current scan → key code mapping
+  * interactively display scan and key codes of pressed keys
+
+ findkeyboards:: display evdev input devices which belong to actual keyboards,
+ i. e. those suitable for the keymap program
+
+ fdi2rules.py:: convert hal keymap FDIs into udev rules and key map files
+ (Please note that this is far from perfect, since the mapping between fdi and
+  udev rules is not straightforward, and impossible in some cases.)
+
+== Fixing broken keys ==
+
+In order to make a broken key work on your system and send it back to upstream
+for inclusion you need to do the following steps:
+
+ 1. Find the keyboard device.
+
+ Run /usr/lib/udev/findkeyboards. This should always give you an "AT
+ keyboard" and possibly a "module". Some laptops (notably Thinkpads, Sonys, and
+ Acers) have multimedia/function keys on a separate input device instead of the
+ primary keyboard. The keyboard device should have a name like "input/event3".
+ In the following commands, the name will be written as "input/eventX" (replace
+ X with the appropriate number).
+
+ 2. Find broken scan codes:
+
+ sudo /usr/lib/udev/keymap -i input/eventX
+
+ Press all multimedia/function keys and check if the key name that gets printed
+ out is plausible. If it is unknown or wrong, write down the scan code (looks
+ like "0x1E") and the intended functionality of this key. Look in
+ /usr/include/linux/input.h for an available KEY_XXXXX constant which most
+ closely approximates this functionality and write it down as the new key code.
+
+ For example, you might press a key labeled "web browser" which currently
+ produces "unknown". Note down this:
+
+   0x1E www # Fn+F2 web browser
+
+ Repeat that for all other keys. Write the resulting list into a file. Look at
+ /usr/lib/udev/keymaps/ for existing key map files and make sure that you use the
+ same structure.
+
+ If the key only ever works once and then your keyboard (or the entire desktop)
+ gets stuck for a long time, then it is likely that the BIOS fails to send a
+ corresponding "key release" event after the key press event. Please note down
+ this case as well, as it can be worked around in
+ /usr/lib/udev/keymaps/95-keyboard-force-release.rules .
+
+ 3. Find out your system vendor and product:
+
+ cat /sys/class/dmi/id/sys_vendor
+ cat /sys/class/dmi/id/product_name
+
+ 4. Generate a device dump with "udevadm info --export-db > /tmp/udev-db.txt".
+
+ 6. Send the system vendor/product names, the key mapping from step 2,
+ and /tmp/udev-db.txt from step 4 to the linux-hotplug@vger.kernel.org mailing
+ list, so that they can be included in the next release.
+
+For local testing, copy your map file to /usr/lib/udev/keymaps/ with an appropriate
+name, and add an appropriate udev rule to /usr/lib/udev/rules.d/95-keymap.rules:
+
+  * If you selected an "AT keyboard", add the rule to the section after
+  'LABEL="keyboard_vendorcheck"'.
+
+  * If you selected a "module", add the rule to the top section where the
+  "ThinkPad Extra Buttons" are.
+
+== Author ==
+
+keymap is written and maintained by Martin Pitt <martin.pitt@ubuntu.com>.
diff --git a/src/udev/keymap/check-keymaps.sh b/src/udev/keymap/check-keymaps.sh
new file mode 100755 (executable)
index 0000000..405168c
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+# check that all key names in keymaps/* are known in <linux/input.h>
+# and that all key maps listed in the rules are valid and present in
+# Makefile.am
+SRCDIR=${1:-.}
+KEYLIST=${2:-src/keymap/keys.txt}
+KEYMAPS_DIR=$SRCDIR/src/keymap/keymaps
+RULES=$SRCDIR/src/keymap/95-keymap.rules
+
+[ -e "$KEYLIST" ] || {
+        echo "need $KEYLIST please build first" >&2
+        exit 1
+}
+
+missing=$(join -v 2 <(awk '{print tolower(substr($1,5))}' $KEYLIST | sort -u) \
+                    <(grep -hv '^#' ${KEYMAPS_DIR}/*| awk '{print $2}' | sort -u))
+[ -z "$missing" ] || {
+        echo "ERROR: unknown key names in src/keymap/keymaps/*:" >&2
+        echo "$missing" >&2
+        exit 1
+}
+
+# check that all maps referred to in $RULES exist
+maps=$(sed -rn '/keymap \$name/ { s/^.*\$name ([^"[:space:]]+).*$/\1/; p }' $RULES)
+for m in $maps; do
+        # ignore inline mappings
+        [ "$m" = "${m#0x}" ] || continue
+
+        [ -e ${KEYMAPS_DIR}/$m ] || {
+                echo "ERROR: unknown map name in $RULES: $m" >&2
+                exit 1
+        }
+        grep -q "src/keymap/keymaps/$m\>" $SRCDIR/Makefile.am || {
+                echo "ERROR: map file $m is not added to Makefile.am" >&2
+                exit 1
+        }
+done
diff --git a/src/udev/keymap/findkeyboards b/src/udev/keymap/findkeyboards
new file mode 100755 (executable)
index 0000000..9ce2742
--- /dev/null
@@ -0,0 +1,68 @@
+#!/bin/sh -e
+# Find "real" keyboard devices and print their device path.
+# Author: Martin Pitt <martin.pitt@ubuntu.com>
+#
+# Copyright (C) 2009, Canonical Ltd.
+#
+# 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.
+
+# returns OK if $1 contains $2
+strstr() {
+        [ "${1#*$2*}" != "$1" ]
+}
+
+# returns OK if $1 contains $2 at the beginning
+str_starts() {
+        [ "${1#$2*}" != "$1" ]
+}
+
+str_line_starts() {
+        while read a; do str_starts "$a" "$1" && return 0;done
+        return 1;
+}
+
+# print a list of input devices which are keyboard-like
+keyboard_devices() {
+        # standard AT keyboard
+        for dev in `udevadm trigger --dry-run --verbose --property-match=ID_INPUT_KEYBOARD=1`; do
+                walk=`udevadm info --attribute-walk --path=$dev`
+                env=`udevadm info --query=env --path=$dev`
+                # filter out non-event devices, such as the parent input devices which have no devnode
+                if ! echo "$env" | str_line_starts 'DEVNAME='; then
+                        continue
+                fi
+                if strstr "$walk" 'DRIVERS=="atkbd"'; then
+                        echo -n 'AT keyboard: '
+                elif echo "$env" | str_line_starts 'ID_USB_DRIVER=usbhid'; then
+                        echo -n 'USB keyboard: '
+                else
+                        echo -n 'Unknown type: '
+               fi
+                       udevadm info --query=name --path=$dev
+        done
+
+        # modules
+        module=$(udevadm trigger --verbose --dry-run --subsystem-match=input --attr-match=name='*Extra Buttons')
+        module="$module
+        $(udevadm trigger --verbose --dry-run --subsystem-match=input --attr-match=name='*extra buttons')"
+        module="$module
+        $(udevadm trigger --verbose --dry-run --subsystem-match=input --attr-match=name='Sony Vaio Keys')"
+        for m in $module; do
+                for evdev in $m/event*/dev; do
+                        if [ -e "$evdev" ]; then
+                                echo -n 'module: '
+                                udevadm info --query=name --path=${evdev%%/dev}
+                        fi
+                done
+        done
+}
+
+keyboard_devices
diff --git a/src/udev/keymap/force-release-maps/common-volume-keys b/src/udev/keymap/force-release-maps/common-volume-keys
new file mode 100644 (file)
index 0000000..3a7654d
--- /dev/null
@@ -0,0 +1,3 @@
+0xa0 #mute
+0xae #volume down
+0xb0 #volume up
diff --git a/src/udev/keymap/force-release-maps/dell-touchpad b/src/udev/keymap/force-release-maps/dell-touchpad
new file mode 100644 (file)
index 0000000..18e9bde
--- /dev/null
@@ -0,0 +1 @@
+0x9E
diff --git a/src/udev/keymap/force-release-maps/hp-other b/src/udev/keymap/force-release-maps/hp-other
new file mode 100644 (file)
index 0000000..6621370
--- /dev/null
@@ -0,0 +1,3 @@
+# list of scancodes (hex or decimal), optional comment
+0xd8 # Touchpad off
+0xd9 # Touchpad on
diff --git a/src/udev/keymap/force-release-maps/samsung-90x3a b/src/udev/keymap/force-release-maps/samsung-90x3a
new file mode 100644 (file)
index 0000000..65707ef
--- /dev/null
@@ -0,0 +1,6 @@
+# list of scancodes (hex or decimal), optional comment
+0xCE # Fn+F8 keyboard backlit up
+0x8D # Fn+F7 keyboard backlit down
+0x97 # Fn+F12 wifi on/off
+0x96 # Fn+F1 performance mode (?)
+0xD5 # Fn+F6 battery life extender
diff --git a/src/udev/keymap/force-release-maps/samsung-other b/src/udev/keymap/force-release-maps/samsung-other
new file mode 100644 (file)
index 0000000..c51123a
--- /dev/null
@@ -0,0 +1,10 @@
+# list of scancodes (hex or decimal), optional comment
+0x82 # Fn+F4 CRT/LCD
+0x83 # Fn+F2 battery
+0x84 # Fn+F5 backlight on/off
+0x86 # Fn+F9 WLAN
+0x88 # Fn-Up brightness up
+0x89 # Fn-Down brightness down
+0xB3 # Fn+F8 switch power mode (battery/dynamic/performance)
+0xF7 # Fn+F10 Touchpad on
+0xF9 # Fn+F10 Touchpad off
diff --git a/src/udev/keymap/keyboard-force-release.sh.in b/src/udev/keymap/keyboard-force-release.sh.in
new file mode 100755 (executable)
index 0000000..dd040ce
--- /dev/null
@@ -0,0 +1,22 @@
+#!@rootprefix@/bin/sh -e
+# read list of scancodes, convert hex to decimal and
+# append to the atkbd force_release sysfs attribute
+# $1 sysfs devpath for serioX
+# $2 file with scancode list (hex or dec)
+
+case "$2" in
+        /*) scf="$2" ;;
+        *)  scf="@pkglibexecdir@/keymaps/force-release/$2" ;;
+esac
+
+read attr <"/sys/$1/force_release"
+while read scancode dummy; do
+        case "$scancode" in
+                \#*) ;;
+                *)
+                        scancode=$(($scancode))
+                        attr="$attr${attr:+,}$scancode"
+                        ;;
+        esac
+done <"$scf"
+echo "$attr" >"/sys/$1/force_release"
diff --git a/src/udev/keymap/keymap.c b/src/udev/keymap/keymap.c
new file mode 100644 (file)
index 0000000..4c30ccf
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ * keymap - dump keymap of an evdev device or set a new keymap from a file
+ *
+ * Based on keyfuzz by Lennart Poettering <mzqrovna@0pointer.net>
+ * Adapted for udev-extras by Martin Pitt <martin.pitt@ubuntu.com>
+ *
+ * Copyright (C) 2006, Lennart Poettering
+ * Copyright (C) 2009, Canonical Ltd.
+ *
+ * keymap is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * keymap is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY 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 keymap; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <linux/limits.h>
+#include <linux/input.h>
+
+const struct key* lookup_key (const char *str, unsigned int len);
+
+#include "keys-from-name.h"
+#include "keys-to-name.h"
+
+#define MAX_SCANCODES 1024
+
+static int evdev_open(const char *dev)
+{
+        int fd;
+        char fn[PATH_MAX];
+
+        if (strncmp(dev, "/dev", 4) != 0) {
+                snprintf(fn, sizeof(fn), "/dev/%s", dev);
+                dev = fn;
+        }
+
+        if ((fd = open(dev, O_RDWR)) < 0) {
+                fprintf(stderr, "error open('%s'): %m\n", dev);
+                return -1;
+        }
+        return fd;
+}
+
+static int evdev_get_keycode(int fd, int scancode, int e)
+{
+        int codes[2];
+
+        codes[0] = scancode;
+        if (ioctl(fd, EVIOCGKEYCODE, codes) < 0) {
+                if (e && errno == EINVAL) {
+                        return -2;
+                } else {
+                        fprintf(stderr, "EVIOCGKEYCODE: %m\n");
+                        return -1;
+                }
+        }
+        return codes[1];
+}
+
+static int evdev_set_keycode(int fd, int scancode, int keycode)
+{
+        int codes[2];
+
+        codes[0] = scancode;
+        codes[1] = keycode;
+
+        if (ioctl(fd, EVIOCSKEYCODE, codes) < 0) {
+                fprintf(stderr, "EVIOCSKEYCODE: %m\n");
+                return -1;
+        }
+        return 0;
+}
+
+static int evdev_driver_version(int fd, char *v, size_t l)
+{
+        int version;
+
+        if (ioctl(fd, EVIOCGVERSION, &version)) {
+                fprintf(stderr, "EVIOCGVERSION: %m\n");
+                return -1;
+        }
+
+        snprintf(v, l, "%i.%i.%i.", version >> 16, (version >> 8) & 0xff, version & 0xff);
+        return 0;
+}
+
+static int evdev_device_name(int fd, char *n, size_t l)
+{
+        if (ioctl(fd, EVIOCGNAME(l), n) < 0) {
+                fprintf(stderr, "EVIOCGNAME: %m\n");
+                return -1;
+        }
+        return 0;
+}
+
+/* Return a lower-case string with KEY_ prefix removed */
+static const char* format_keyname(const char* key) {
+        static char result[101];
+        const char* s;
+        int len;
+
+        for (s = key+4, len = 0; *s && len < 100; ++len, ++s)
+                result[len] = tolower(*s);
+        result[len] = '\0';
+        return result;
+}
+
+static int dump_table(int fd) {
+        char version[256], name[256];
+        int scancode, r = -1;
+
+        if (evdev_driver_version(fd, version, sizeof(version)) < 0)
+                goto fail;
+
+        if (evdev_device_name(fd, name, sizeof(name)) < 0)
+                goto fail;
+
+        printf("### evdev %s, driver '%s'\n", version, name);
+
+        r = 0;
+        for (scancode = 0; scancode < MAX_SCANCODES; scancode++) {
+                int keycode;
+
+                if ((keycode = evdev_get_keycode(fd, scancode, 1)) < 0) {
+                        if (keycode == -2)
+                                continue;
+                        r = -1;
+                        break;
+                }
+
+                if (keycode < KEY_MAX && key_names[keycode])
+                        printf("0x%03x %s\n", scancode, format_keyname(key_names[keycode]));
+                else
+                        printf("0x%03x 0x%03x\n", scancode, keycode);
+        }
+fail:
+        return r;
+}
+
+static void set_key(int fd, const char* scancode_str, const char* keyname)
+{
+        unsigned scancode;
+        char *endptr;
+        char t[105] = "KEY_UNKNOWN";
+        const struct key *k;
+
+        scancode = (unsigned) strtol(scancode_str, &endptr, 0);
+        if (*endptr != '\0') {
+                fprintf(stderr, "ERROR: Invalid scancode\n");
+                exit(1);
+        }
+
+        snprintf(t, sizeof(t), "KEY_%s", keyname);
+
+        if (!(k = lookup_key(t, strlen(t)))) {
+                fprintf(stderr, "ERROR: Unknown key name '%s'\n", keyname);
+                exit(1);
+        }
+
+        if (evdev_set_keycode(fd, scancode, k->id) < 0)
+                fprintf(stderr, "setting scancode 0x%2X to key code %i failed\n",
+                        scancode, k->id);
+        else
+                printf("setting scancode 0x%2X to key code %i\n",
+                        scancode, k->id);
+}
+
+static int merge_table(int fd, FILE *f) {
+        int r = 0;
+        int line = 0;
+
+        while (!feof(f)) {
+                char s[256], *p;
+                int scancode, new_keycode, old_keycode;
+
+                if (!fgets(s, sizeof(s), f))
+                        break;
+
+                line++;
+                p = s+strspn(s, "\t ");
+                if (*p == '#' || *p == '\n')
+                        continue;
+
+                if (sscanf(p, "%i %i", &scancode, &new_keycode) != 2) {
+                        char t[105] = "KEY_UNKNOWN";
+                        const struct key *k;
+
+                        if (sscanf(p, "%i %100s", &scancode, t+4) != 2) {
+                                fprintf(stderr, "WARNING: Parse failure at line %i, ignoring.\n", line);
+                                r = -1;
+                                continue;
+                        }
+
+                        if (!(k = lookup_key(t, strlen(t)))) {
+                                fprintf(stderr, "WARNING: Unknown key '%s' at line %i, ignoring.\n", t, line);
+                                r = -1;
+                                continue;
+                        }
+
+                        new_keycode = k->id;
+                }
+
+
+                if ((old_keycode = evdev_get_keycode(fd, scancode, 0)) < 0) {
+                        r = -1;
+                        goto fail;
+                }
+
+                if (evdev_set_keycode(fd, scancode, new_keycode) < 0) {
+                        r = -1;
+                        goto fail;
+                }
+
+                if (new_keycode != old_keycode)
+                        fprintf(stderr, "Remapped scancode 0x%02x to 0x%02x (prior: 0x%02x)\n",
+                                scancode, new_keycode, old_keycode);
+        }
+fail:
+        fclose(f);
+        return r;
+}
+
+
+/* read one event; return 1 if valid */
+static int read_event(int fd, struct input_event* ev)
+{
+        int ret;
+        ret = read(fd, ev, sizeof(struct input_event));
+
+        if (ret < 0) {
+                perror("read");
+                return 0;
+        }
+        if (ret != sizeof(struct input_event)) {
+                fprintf(stderr, "did not get enough data for event struct, aborting\n");
+                return 0;
+        }
+
+        return 1;
+}
+
+static void print_key(uint32_t scancode, uint16_t keycode, int has_scan, int has_key)
+{
+        const char *keyname;
+
+        /* ignore key release events */
+        if (has_key == 1)
+                return;
+
+        if (has_key == 0 && has_scan != 0) {
+                fprintf(stderr, "got scan code event 0x%02X without a key code event\n",
+                        scancode);
+                return;
+        }
+
+        if (has_scan != 0)
+                printf("scan code: 0x%02X   ", scancode);
+        else
+                printf("(no scan code received)  ");
+
+        keyname = key_names[keycode];
+        if (keyname != NULL)
+                printf("key code: %s\n", format_keyname(keyname));
+        else
+                printf("key code: %03X\n", keycode);
+}
+
+static void interactive(int fd)
+{
+        struct input_event ev;
+        uint32_t last_scan = 0;
+        uint16_t last_key = 0;
+        int has_scan; /* boolean */
+        int has_key; /* 0: none, 1: release, 2: press */
+
+        /* grab input device */
+        ioctl(fd, EVIOCGRAB, 1);
+        puts("Press ESC to finish, or Control-C if this device is not your primary keyboard");
+
+        has_scan = has_key = 0;
+        while (read_event(fd, &ev)) {
+                /* Drivers usually send the scan code first, then the key code,
+                 * then a SYN. Some drivers (like thinkpad_acpi) send the key
+                 * code first, and some drivers might not send SYN events, so
+                 * keep a robust state machine which can deal with any of those
+                 */
+
+                if (ev.type == EV_MSC && ev.code == MSC_SCAN) {
+                        if (has_scan) {
+                                fputs("driver did not send SYN event in between key events; previous event:\n",
+                                      stderr);
+                                print_key(last_scan, last_key, has_scan, has_key);
+                                has_key = 0;
+                        }
+
+                        last_scan = ev.value;
+                        has_scan = 1;
+                        /*printf("--- got scan %u; has scan %i key %i\n", last_scan, has_scan, has_key); */
+                }
+                else if (ev.type == EV_KEY) {
+                        if (has_key) {
+                                fputs("driver did not send SYN event in between key events; previous event:\n",
+                                      stderr);
+                                print_key(last_scan, last_key, has_scan, has_key);
+                                has_scan = 0;
+                        }
+
+                        last_key = ev.code;
+                        has_key = 1 + ev.value;
+                        /*printf("--- got key %hu; has scan %i key %i\n", last_key, has_scan, has_key);*/
+
+                        /* Stop on ESC */
+                        if (ev.code == KEY_ESC && ev.value == 0)
+                                break;
+                }
+                else if (ev.type == EV_SYN) {
+                        /*printf("--- got SYN; has scan %i key %i\n", has_scan, has_key);*/
+                        print_key(last_scan, last_key, has_scan, has_key);
+
+                        has_scan = has_key = 0;
+                }
+
+        }
+
+        /* release input device */
+        ioctl(fd, EVIOCGRAB, 0);
+}
+
+static void help(int error)
+{
+        const char* h = "Usage: keymap <event device> [<map file>]\n"
+                        "       keymap <event device> scancode keyname [...]\n"
+                        "       keymap -i <event device>\n";
+        if (error) {
+                fputs(h, stderr);
+                exit(2);
+        } else {
+                fputs(h, stdout);
+                exit(0);
+        }
+}
+
+int main(int argc, char **argv)
+{
+        static const struct option options[] = {
+                { "help", no_argument, NULL, 'h' },
+                { "interactive", no_argument, NULL, 'i' },
+                {}
+        };
+        int fd = -1;
+        int opt_interactive = 0;
+        int i;
+
+        while (1) {
+                int option;
+
+                option = getopt_long(argc, argv, "hi", options, NULL);
+                if (option == -1)
+                        break;
+
+                switch (option) {
+                case 'h':
+                        help(0);
+
+                case 'i':
+                        opt_interactive = 1;
+                        break;
+                default:
+                        return 1;
+                }
+        }
+
+        if (argc < optind+1)
+                help (1);
+
+        if ((fd = evdev_open(argv[optind])) < 0)
+                return 3;
+
+        /* one argument (device): dump or interactive */
+        if (argc == optind+1) {
+                if (opt_interactive)
+                        interactive(fd);
+                else
+                        dump_table(fd);
+                return 0;
+        }
+
+        /* two arguments (device, mapfile): set map file */
+        if (argc == optind+2) {
+                const char *filearg = argv[optind+1];
+                if (strchr(filearg, '/')) {
+                        /* Keymap file argument is a path */
+                        FILE *f = fopen(filearg, "r");
+                        if (f)
+                                merge_table(fd, f);
+                        else
+                                perror(filearg);
+                } else {
+                        /* Keymap file argument is a filename */
+                        /* Open override file if present, otherwise default file */
+                        char keymap_path[PATH_MAX];
+                        snprintf(keymap_path, sizeof(keymap_path), "%s%s", SYSCONFDIR "/udev/keymaps/", filearg);
+                        FILE *f = fopen(keymap_path, "r");
+                        if (f) {
+                                merge_table(fd, f);
+                        } else {
+                                snprintf(keymap_path, sizeof(keymap_path), "%s%s", UDEVLIBEXECDIR "/keymaps/", filearg);
+                                f = fopen(keymap_path, "r");
+                                if (f)
+                                        merge_table(fd, f);
+                                else
+                                        perror(keymap_path);
+                        }
+                }
+                return 0;
+        }
+
+        /* more arguments (device, scancode/keyname pairs): set keys directly */
+        if ((argc - optind - 1) % 2 == 0) {
+                for (i = optind+1; i < argc; i += 2)
+                        set_key(fd, argv[i], argv[i+1]);
+                return 0;
+        }
+
+        /* invalid number of arguments */
+        help(1);
+        return 1; /* not reached */
+}
diff --git a/src/udev/keymap/keymaps/acer b/src/udev/keymap/keymaps/acer
new file mode 100644 (file)
index 0000000..4e7c297
--- /dev/null
@@ -0,0 +1,22 @@
+0xA5 help # Fn+F1
+0xA6 setup # Fn+F2 Acer eSettings
+0xA7 battery # Fn+F3 Power Management
+0xA9 switchvideomode # Fn+F5
+0xB3 euro
+0xB4 dollar
+0xCE brightnessup # Fn+Right
+0xD4 bluetooth # (toggle) off-to-on
+0xD5 wlan # (toggle) on-to-off
+0xD6 wlan # (toggle) off-to-on
+0xD7 bluetooth # (toggle) on-to-off
+0xD8 bluetooth # (toggle) off-to-on
+0xD9 brightnessup # Fn+Right
+0xEE brightnessup # Fn+Right
+0xEF brightnessdown # Fn+Left
+0xF1 f22 # Fn+F7 Touchpad toggle (off-to-on)
+0xF2 f23 # Fn+F7 Touchpad toggle (on-to-off)
+0xF3 prog2 # "P2" programmable button
+0xF4 prog1 # "P1" programmable button
+0xF5 presentation
+0xF8 fn
+0xF9 f23 # Launch NTI shadow
diff --git a/src/udev/keymap/keymaps/acer-aspire_5720 b/src/udev/keymap/keymaps/acer-aspire_5720
new file mode 100644 (file)
index 0000000..1496d63
--- /dev/null
@@ -0,0 +1,4 @@
+0x84 bluetooth  # sent when bluetooth module missing, and key pressed
+0x92 media      # acer arcade
+0xD4 bluetooth  # bluetooth on
+0xD9 bluetooth  # bluetooth off
diff --git a/src/udev/keymap/keymaps/acer-aspire_5920g b/src/udev/keymap/keymaps/acer-aspire_5920g
new file mode 100644 (file)
index 0000000..633c4e8
--- /dev/null
@@ -0,0 +1,5 @@
+0x8A media
+0x92 media
+0xA6 setup
+0xB2 www
+0xD9 bluetooth # (toggle) on-to-off
diff --git a/src/udev/keymap/keymaps/acer-aspire_6920 b/src/udev/keymap/keymaps/acer-aspire_6920
new file mode 100644 (file)
index 0000000..699c954
--- /dev/null
@@ -0,0 +1,5 @@
+0xD9 bluetooth # (toggle) on-to-off
+0x92 media
+0x9E back
+0x83 rewind
+0x89 fastforward
diff --git a/src/udev/keymap/keymaps/acer-aspire_8930 b/src/udev/keymap/keymaps/acer-aspire_8930
new file mode 100644 (file)
index 0000000..fb27bfb
--- /dev/null
@@ -0,0 +1,5 @@
+0xCA prog3        # key 'HOLD' on cine dash media console
+0x83 rewind
+0x89 fastforward
+0x92 media        # key 'ARCADE' on cine dash media console
+0x9E back
diff --git a/src/udev/keymap/keymaps/acer-travelmate_c300 b/src/udev/keymap/keymaps/acer-travelmate_c300
new file mode 100644 (file)
index 0000000..bfef4cf
--- /dev/null
@@ -0,0 +1,5 @@
+0x67 f24 # FIXME: rotate screen
+0x68 up
+0x69 down
+0x6B fn
+0x6C screenlock # FIXME: lock tablet device/buttons
diff --git a/src/udev/keymap/keymaps/asus b/src/udev/keymap/keymaps/asus
new file mode 100644 (file)
index 0000000..2a5995f
--- /dev/null
@@ -0,0 +1,3 @@
+0xED volumeup
+0xEE volumedown
+0xEF mute
diff --git a/src/udev/keymap/keymaps/compaq-e_evo b/src/udev/keymap/keymaps/compaq-e_evo
new file mode 100644 (file)
index 0000000..5fbc573
--- /dev/null
@@ -0,0 +1,4 @@
+0xA3 www # I key
+0x9A search
+0x9E email
+0x9F homepage
diff --git a/src/udev/keymap/keymaps/dell b/src/udev/keymap/keymaps/dell
new file mode 100644 (file)
index 0000000..4f907b3
--- /dev/null
@@ -0,0 +1,29 @@
+0x81 playpause # Play/Pause
+0x82 stopcd # Stop
+0x83 previoussong # Previous song
+0x84 nextsong # Next song
+0x85 brightnessdown # Fn+Down arrow Brightness Down
+0x86 brightnessup # Fn+Up arrow Brightness Up
+0x87 battery # Fn+F3 battery icon
+0x88 unknown # Fn+F2 Turn On/Off Wireless - handled in hardware
+0x89 ejectclosecd # Fn+F10 Eject CD
+0x8A suspend # Fn+F1 hibernate
+0x8B switchvideomode # Fn+F8 CRT/LCD (high keycode: "displaytoggle")
+0x8C f23 # Fn+Right arrow Auto Brightness
+0x8F switchvideomode # Fn+F7 aspect ratio
+0x90 previoussong # Front panel previous song
+0x91 prog1 # Wifi Catcher (DELL Specific)
+0x92 media # MediaDirect button (house icon)
+0x93 f23 # FIXME Fn+Left arrow Auto Brightness
+0x95 camera # Shutter button Takes a picture if optional camera available
+0x97 email # Tablet email button
+0x98 f21 # FIXME: Tablet screen rotatation
+0x99 nextsong # Front panel next song
+0x9A setup # Tablet tools button
+0x9B switchvideomode # Display Toggle button
+0x9E f21 #touchpad toggle
+0xA2 playpause # Front panel play/pause
+0xA4 stopcd # Front panel stop
+0xED media # MediaDirect button
+0xD8 screenlock # FIXME: Tablet lock button
+0xD9 f21 # touchpad toggle
diff --git a/src/udev/keymap/keymaps/dell-latitude-xt2 b/src/udev/keymap/keymaps/dell-latitude-xt2
new file mode 100644 (file)
index 0000000..39872f5
--- /dev/null
@@ -0,0 +1,4 @@
+0x9B up # tablet rocker up
+0x9E enter # tablet rocker press
+0x9F back # tablet back
+0xA3 down # tablet rocker down
diff --git a/src/udev/keymap/keymaps/everex-xt5000 b/src/udev/keymap/keymaps/everex-xt5000
new file mode 100644 (file)
index 0000000..4823a83
--- /dev/null
@@ -0,0 +1,7 @@
+0x5C media
+0x65 f21 # Fn+F5 Touchpad toggle
+0x67 prog3 # Fan Speed Control button
+0x6F brightnessup
+0x7F brightnessdown
+0xB2 www
+0xEC mail
diff --git a/src/udev/keymap/keymaps/fujitsu-amilo_li_2732 b/src/udev/keymap/keymaps/fujitsu-amilo_li_2732
new file mode 100644 (file)
index 0000000..9b8b36a
--- /dev/null
@@ -0,0 +1,3 @@
+0xD9 brightnessdown # Fn+F8 brightness down
+0xEF brightnessup # Fn+F9 brightness up
+0xA9 switchvideomode # Fn+F10 Cycle between available video outputs
diff --git a/src/udev/keymap/keymaps/fujitsu-amilo_pa_2548 b/src/udev/keymap/keymaps/fujitsu-amilo_pa_2548
new file mode 100644 (file)
index 0000000..f7b0c52
--- /dev/null
@@ -0,0 +1,3 @@
+0xE0 volumedown
+0xE1 volumeup
+0xE5 prog1
diff --git a/src/udev/keymap/keymaps/fujitsu-amilo_pro_edition_v3505 b/src/udev/keymap/keymaps/fujitsu-amilo_pro_edition_v3505
new file mode 100644 (file)
index 0000000..d2e38cb
--- /dev/null
@@ -0,0 +1,4 @@
+0xA5 help # Fn-F1
+0xA9 switchvideomode # Fn-F3
+0xD9 brightnessdown # Fn-F8
+0xE0 brightnessup # Fn-F9
diff --git a/src/udev/keymap/keymaps/fujitsu-amilo_pro_v3205 b/src/udev/keymap/keymaps/fujitsu-amilo_pro_v3205
new file mode 100644 (file)
index 0000000..43e3199
--- /dev/null
@@ -0,0 +1,2 @@
+0xF4 f21 # FIXME: silent-mode decrease CPU/GPU clock
+0xF7 switchvideomode # Fn+F3
diff --git a/src/udev/keymap/keymaps/fujitsu-amilo_si_1520 b/src/udev/keymap/keymaps/fujitsu-amilo_si_1520
new file mode 100644 (file)
index 0000000..1419bd9
--- /dev/null
@@ -0,0 +1,6 @@
+0xE1 wlan
+0xF3 wlan
+0xEE brightnessdown
+0xE0 brightnessup
+0xE2 bluetooth
+0xF7 video
diff --git a/src/udev/keymap/keymaps/fujitsu-esprimo_mobile_v5 b/src/udev/keymap/keymaps/fujitsu-esprimo_mobile_v5
new file mode 100644 (file)
index 0000000..d3d056b
--- /dev/null
@@ -0,0 +1,4 @@
+0xA9 switchvideomode
+0xD9 brightnessdown
+0xDF sleep
+0xEF brightnessup
diff --git a/src/udev/keymap/keymaps/fujitsu-esprimo_mobile_v6 b/src/udev/keymap/keymaps/fujitsu-esprimo_mobile_v6
new file mode 100644 (file)
index 0000000..52c70c5
--- /dev/null
@@ -0,0 +1,2 @@
+0xCE brightnessup
+0xEF brightnessdown
diff --git a/src/udev/keymap/keymaps/genius-slimstar-320 b/src/udev/keymap/keymaps/genius-slimstar-320
new file mode 100644 (file)
index 0000000..d0a3656
--- /dev/null
@@ -0,0 +1,35 @@
+# Genius SlimStar 320
+#
+# Only buttons which are not properly mapped yet are configured below
+
+# "Scroll wheel", a circular up/down/left/right button. Aimed for scolling,
+# but since there are no scrollleft/scrollright, let's map to back/forward.
+0x900f0 scrollup
+0x900f1 scrolldown
+0x900f3 back
+0x900f2 forward
+
+# Multimedia buttons, left side (from left to right)
+# [W]
+0x900f5 wordprocessor
+# [Ex]
+0x900f6 spreadsheet
+# [P]
+0x900f4 presentation
+# Other five (calculator, playpause, stop, mute and eject) are OK
+
+# Right side, from left to right
+# [e]
+0xc0223 www
+# "man"
+0x900f7 chat
+# "Y"
+0x900fb prog1
+# [X]
+0x900f8 close
+# "picture"
+0x900f9 graphicseditor
+# "two windows"
+0x900fd scale
+# "lock"
+0x900fc screenlock
diff --git a/src/udev/keymap/keymaps/hewlett-packard b/src/udev/keymap/keymaps/hewlett-packard
new file mode 100644 (file)
index 0000000..4461fa2
--- /dev/null
@@ -0,0 +1,12 @@
+0x81 fn_esc
+0x89 battery # FnF8
+0x8A screenlock # FnF6
+0x8B camera
+0x8C media # music
+0x8E dvd
+0xB1 help
+0xB3 f23 # FIXME: Auto brightness
+0xD7 wlan
+0x92 brightnessdown # FnF7 (FnF9 on 6730b)
+0x97 brightnessup # FnF8 (FnF10 on 6730b)
+0xEE switchvideomode # FnF4
diff --git a/src/udev/keymap/keymaps/hewlett-packard-2510p_2530p b/src/udev/keymap/keymaps/hewlett-packard-2510p_2530p
new file mode 100644 (file)
index 0000000..41ad2e9
--- /dev/null
@@ -0,0 +1,2 @@
+0xD8 f23 # touchpad off
+0xD9 f22 # touchpad on
diff --git a/src/udev/keymap/keymaps/hewlett-packard-compaq_elitebook b/src/udev/keymap/keymaps/hewlett-packard-compaq_elitebook
new file mode 100644 (file)
index 0000000..42007c5
--- /dev/null
@@ -0,0 +1,2 @@
+0x88 presentation
+0xD9 help # I key (high keycode: "info")
diff --git a/src/udev/keymap/keymaps/hewlett-packard-pavilion b/src/udev/keymap/keymaps/hewlett-packard-pavilion
new file mode 100644 (file)
index 0000000..3d3cefc
--- /dev/null
@@ -0,0 +1,3 @@
+0x88 media # FIXME: quick play
+0xD8 f23 # touchpad off
+0xD9 f22 # touchpad on
diff --git a/src/udev/keymap/keymaps/hewlett-packard-presario-2100 b/src/udev/keymap/keymaps/hewlett-packard-presario-2100
new file mode 100644 (file)
index 0000000..1df39dc
--- /dev/null
@@ -0,0 +1,3 @@
+0xF0 help
+0xF1 screenlock
+0xF3 search
diff --git a/src/udev/keymap/keymaps/hewlett-packard-tablet b/src/udev/keymap/keymaps/hewlett-packard-tablet
new file mode 100644 (file)
index 0000000..d19005a
--- /dev/null
@@ -0,0 +1,6 @@
+0x82 prog2 # Funny Key
+0x83 prog1 # Q
+0x84 tab
+0x85 esc
+0x86 pageup
+0x87 pagedown
diff --git a/src/udev/keymap/keymaps/hewlett-packard-tx2 b/src/udev/keymap/keymaps/hewlett-packard-tx2
new file mode 100644 (file)
index 0000000..36a690f
--- /dev/null
@@ -0,0 +1,3 @@
+0xC2 media
+0xD8 f23 # Toggle touchpad button on tx2 (OFF)
+0xD9 f22 # Toggle touchpad button on tx2 (ON)
diff --git a/src/udev/keymap/keymaps/ibm-thinkpad-usb-keyboard-trackpoint b/src/udev/keymap/keymaps/ibm-thinkpad-usb-keyboard-trackpoint
new file mode 100644 (file)
index 0000000..027e50b
--- /dev/null
@@ -0,0 +1,7 @@
+0x900f0 screenlock
+0x900f1 wlan
+0x900f2 switchvideomode
+0x900f3 suspend
+0x900f4 brightnessup
+0x900f5 brightnessdown
+0x900f8 zoom
diff --git a/src/udev/keymap/keymaps/inventec-symphony_6.0_7.0 b/src/udev/keymap/keymaps/inventec-symphony_6.0_7.0
new file mode 100644 (file)
index 0000000..4a8b4ba
--- /dev/null
@@ -0,0 +1,2 @@
+0xF3 prog2
+0xF4 prog1
diff --git a/src/udev/keymap/keymaps/lenovo-3000 b/src/udev/keymap/keymaps/lenovo-3000
new file mode 100644 (file)
index 0000000..5bd1656
--- /dev/null
@@ -0,0 +1,5 @@
+0x8B switchvideomode # Fn+F7 video
+0x96 wlan # Fn+F5 wireless
+0x97 sleep # Fn+F4 suspend
+0x98 suspend # Fn+F12 hibernate
+0xB4 prog1 # Lenovo Care
diff --git a/src/udev/keymap/keymaps/lenovo-ideapad b/src/udev/keymap/keymaps/lenovo-ideapad
new file mode 100644 (file)
index 0000000..fc33983
--- /dev/null
@@ -0,0 +1,8 @@
+# Key codes observed on S10-3, assumed valid on other IdeaPad models
+0x81 rfkill             # does nothing in BIOS
+0x83 display_off        # BIOS toggles screen state
+0xB9 brightnessup       # does nothing in BIOS
+0xBA brightnessdown     # does nothing in BIOS
+0xF1 camera             # BIOS toggles camera power
+0xf2 f21                # touchpad toggle (key alternately emits f2 and f3)
+0xf3 f21
diff --git a/src/udev/keymap/keymaps/lenovo-thinkpad-usb-keyboard-trackpoint b/src/udev/keymap/keymaps/lenovo-thinkpad-usb-keyboard-trackpoint
new file mode 100644 (file)
index 0000000..47e8846
--- /dev/null
@@ -0,0 +1,13 @@
+0x90012 screenlock # Fn+F2
+0x90013 battery # Fn+F3
+0x90014 wlan # Fn+F5
+0x90016 switchvideomode # Fn+F7
+0x90017 f21 # Fn+F8  touchpadtoggle
+0x90019 suspend # Fn+F12
+0x9001A brightnessup # Fn+Home
+0x9001B brightnessdown # Fn+End
+0x9001D zoom # Fn+Space
+0x90011 prog1 # Thinkvantage button
+
+0x90015 camera # Fn+F6 headset/camera VoIP key  ??
+0x90010 micmute # Microphone mute button
diff --git a/src/udev/keymap/keymaps/lenovo-thinkpad_x200_tablet b/src/udev/keymap/keymaps/lenovo-thinkpad_x200_tablet
new file mode 100644 (file)
index 0000000..31ea3b2
--- /dev/null
@@ -0,0 +1,6 @@
+0x5D menu
+0x63 fn
+0x66 screenlock
+0x67 cyclewindows # bezel circular arrow
+0x68 setup # bezel setup / menu
+0x6c direction # rotate screen
diff --git a/src/udev/keymap/keymaps/lenovo-thinkpad_x6_tablet b/src/udev/keymap/keymaps/lenovo-thinkpad_x6_tablet
new file mode 100644 (file)
index 0000000..6fd16b5
--- /dev/null
@@ -0,0 +1,8 @@
+0x6C f21 # rotate
+0x68 screenlock # screenlock
+0x6B esc # escape
+0x6D right # right on d-pad
+0x6E left # left on d-pad
+0x71 up # up on d-pad
+0x6F down # down on d-pad
+0x69 enter # enter on d-pad
diff --git a/src/udev/keymap/keymaps/lg-x110 b/src/udev/keymap/keymaps/lg-x110
new file mode 100644 (file)
index 0000000..ba08cba
--- /dev/null
@@ -0,0 +1,12 @@
+0xA0 mute # Fn-F9
+0xAE volumedown # Fn-Left
+0xAF search # Fn-F3
+0xB0 volumeup # Fn-Right
+0xB1 battery # Fn-F10 Info
+0xB3 suspend # Fn-F12
+0xDF sleep # Fn-F4
+# 0xE2 bluetooth # satellite dish2
+0xE4 f21 # Fn-F5   Touchpad disable
+0xF6 wlan # Fn-F6
+0xF7 reserved # brightnessdown # Fn-Down
+0xF8 reserved # brightnessup # Fn-Up
diff --git a/src/udev/keymap/keymaps/logitech-wave b/src/udev/keymap/keymaps/logitech-wave
new file mode 100644 (file)
index 0000000..caa5d5d
--- /dev/null
@@ -0,0 +1,16 @@
+0x9001C scale #expo
+0x9001F zoomout #zoom out
+0x90020 zoomin #zoom in
+0x9003D prog1 #gadget
+0x90005 camera #camera
+0x90018 media #media center
+0x90041 wordprocessor #fn+f1 (word)
+0x90042 spreadsheet #fn+f2 (excel)
+0x90043 calendar #fn+f3 (calendar)
+0x90044 prog2 #fn+f4 (program a)
+0x90045 prog3 #fn+f5 (program b)
+0x90046 prog4 #fn+f6 (program c)
+0x90048 messenger #fn+f8 (msn messenger)
+0x9002D find #fn+f10 (search www)
+0x9004B search #fn+f11 (search pc)
+0x9004C ejectclosecd #fn+f12 (eject)
diff --git a/src/udev/keymap/keymaps/logitech-wave-cordless b/src/udev/keymap/keymaps/logitech-wave-cordless
new file mode 100644 (file)
index 0000000..a10dad5
--- /dev/null
@@ -0,0 +1,15 @@
+0xD4 zoomin
+0xCC zoomout
+0xC0183 media
+0xC1005 camera
+0xC101F zoomout
+0xC1020 zoomin
+0xC1041 wordprocessor
+0xC1042 spreadsheet
+0xC1043 calendar
+0xC1044 prog2 #fn+f4 (program a)
+0xC1045 prog3 #fn+f5 (program b)
+0xC1046 prog4 #fn+f6 (program c)
+0xC1048 messenger
+0xC104A find #fn+f10 (search www)
+0xC104C ejectclosecd
diff --git a/src/udev/keymap/keymaps/logitech-wave-pro-cordless b/src/udev/keymap/keymaps/logitech-wave-pro-cordless
new file mode 100644 (file)
index 0000000..e7aa022
--- /dev/null
@@ -0,0 +1,12 @@
+0xC01B6 camera
+0xC0183 media
+0xC0184 wordprocessor
+0xC0186 spreadsheet
+0xC018E calendar
+0xC0223 homepage
+0xC01BC messenger
+0xC018A mail
+0xC0221 search
+0xC00B8 ejectcd
+0xC022D zoomin
+0xC022E zoomout
diff --git a/src/udev/keymap/keymaps/maxdata-pro_7000 b/src/udev/keymap/keymaps/maxdata-pro_7000
new file mode 100644 (file)
index 0000000..c0e4f77
--- /dev/null
@@ -0,0 +1,9 @@
+0x97 prog2
+0x9F prog1
+0xA0 mute # Fn-F5
+0x82 www
+0xEC email
+0xAE volumedown # Fn-Down
+0xB0 volumeup # Fn-Up
+0xDF suspend # Fn+F2
+0xF5 help
diff --git a/src/udev/keymap/keymaps/medion-fid2060 b/src/udev/keymap/keymaps/medion-fid2060
new file mode 100644 (file)
index 0000000..5a76c76
--- /dev/null
@@ -0,0 +1,2 @@
+0x6B channeldown # Thottle Down
+0x6D channelup # Thottle Up
diff --git a/src/udev/keymap/keymaps/medionnb-a555 b/src/udev/keymap/keymaps/medionnb-a555
new file mode 100644 (file)
index 0000000..c3b5dfa
--- /dev/null
@@ -0,0 +1,4 @@
+0x63 www # N button
+0x66 prog1 # link 1 button
+0x67 email # envelope button
+0x69 prog2 # link 2 button
diff --git a/src/udev/keymap/keymaps/micro-star b/src/udev/keymap/keymaps/micro-star
new file mode 100644 (file)
index 0000000..4a43869
--- /dev/null
@@ -0,0 +1,13 @@
+0xA0 mute # Fn-F9
+0xAE volumedown # Fn-F7
+0xB0 volumeup # Fn-F8
+0xB2 www # e button
+0xDF sleep # Fn-F12
+0xE2 bluetooth # satellite dish2
+0xE4 f21 # Fn-F3   Touchpad disable
+0xEC email # envelope button
+0xEE camera # Fn-F6 camera disable
+0xF6 wlan # satellite dish1
+0xF7 brightnessdown # Fn-F4
+0xF8 brightnessup # Fn-F5
+0xF9 search
diff --git a/src/udev/keymap/keymaps/module-asus-w3j b/src/udev/keymap/keymaps/module-asus-w3j
new file mode 100644 (file)
index 0000000..773e0b3
--- /dev/null
@@ -0,0 +1,11 @@
+0x41 nextsong
+0x45 playpause
+0x43 stopcd
+0x40 previoussong
+0x4C ejectclosecd
+0x32 mute
+0x31 volumedown
+0x30 volumeup
+0x5D wlan
+0x7E bluetooth
+0x8A media # high keycode: "tv"
diff --git a/src/udev/keymap/keymaps/module-ibm b/src/udev/keymap/keymaps/module-ibm
new file mode 100644 (file)
index 0000000..a92dfa2
--- /dev/null
@@ -0,0 +1,16 @@
+0x01 battery # Fn+F2
+0x02 screenlock # Fn+F3
+0x03 sleep # Fn+F4
+0x04 wlan # Fn+F5
+0x06 switchvideomode # Fn+F7
+0x07 zoom # Fn+F8 screen expand
+0x08 f24 # Fn+F9 undock
+0x0B suspend # Fn+F12
+0x0F brightnessup # Fn+Home
+0x10 brightnessdown # Fn+End
+0x11 kbdillumtoggle # Fn+PgUp - ThinkLight
+0x13 zoom # Fn+Space
+0x14 volumeup
+0x15 volumedown
+0x16 mute
+0x17 prog1 # ThinkPad/ThinkVantage button  (high keycode: "vendor")
diff --git a/src/udev/keymap/keymaps/module-lenovo b/src/udev/keymap/keymaps/module-lenovo
new file mode 100644 (file)
index 0000000..8e38883
--- /dev/null
@@ -0,0 +1,17 @@
+0x1 screenlock # Fn+F2
+0x2 battery # Fn+F3
+0x3 sleep # Fn+F4
+0x4 wlan # Fn+F5
+0x6 switchvideomode # Fn+F7
+0x7 f21 # Fn+F8 touchpadtoggle
+0x8 f24 # Fn+F9 undock
+0xB suspend # Fn+F12
+0xF brightnessup # Fn+Home
+0x10 brightnessdown # Fn+End
+0x11 kbdillumtoggle # Fn+PgUp - ThinkLight
+0x13 zoom # Fn+Space
+0x14 volumeup
+0x15 volumedown
+0x16 mute
+0x17 prog1 # ThinkPad/ThinkVantage button (high keycode: "vendor")
+0x1A micmute # Microphone mute
diff --git a/src/udev/keymap/keymaps/module-sony b/src/udev/keymap/keymaps/module-sony
new file mode 100644 (file)
index 0000000..7c00013
--- /dev/null
@@ -0,0 +1,8 @@
+0x06 mute # Fn+F2
+0x07 volumedown # Fn+F3
+0x08 volumeup # Fn+F4
+0x09 brightnessdown # Fn+F5
+0x0A brightnessup # Fn+F6
+0x0B switchvideomode # Fn+F7
+0x0E zoom # Fn+F10
+0x10 suspend # Fn+F12
diff --git a/src/udev/keymap/keymaps/module-sony-old b/src/udev/keymap/keymaps/module-sony-old
new file mode 100644 (file)
index 0000000..596a342
--- /dev/null
@@ -0,0 +1,2 @@
+0x06 battery
+0x07 mute
diff --git a/src/udev/keymap/keymaps/module-sony-vgn b/src/udev/keymap/keymaps/module-sony-vgn
new file mode 100644 (file)
index 0000000..c8ba001
--- /dev/null
@@ -0,0 +1,8 @@
+0x00 brightnessdown # Fn+F5
+0x10 brightnessup # Fn+F6
+0x11 switchvideomode # Fn+F7
+0x12 zoomout
+0x14 zoomin
+0x15 suspend # Fn+F12
+0x17 prog1
+0x20 media
diff --git a/src/udev/keymap/keymaps/olpc-xo b/src/udev/keymap/keymaps/olpc-xo
new file mode 100644 (file)
index 0000000..34434a1
--- /dev/null
@@ -0,0 +1,74 @@
+0x59 fn
+0x81 fn_esc
+0xF9 camera
+0xF8 sound # Fn-CAMERA = Mic
+
+
+# Function key mappings, as per
+#    http://dev.laptop.org/ticket/10213#comment:20
+#
+# Unmodified F1-F8 produce F1-F8, so no remap necessary.
+# Unmodified F9-F12 control brightness and volume.
+0x43 brightnessdown
+0x44 brightnessup
+0x57 volumedown
+0x58 volumeup
+
+# fn-modified fkeys all produce the unmodified version of the key.
+0xBB f1
+0xBC f2
+0xBD f3
+0xBE f4
+0xBF f5
+0xC0 f6
+0xC1 f7
+0xC2 f8
+0xC3 f9
+0xC4 f10
+0xD7 f11
+0xD8 f12
+
+
+# Using F13-F21 for the .5 F keys right now.
+0xF7 f13
+0xF6 f14
+0xF5 f15
+0xF4 f16
+0xF3 f17
+0xF2 f18
+0xF1 f19
+0xF0 f20
+0xEF f21
+
+0xEE chat
+0xE4 chat # Just mapping Fn-Chat to Chat for now
+0xDD menu # Frame
+0xDA prog1 # Fn-Frame
+
+# The FN of some keys is other keys
+0xD3 delete
+0xD2 insert
+0xC9 pageup
+0xD1 pagedown
+0xC7 home
+0xCF end
+
+# Language key - don't ask what they are doing as KEY_HP
+0x73 hp
+0x7E hp
+
+0xDB leftmeta # left grab
+0xDC rightmeta # right grab
+0x85 rightmeta # Right grab releases on a different scancode
+0xD6 kbdillumtoggle # Fn-space
+0x69 switchvideomode # Brightness key
+
+# Game keys
+0x65 kp8 # up
+0x66 kp2 # down
+0x67 kp4 # left
+0x68 kp6 # right
+0xE5 kp9 # pgup
+0xE6 kp3 # pgdn
+0xE7 kp7 # home
+0xE8 kp1 # end
diff --git a/src/udev/keymap/keymaps/onkyo b/src/udev/keymap/keymaps/onkyo
new file mode 100644 (file)
index 0000000..ee864ad
--- /dev/null
@@ -0,0 +1,14 @@
+0xA0 mute # Fn+D
+0xAE volumedown # Fn+F
+0xB0 volumeup # Fn+G
+0xDF sleep # Fn+W
+0xE0 bluetooth # Fn+H
+0xE2 cyclewindows # Fn+Esc
+0xEE battery # Fn+Q
+0xF0 media # Fn+R
+0xF5 switchvideomode # Fn+E
+0xF6 camera # Fn+T
+0xF7 f21 # Fn+Y (touchpad toggle)
+0xF8 brightnessup # Fn+S
+0xF9 brightnessdown # Fn+A
+0xFB wlan # Fn+J
diff --git a/src/udev/keymap/keymaps/oqo-model2 b/src/udev/keymap/keymaps/oqo-model2
new file mode 100644 (file)
index 0000000..b7f4851
--- /dev/null
@@ -0,0 +1,5 @@
+0x8E wlan
+0xF0 switchvideomode
+0xF1 mute
+0xF2 volumedown
+0xF3 volumeup
diff --git a/src/udev/keymap/keymaps/samsung-90x3a b/src/udev/keymap/keymaps/samsung-90x3a
new file mode 100644 (file)
index 0000000..8b65eb6
--- /dev/null
@@ -0,0 +1,5 @@
+0x96 kbdillumup         # Fn+F8 keyboard backlit up
+0x97 kbdillumdown       # Fn+F7 keyboard backlit down
+0xD5 wlan               # Fn+F12 wifi on/off
+0xCE prog1              # Fn+F1 performance mode
+0x8D prog2              # Fn+F6 battery life extender
diff --git a/src/udev/keymap/keymaps/samsung-other b/src/udev/keymap/keymaps/samsung-other
new file mode 100644 (file)
index 0000000..3ac0c2f
--- /dev/null
@@ -0,0 +1,14 @@
+0x74 prog1 # User key
+0x75 www
+0x78 mail
+0x82 switchvideomode # Fn+F4 CRT/LCD (high keycode: "displaytoggle")
+0x83 battery # Fn+F2
+0x84 prog1 # Fn+F5 backlight on/off
+0x86 wlan # Fn+F9
+0x88 brightnessup # Fn-Up
+0x89 brightnessdown # Fn-Down
+0xB1 prog2 # Fn+F7 run Samsung Magic Doctor (keypressed event is generated twice)
+0xB3 prog3 # Fn+F8 switch power mode (battery/dynamic/performance)
+0xB4 wlan # Fn+F9 (X60P)
+0xF7 f22 # Fn+F10 Touchpad on
+0xF9 f23 # Fn+F10 Touchpad off
diff --git a/src/udev/keymap/keymaps/samsung-sq1us b/src/udev/keymap/keymaps/samsung-sq1us
new file mode 100644 (file)
index 0000000..ea2141e
--- /dev/null
@@ -0,0 +1,7 @@
+0xD4 menu
+0xD8 f1
+0xD9 f10
+0xD6 f3
+0xD7 f9
+0xE4 f5
+0xEE f11
diff --git a/src/udev/keymap/keymaps/samsung-sx20s b/src/udev/keymap/keymaps/samsung-sx20s
new file mode 100644 (file)
index 0000000..9d954ee
--- /dev/null
@@ -0,0 +1,4 @@
+0x74 mute
+0x75 mute
+0x77 f22 # Touchpad on
+0x79 f23 # Touchpad off
diff --git a/src/udev/keymap/keymaps/toshiba-satellite_a100 b/src/udev/keymap/keymaps/toshiba-satellite_a100
new file mode 100644 (file)
index 0000000..22007be
--- /dev/null
@@ -0,0 +1,2 @@
+0xA4 stopcd
+0xB2 www
diff --git a/src/udev/keymap/keymaps/toshiba-satellite_a110 b/src/udev/keymap/keymaps/toshiba-satellite_a110
new file mode 100644 (file)
index 0000000..1429409
--- /dev/null
@@ -0,0 +1,10 @@
+0x92 stop
+0x93 www
+0x94 media
+0x9E f22 # Touchpad on
+0x9F f23 # Touchpad off
+0xB9 nextsong
+0xD9 brightnessup
+0xEE screenlock
+0xF4 previoussong
+0xF7 playpause
diff --git a/src/udev/keymap/keymaps/toshiba-satellite_m30x b/src/udev/keymap/keymaps/toshiba-satellite_m30x
new file mode 100644 (file)
index 0000000..ae8e349
--- /dev/null
@@ -0,0 +1,6 @@
+0xef brightnessdown
+0xd9 brightnessup
+0xee screenlock
+0x93 media
+0x9e f22 #touchpad_enable
+0x9f f23 #touchpad_disable
diff --git a/src/udev/keymap/keymaps/zepto-znote b/src/udev/keymap/keymaps/zepto-znote
new file mode 100644 (file)
index 0000000..cf72fda
--- /dev/null
@@ -0,0 +1,11 @@
+0x93 switchvideomode    # Fn+F3 Toggle Video Output
+0x95 brightnessdown     # Fn+F4 Brightness Down
+0x91 brightnessup       # Fn+F5 Brightness Up
+0xA5 f23                # Fn+F6 Disable Touchpad
+0xA6 f22                # Fn+F6 Enable Touchpad
+0xA7 bluetooth          # Fn+F10 Enable Bluetooth
+0XA9 bluetooth          # Fn+F10 Disable Bluetooth
+0xF1 wlan               # RF Switch Off
+0xF2 wlan               # RF Switch On
+0xF4 prog1              # P1 Button
+0xF3 prog2              # P2 Button
diff --git a/src/udev/libudev-device-private.c b/src/udev/libudev-device-private.c
new file mode 100644 (file)
index 0000000..13fdb8e
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "libudev.h"
+#include "libudev-private.h"
+
+static void udev_device_tag(struct udev_device *dev, const char *tag, bool add)
+{
+        const char *id;
+        struct udev *udev = udev_device_get_udev(dev);
+        char filename[UTIL_PATH_SIZE];
+
+        id = udev_device_get_id_filename(dev);
+        if (id == NULL)
+                return;
+        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/tags/", tag, "/", id, NULL);
+
+        if (add) {
+                int fd;
+
+                util_create_path(udev, filename);
+                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 (strcmp(tag, tag_old) == 0) {
+                                        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)
+{
+        bool has_info;
+        const char *id;
+        struct udev *udev = udev_device_get_udev(udev_device);
+        char filename[UTIL_PATH_SIZE];
+        char filename_tmp[UTIL_PATH_SIZE];
+        FILE *f;
+
+        id = udev_device_get_id_filename(udev_device);
+        if (id == NULL)
+                return -1;
+
+        has_info = device_has_info(udev_device);
+        util_strscpyl(filename, sizeof(filename), udev_get_run_path(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 */
+        util_strscpyl(filename_tmp, sizeof(filename_tmp), filename, ".tmp", NULL);
+        util_create_path(udev, filename_tmp);
+        f = fopen(filename_tmp, "we");
+        if (f == NULL) {
+                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) {
+                        size_t devlen = strlen(udev_get_dev_path(udev))+1;
+
+                        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)[devlen]);
+                        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", 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);
+        rename(filename_tmp, filename);
+        info(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;
+        struct udev *udev = udev_device_get_udev(udev_device);
+        char filename[UTIL_PATH_SIZE];
+
+        id = udev_device_get_id_filename(udev_device);
+        if (id == NULL)
+                return -1;
+        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/data/", id, NULL);
+        unlink(filename);
+        return 0;
+}
diff --git a/src/udev/libudev-device.c b/src/udev/libudev-device.c
new file mode 100644 (file)
index 0000000..10f28b8
--- /dev/null
@@ -0,0 +1,1744 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <net/if.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/sockios.h>
+
+#include "libudev.h"
+#include "libudev-private.h"
+
+/**
+ * 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 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;
+        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;
+        unsigned long long int 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.
+ **/
+UDEV_EXPORT 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
+ *
+ * Returns: the device major/minor number.
+ **/
+UDEV_EXPORT 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
+ *
+ * Returns: the driver string, or #NULL if there is no driver attached.
+ **/
+UDEV_EXPORT 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
+ **/
+UDEV_EXPORT 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;
+}
+
+static 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
+ **/
+UDEV_EXPORT 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 (strncmp(udev_device->devpath, "/module/", 8) == 0) {
+                        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 (strncmp(udev_device->devpath, "/subsystem/", 11) == 0 ||
+                    strncmp(udev_device->devpath, "/class/", 7) == 0 ||
+                    strncmp(udev_device->devpath, "/bus/", 5) == 0) {
+                        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;
+}
+
+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;
+
+        util_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 (strncmp(property, "DEVPATH=", 8) == 0) {
+                char path[UTIL_PATH_SIZE];
+
+                util_strscpyl(path, sizeof(path), udev_get_sys_path(udev_device->udev), &property[8], NULL);
+                udev_device_set_syspath(udev_device, path);
+        } else if (strncmp(property, "SUBSYSTEM=", 10) == 0) {
+                udev_device_set_subsystem(udev_device, &property[10]);
+        } else if (strncmp(property, "DEVTYPE=", 8) == 0) {
+                udev_device_set_devtype(udev_device, &property[8]);
+        } else if (strncmp(property, "DEVNAME=", 8) == 0) {
+                udev_device_set_devnode(udev_device, &property[8]);
+        } else if (strncmp(property, "DEVLINKS=", 9) == 0) {
+                char devlinks[UTIL_PATH_SIZE];
+                char *slink;
+                char *next;
+
+                util_strscpy(devlinks, sizeof(devlinks), &property[9]);
+                slink = devlinks;
+                next = strchr(slink, ' ');
+                while (next != NULL) {
+                        next[0] = '\0';
+                        udev_device_add_devlink(udev_device, slink, 0);
+                        slink = &next[1];
+                        next = strchr(slink, ' ');
+                }
+                if (slink[0] != '\0')
+                        udev_device_add_devlink(udev_device, slink, 0);
+        } else if (strncmp(property, "TAGS=", 5) == 0) {
+                char tags[UTIL_PATH_SIZE];
+                char *next;
+
+                util_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 (strncmp(property, "USEC_INITIALIZED=", 19) == 0) {
+                udev_device_set_usec_initialized(udev_device, strtoull(&property[19], NULL, 10));
+        } else if (strncmp(property, "DRIVER=", 7) == 0) {
+                udev_device_set_driver(udev_device, &property[7]);
+        } else if (strncmp(property, "ACTION=", 7) == 0) {
+                udev_device_set_action(udev_device, &property[7]);
+        } else if (strncmp(property, "MAJOR=", 6) == 0) {
+                udev_device->maj = strtoull(&property[6], NULL, 10);
+        } else if (strncmp(property, "MINOR=", 6) == 0) {
+                udev_device->min = strtoull(&property[6], NULL, 10);
+        } else if (strncmp(property, "DEVPATH_OLD=", 12) == 0) {
+                udev_device_set_devpath_old(udev_device, &property[12]);
+        } else if (strncmp(property, "SEQNUM=", 7) == 0) {
+                udev_device_set_seqnum(udev_device, strtoull(&property[7], NULL, 10));
+        } else if (strncmp(property, "IFINDEX=", 8) == 0) {
+                udev_device_set_ifindex(udev_device, strtoull(&property[8], NULL, 10));
+        } else if (strncmp(property, "DEVMODE=", 8) == 0) {
+                udev_device_set_devnode_mode(udev_device, strtoul(&property[8], NULL, 8));
+        } 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
+ *
+ * Returns: the value of a device property, or #NULL if there is no such property.
+ **/
+UDEV_EXPORT 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;
+                util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev_device->udev), "/data/", id, NULL);
+                dbfile = filename;
+        }
+
+        f = fopen(dbfile, "re");
+        if (f == NULL) {
+                info(udev_device->udev, "no db file to read %s: %m\n", dbfile);
+                return -1;
+        }
+        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':
+                        util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_device->udev), "/", val, NULL);
+                        udev_device_add_devlink(udev_device, filename, 0);
+                        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);
+
+        info(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;
+
+        util_strscpyl(filename, sizeof(filename), udev_device->syspath, "/uevent", NULL);
+        f = fopen(filename, "re");
+        if (f == NULL)
+                return -1;
+        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 (strncmp(line, "DEVTYPE=", 8) == 0) {
+                        udev_device_set_devtype(udev_device, &line[8]);
+                        continue;
+                }
+                if (strncmp(line, "IFINDEX=", 8) == 0) {
+                        udev_device_set_ifindex(udev_device, strtoull(&line[8], NULL, 10));
+                        continue;
+                }
+                if (strncmp(line, "DEVNAME=", 8) == 0) {
+                        udev_device_set_devnode(udev_device, &line[8]);
+                        continue;
+                }
+
+                if (strncmp(line, "MAJOR=", 6) == 0)
+                        maj = strtoull(&line[6], NULL, 10);
+                else if (strncmp(line, "MINOR=", 6) == 0)
+                        min = strtoull(&line[6], NULL, 10);
+                else if (strncmp(line, "DEVMODE=", 8) == 0)
+                        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 = calloc(1, sizeof(struct udev_device));
+        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));
+        dbg(udev_device->udev, "udev_device: %p created\n", udev_device);
+        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
+ **/
+UDEV_EXPORT struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath)
+{
+        size_t len;
+        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 */
+        len = strlen(udev_get_sys_path(udev));
+        if (strncmp(syspath, udev_get_sys_path(udev), len) != 0) {
+                info(udev, "not in sys :%s\n", syspath);
+                return NULL;
+        }
+
+        /* path is not a root directory */
+        subdir = &syspath[len+1];
+        pos = strrchr(subdir, '/');
+        if (pos == NULL || pos[1] == '\0' || pos < &subdir[2]) {
+                dbg(udev, "not a subdir :%s\n", syspath);
+                return NULL;
+        }
+
+        /* resolve possible symlink to real path */
+        util_strscpy(path, sizeof(path), syspath);
+        util_resolve_sys_link(udev, path, sizeof(path));
+
+        if (strncmp(&path[len], "/devices/", 9) == 0) {
+                char file[UTIL_PATH_SIZE];
+
+                /* all "devices" require a "uevent" file */
+                util_strscpyl(file, sizeof(file), path, "/uevent", NULL);
+                if (stat(file, &statbuf) != 0) {
+                        dbg(udev, "not a device: %s\n", syspath);
+                        return NULL;
+                }
+        } else {
+                /* everything else just needs to be a directory */
+                if (stat(path, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) {
+                        dbg(udev, "directory not found: %s\n", syspath);
+                        return NULL;
+                }
+        }
+
+        udev_device = udev_device_new(udev);
+        if (udev_device == NULL)
+                return NULL;
+
+        udev_device_set_syspath(udev_device, path);
+        info(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
+ **/
+UDEV_EXPORT 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}/<maj>:<min> link */
+        snprintf(path, sizeof(path), "%s/dev/%s/%u:%u",
+                 udev_get_sys_path(udev), type_str, major(devnum), minor(devnum));
+        return udev_device_new_from_syspath(udev, path);
+}
+
+struct udev_device *udev_device_new_from_id_filename(struct udev *udev, 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;
+                memset(&ifr, 0x00, 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 '+':
+                util_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
+ **/
+UDEV_EXPORT struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname)
+{
+        char path_full[UTIL_PATH_SIZE];
+        char *path;
+        size_t l;
+        struct stat statbuf;
+
+        path = path_full;
+        l = util_strpcpyl(&path, sizeof(path_full), udev_get_sys_path(udev), NULL);
+
+        if (strcmp(subsystem, "subsystem") == 0) {
+                util_strscpyl(path, l, "/subsystem/", sysname, NULL);
+                if (stat(path_full, &statbuf) == 0)
+                        goto found;
+
+                util_strscpyl(path, l, "/bus/", sysname, NULL);
+                if (stat(path_full, &statbuf) == 0)
+                        goto found;
+
+                util_strscpyl(path, l, "/class/", sysname, NULL);
+                if (stat(path_full, &statbuf) == 0)
+                        goto found;
+                goto out;
+        }
+
+        if (strcmp(subsystem, "module") == 0) {
+                util_strscpyl(path, l, "/module/", sysname, NULL);
+                if (stat(path_full, &statbuf) == 0)
+                        goto found;
+                goto out;
+        }
+
+        if (strcmp(subsystem, "drivers") == 0) {
+                char subsys[UTIL_NAME_SIZE];
+                char *driver;
+
+                util_strscpy(subsys, sizeof(subsys), sysname);
+                driver = strchr(subsys, ':');
+                if (driver != NULL) {
+                        driver[0] = '\0';
+                        driver = &driver[1];
+
+                        util_strscpyl(path, l, "/subsystem/", subsys, "/drivers/", driver, NULL);
+                        if (stat(path_full, &statbuf) == 0)
+                                goto found;
+
+                        util_strscpyl(path, l, "/bus/", subsys, "/drivers/", driver, NULL);
+                        if (stat(path_full, &statbuf) == 0)
+                                goto found;
+                }
+                goto out;
+        }
+
+        util_strscpyl(path, l, "/subsystem/", subsystem, "/devices/", sysname, NULL);
+        if (stat(path_full, &statbuf) == 0)
+                goto found;
+
+        util_strscpyl(path, l, "/bus/", subsystem, "/devices/", sysname, NULL);
+        if (stat(path_full, &statbuf) == 0)
+                goto found;
+
+        util_strscpyl(path, l, "/class/", subsystem, "/", sysname, NULL);
+        if (stat(path_full, &statbuf) == 0)
+                goto found;
+out:
+        return NULL;
+found:
+        return udev_device_new_from_syspath(udev, path_full);
+}
+
+/**
+ * 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
+ **/
+UDEV_EXPORT 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) {
+                info(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;
+
+        util_strscpy(path, sizeof(path), udev_device->syspath);
+        subdir = &path[strlen(udev_get_sys_path(udev_device->udev))+1];
+        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.
+ *
+ * The returned the 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.
+ **/
+UDEV_EXPORT 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);
+        }
+        if (udev_device->parent_device != NULL)
+                dbg(udev_device->udev, "returning existing parent %p\n", udev_device->parent_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.
+ *
+ * The returned the 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.
+ **/
+UDEV_EXPORT 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 && strcmp(parent_subsystem, subsystem) == 0) {
+                        if (devtype == NULL)
+                                break;
+                        parent_devtype = udev_device_get_devtype(parent);
+                        if (parent_devtype != NULL && strcmp(parent_devtype, devtype) == 0)
+                                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
+ **/
+UDEV_EXPORT 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
+ **/
+UDEV_EXPORT 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.
+ *
+ **/
+UDEV_EXPORT void udev_device_unref(struct udev_device *udev_device)
+{
+        if (udev_device == NULL)
+                return;
+        udev_device->refcount--;
+        if (udev_device->refcount > 0)
+                return;
+        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);
+        dbg(udev_device->udev, "udev_device: %p released\n", udev_device);
+        free(udev_device);
+}
+
+/**
+ * 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
+ **/
+UDEV_EXPORT 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
+ **/
+UDEV_EXPORT 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
+ *
+ * Returns: the sys name of the device device
+ **/
+UDEV_EXPORT 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
+ *
+ * Returns: the trailing number of of the device name
+ **/
+UDEV_EXPORT 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
+ **/
+UDEV_EXPORT 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_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
+ **/
+UDEV_EXPORT 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_next(),
+ * which returns #NULL if no more entries exist. The property name
+ * can be retrieved from the list entry by udev_list_get_name(),
+ * the property value by udev_list_get_value().
+ *
+ * Returns: the first entry of the property list
+ **/
+UDEV_EXPORT 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 = util_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 = util_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 = util_strpcpyl(&s, sizeof(tags), ":", NULL);
+                        udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device))
+                                l = util_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.
+ **/
+UDEV_EXPORT 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.
+ **/
+UDEV_EXPORT unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device)
+{
+        unsigned long long now;
+
+        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 = now_usec();
+        if (now == 0)
+                return 0;
+        return now - udev_device->usec_initialized;
+}
+
+unsigned long long 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, unsigned long long usec_initialized)
+{
+        char num[32];
+
+        udev_device->usec_initialized = usec_initialized;
+        snprintf(num, sizeof(num), "%llu", 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.
+ **/
+UDEV_EXPORT 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) {
+                dbg(udev_device->udev, "got '%s' (%s) from cache\n",
+                    sysattr, udev_list_entry_get_value(list_entry));
+                return udev_list_entry_get_value(list_entry);
+        }
+
+        util_strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device), "/", sysattr, NULL);
+        if (lstat(path, &statbuf) != 0) {
+                dbg(udev_device->udev, "no attribute '%s', keep negative entry\n", path);
+                udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, NULL);
+                goto out;
+        }
+
+        if (S_ISLNK(statbuf.st_mode)) {
+                struct udev_device *dev;
+
+                /*
+                 * Some core links return only the last element of the target path,
+                 * these are just values, the paths should not be exposed.
+                 */
+                if (strcmp(sysattr, "driver") == 0 ||
+                    strcmp(sysattr, "subsystem") == 0 ||
+                    strcmp(sysattr, "module") == 0) {
+                        if (util_get_sys_core_link_value(udev_device->udev, sysattr,
+                                                         udev_device->syspath, value, sizeof(value)) < 0)
+                                return NULL;
+                        dbg(udev_device->udev, "cache '%s' with link value '%s'\n", sysattr, value);
+                        list_entry = udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, value);
+                        val = udev_list_entry_get_value(list_entry);
+                        goto out;
+                }
+
+                /* resolve link to a device and return its syspath */
+                util_strscpyl(path, sizeof(path), udev_device->syspath, "/", sysattr, NULL);
+                dev = udev_device_new_from_syspath(udev_device->udev, path);
+                if (dev != NULL) {
+                        list_entry = udev_list_entry_add(&udev_device->sysattr_value_list, sysattr,
+                                                         udev_device_get_syspath(dev));
+                        val = udev_list_entry_get_value(list_entry);
+                        udev_device_unref(dev);
+                }
+
+                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) {
+                dbg(udev_device->udev, "attribute '%s' can not be opened\n", path);
+                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');
+        dbg(udev_device->udev, "'%s' has attribute value '%s'\n", path, value);
+        list_entry = udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, value);
+        val = udev_list_entry_get_value(list_entry);
+out:
+        return val;
+}
+
+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 -1;
+        if (udev_device->sysattr_list_read)
+                return 0;
+
+        dir = opendir(udev_device_get_syspath(udev_device));
+        if (!dir) {
+                dbg(udev_device->udev, "sysfs dir '%s' can not be opened\n",
+                                udev_device_get_syspath(udev_device));
+                return -1;
+        }
+
+        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;
+
+                util_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);
+        dbg(udev_device->udev, "found %d sysattrs for '%s'\n", num, udev_device_get_syspath(udev_device));
+        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
+ **/
+UDEV_EXPORT 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(udev_get_sys_path(udev_device->udev))];
+        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;
+}
+
+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, "%s/%s", udev_get_dev_path(udev_device->udev), 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, int unique)
+{
+        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;
+        if (unique)
+                udev_list_entry_set_num(list_entry, true);
+        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",
+                                     strcmp(udev_device_get_subsystem(udev_device), "block") == 0 ? '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.
+ **/
+UDEV_EXPORT 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_next(),
+ * which returns #NULL if no more entries exist. The tag string
+ * can be retrieved from the list entry by udev_list_get_name().
+ *
+ * Returns: the first entry of the tag list
+ **/
+UDEV_EXPORT 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_EXPORT 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 = util_strpcpyl(&s, l, key, "=", udev_list_entry_get_value(list_entry), NULL);
+                if (l == 0)
+                        return -EINVAL;
+                /* advance past the trailing '\0' that util_strpcpyl() guarantees */
+                s++;
+                l--;
+        }
+        udev_device->envp[i] = NULL;
+        udev_device->monitor_buf_len = s - udev_device->monitor_buf;
+        udev_device->envp_uptodate = true;
+        dbg(udev_device->udev, "filled envp/monitor buffer, %u properties, %zu bytes\n",
+            i, udev_device->monitor_buf_len);
+        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/udev/libudev-enumerate.c b/src/udev/libudev-enumerate.c
new file mode 100644 (file)
index 0000000..034d96f
--- /dev/null
@@ -0,0 +1,947 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <fnmatch.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#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
+ *
+ * Returns: an enumeration context
+ **/
+UDEV_EXPORT struct udev_enumerate *udev_enumerate_new(struct udev *udev)
+{
+        struct udev_enumerate *udev_enumerate;
+
+        udev_enumerate = calloc(1, sizeof(struct udev_enumerate));
+        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
+ **/
+UDEV_EXPORT 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.
+ **/
+UDEV_EXPORT void udev_enumerate_unref(struct udev_enumerate *udev_enumerate)
+{
+        unsigned int i;
+
+        if (udev_enumerate == NULL)
+                return;
+        udev_enumerate->refcount--;
+        if (udev_enumerate->refcount > 0)
+                return;
+        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);
+}
+
+/**
+ * udev_enumerate_get_udev:
+ * @udev_enumerate: context
+ *
+ * Returns: the udev library context.
+ */
+UDEV_EXPORT 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
+        };
+        size_t len;
+        int i;
+
+        len = strlen(udev_get_sys_path(udev));
+        for (i = 0; delay_device_list[i] != NULL; i++) {
+                if (strstr(&syspath[len], delay_device_list[i]) != NULL) {
+                        dbg(udev, "delaying: %s\n", syspath);
+                        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 (strncmp(c, "/controlC", 9) == 0)
+                        return c - syspath + 1;
+        }
+
+        return 0;
+}
+
+/**
+ * udev_enumerate_get_list_entry:
+ * @udev_enumerate: context
+ *
+ * Returns: the first entry of the sorted list of device paths.
+ */
+UDEV_EXPORT 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;
+                unsigned int max;
+                struct syspath *prev = NULL, *move_later = NULL;
+                size_t move_later_prefix = 0;
+
+                udev_list_cleanup(&udev_enumerate->devices_list);
+                qsort(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) {
+                                move_later_prefix = devices_delay_later(udev_enumerate->udev, entry->syspath);
+
+                                if (move_later_prefix > 0) {
+                                        move_later = entry;
+                                        continue;
+                                }
+                        }
+
+                        if (move_later &&
+                            strncmp(entry->syspath, move_later->syspath, move_later_prefix) != 0) {
+
+                                udev_list_entry_add(&udev_enumerate->devices_list, move_later->syspath, NULL);
+                                move_later = NULL;
+                        }
+
+                        udev_list_entry_add(&udev_enumerate->devices_list, entry->syspath, NULL);
+                }
+
+                if (move_later)
+                        udev_list_entry_add(&udev_enumerate->devices_list, 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
+ *
+ * Returns: 0 on success, otherwise a negative error value.
+ */
+UDEV_EXPORT 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
+ *
+ * Returns: 0 on success, otherwise a negative error value.
+ */
+UDEV_EXPORT 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
+ *
+ * Returns: 0 on success, otherwise a negative error value.
+ */
+UDEV_EXPORT 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
+ *
+ * Returns: 0 on success, otherwise a negative error value.
+ */
+UDEV_EXPORT 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
+ *
+ * Returns: 0 on success, otherwise a negative error value.
+ */
+UDEV_EXPORT 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
+ *
+ * Returns: 0 on success, otherwise a negative error value.
+ */
+UDEV_EXPORT 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.
+ */
+UDEV_EXPORT 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.
+ */
+UDEV_EXPORT 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
+ *
+ * Returns: 0 on success, otherwise a negative error value.
+ */
+UDEV_EXPORT 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)
+{
+        const char *parent;
+
+        if (udev_enumerate->parent_match == NULL)
+                return true;
+
+        parent = udev_device_get_devpath(udev_enumerate->parent_match);
+        return strncmp(parent, udev_device_get_devpath(dev), strlen(parent)) == 0;
+}
+
+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)
+{
+        struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
+        char path[UTIL_PATH_SIZE];
+        size_t l;
+        char *s;
+        DIR *dir;
+        struct dirent *dent;
+
+        s = path;
+        l = util_strpcpyl(&s, sizeof(path), udev_get_sys_path(udev), "/", basedir, NULL);
+        if (subdir1 != NULL)
+                l = util_strpcpyl(&s, l, "/", subdir1, NULL);
+        if (subdir2 != NULL)
+                util_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;
+
+                util_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;
+
+        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)
+{
+        struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
+
+        char path[UTIL_PATH_SIZE];
+        DIR *dir;
+        struct dirent *dent;
+
+        util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), "/", 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.
+ */
+UDEV_EXPORT 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 *udev = udev_enumerate_get_udev(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];
+
+                util_strscpyl(path, sizeof(path), udev_get_run_path(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_id_filename(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;
+
+        dev = udev_device_new_from_syspath(enumerate->udev, path);
+        if (dev == NULL)
+                return -ENODEV;
+
+        if (!match_subsystem(enumerate, udev_device_get_subsystem(dev)))
+                return 0;
+        if (!match_sysname(enumerate, udev_device_get_sysname(dev)))
+                return 0;
+        if (!match_property(enumerate, dev))
+                return 0;
+        if (!match_sysattr(enumerate, dev))
+                return 0;
+
+        syspath_add(enumerate, udev_device_get_syspath(dev));
+        udev_device_unref(dev);
+        return 1;
+}
+
+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 udev *udev = udev_enumerate_get_udev(udev_enumerate);
+        char base[UTIL_PATH_SIZE];
+        struct stat statbuf;
+
+        util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/subsystem", NULL);
+        if (stat(base, &statbuf) == 0) {
+                /* we have /subsystem/, forget all the old stuff */
+                dbg(udev, "searching '/subsystem/*/devices/*' dir\n");
+                scan_dir(udev_enumerate, "subsystem", "devices", NULL);
+        } else {
+                dbg(udev, "searching '/bus/*/devices/*' dir\n");
+                scan_dir(udev_enumerate, "bus", "devices", NULL);
+                dbg(udev, "searching '/class/*' dir\n");
+                scan_dir(udev_enumerate, "class", NULL, NULL);
+        }
+        return 0;
+}
+
+/**
+ * udev_enumerate_scan_devices:
+ * @udev_enumerate: udev enumeration context
+ *
+ * Returns: 0 on success, otherwise a negative error value.
+ **/
+UDEV_EXPORT 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
+ *
+ * Returns: 0 on success, otherwise a negative error value.
+ **/
+UDEV_EXPORT int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate)
+{
+        struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
+        char base[UTIL_PATH_SIZE];
+        struct stat statbuf;
+        const char *subsysdir;
+
+        if (udev_enumerate == NULL)
+                return -EINVAL;
+
+        /* all kernel modules */
+        if (match_subsystem(udev_enumerate, "module")) {
+                dbg(udev, "searching 'modules/*' dir\n");
+                scan_dir_and_add_devices(udev_enumerate, "module", NULL, NULL);
+        }
+
+        util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/subsystem", NULL);
+        if (stat(base, &statbuf) == 0)
+                subsysdir = "subsystem";
+        else
+                subsysdir = "bus";
+
+        /* all subsystems (only buses support coldplug) */
+        if (match_subsystem(udev_enumerate, "subsystem")) {
+                dbg(udev, "searching '%s/*' dir\n", subsysdir);
+                scan_dir_and_add_devices(udev_enumerate, subsysdir, NULL, NULL);
+        }
+
+        /* all subsystem drivers */
+        if (match_subsystem(udev_enumerate, "drivers")) {
+                dbg(udev, "searching '%s/*/drivers/*' dir\n", subsysdir);
+                scan_dir(udev_enumerate, subsysdir, "drivers", "drivers");
+        }
+        return 0;
+}
diff --git a/src/udev/libudev-list.c b/src/udev/libudev-list.c
new file mode 100644 (file)
index 0000000..4bdef35
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#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 struct udev_list_entry *list_node_to_entry(struct udev_list_node *node)
+{
+        char *list;
+
+        list = (char *)node;
+        list -= offsetof(struct udev_list_entry, node);
+        return (struct udev_list_entry *)list;
+}
+
+void udev_list_init(struct udev *udev, struct udev_list *list, bool unique)
+{
+        memset(list, 0x00, 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  */
+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 */
+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];
+
+                        dbg(list->udev, "'%s' is already in the list\n", name);
+                        free(entry->value);
+                        if (value == NULL) {
+                                entry->value = NULL;
+                                dbg(list->udev, "'%s' value unset\n", name);
+                                return entry;
+                        }
+                        entry->value = strdup(value);
+                        if (entry->value == NULL)
+                                return NULL;
+                        dbg(list->udev, "'%s' value replaced with '%s'\n", name, value);
+                        return entry;
+                }
+        }
+
+        /* add new name */
+        entry = calloc(1, sizeof(struct udev_list_entry));
+        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) {
+                        unsigned int add;
+
+                        add = list->entries_max;
+                        if (add < 1)
+                                add = 64;
+                        list->entries = realloc(list->entries, (list->entries_max + add) * sizeof(struct udev_list_entry *));
+                        if (list->entries == NULL) {
+                                free(entry->name);
+                                free(entry->value);
+                                return NULL;
+                        }
+                        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);
+        }
+
+        dbg(list->udev, "'%s=%s' added\n", entry->name, entry->value);
+        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
+ *
+ * Returns: the next entry from the list, #NULL is no more entries are found.
+ */
+UDEV_EXPORT 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
+ *
+ * Returns: the entry where @name matched, #NULL if no matching entry is found.
+ */
+UDEV_EXPORT 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
+ *
+ * Returns: the name string of this entry.
+ */
+UDEV_EXPORT 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
+ *
+ * Returns: the value string of this entry.
+ */
+UDEV_EXPORT 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/udev/libudev-monitor.c b/src/udev/libudev-monitor.c
new file mode 100644 (file)
index 0000000..77dc555
--- /dev/null
@@ -0,0 +1,874 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/poll.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <arpa/inet.h>
+#include <linux/netlink.h>
+#include <linux/filter.h>
+
+#include "libudev.h"
+#include "libudev-private.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;
+        struct sockaddr_nl snl;
+        struct sockaddr_nl snl_trusted_sender;
+        struct sockaddr_nl snl_destination;
+        struct sockaddr_un sun;
+        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 = calloc(1, sizeof(struct udev_monitor));
+        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;
+}
+
+/**
+ * udev_monitor_new_from_socket:
+ * @udev: udev library context
+ * @socket_path: unix socket path
+ *
+ * This function should not be used in any new application. The
+ * kernel's netlink socket multiplexes messages to all interested
+ * clients. Creating custom sockets from udev to applications
+ * should be avoided.
+ *
+ * Create a new udev monitor and connect to a specified socket. The
+ * path to a socket either points to an existing socket file, or if
+ * the socket path starts with a '@' character, an abstract namespace
+ * socket will be used.
+ *
+ * A socket file will not be created. If it does not already exist,
+ * it will fall-back and connect to an abstract namespace socket with
+ * the given path. The permissions adjustment of a socket file, as
+ * well as the later cleanup, needs to be done by the caller.
+ *
+ * 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
+ **/
+UDEV_EXPORT struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path)
+{
+        struct udev_monitor *udev_monitor;
+        struct stat statbuf;
+
+        if (udev == NULL)
+                return NULL;
+        if (socket_path == NULL)
+                return NULL;
+        udev_monitor = udev_monitor_new(udev);
+        if (udev_monitor == NULL)
+                return NULL;
+
+        udev_monitor->sun.sun_family = AF_LOCAL;
+        if (socket_path[0] == '@') {
+                /* translate leading '@' to abstract namespace */
+                util_strscpy(udev_monitor->sun.sun_path, sizeof(udev_monitor->sun.sun_path), socket_path);
+                udev_monitor->sun.sun_path[0] = '\0';
+                udev_monitor->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(socket_path);
+        } else if (stat(socket_path, &statbuf) == 0 && S_ISSOCK(statbuf.st_mode)) {
+                /* existing socket file */
+                util_strscpy(udev_monitor->sun.sun_path, sizeof(udev_monitor->sun.sun_path), socket_path);
+                udev_monitor->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(socket_path);
+        } else {
+                /* no socket file, assume abstract namespace socket */
+                util_strscpy(&udev_monitor->sun.sun_path[1], sizeof(udev_monitor->sun.sun_path)-1, socket_path);
+                udev_monitor->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(socket_path)+1;
+        }
+        udev_monitor->sock = socket(AF_LOCAL, SOCK_DGRAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
+        if (udev_monitor->sock == -1) {
+                err(udev, "error getting socket: %m\n");
+                free(udev_monitor);
+                return NULL;
+        }
+
+        dbg(udev, "monitor %p created with '%s'\n", udev_monitor, socket_path);
+        return udev_monitor;
+}
+
+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 (strcmp(name, "udev") == 0)
+                group = UDEV_MONITOR_UDEV;
+        else if (strcmp(name, "kernel") == 0)
+                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) {
+                        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_family = AF_NETLINK;
+        udev_monitor->snl.nl_groups = group;
+
+        /* default destination for sending */
+        udev_monitor->snl_destination.nl_family = AF_NETLINK;
+        udev_monitor->snl_destination.nl_groups = UDEV_MONITOR_UDEV;
+
+        dbg(udev, "monitor %p created with NETLINK_KOBJECT_UEVENT (%u)\n", udev_monitor, group);
+        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
+ **/
+UDEV_EXPORT 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.
+ */
+UDEV_EXPORT 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;
+
+        memset(ins, 0x00, 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 >= ARRAY_SIZE(ins))
+                                return -1;
+                }
+
+                /* 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 */
+        memset(&filter, 0x00, sizeof(filter));
+        filter.len = i;
+        filter.filter = ins;
+        err = setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter));
+        return err;
+}
+
+int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender)
+{
+        udev_monitor->snl_trusted_sender.nl_pid = sender->snl.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.
+ */
+UDEV_EXPORT int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor)
+{
+        int err = 0;
+        const int on = 1;
+
+        if (udev_monitor->sun.sun_family != 0) {
+                if (!udev_monitor->bound) {
+                        err = bind(udev_monitor->sock,
+                                   (struct sockaddr *)&udev_monitor->sun, udev_monitor->addrlen);
+                        if (err == 0)
+                                udev_monitor->bound = true;
+                }
+        } else if (udev_monitor->snl.nl_family != 0) {
+                udev_monitor_filter_update(udev_monitor);
+                if (!udev_monitor->bound) {
+                        err = bind(udev_monitor->sock,
+                                   (struct sockaddr *)&udev_monitor->snl, sizeof(struct sockaddr_nl));
+                        if (err == 0)
+                                udev_monitor->bound = true;
+                }
+                if (err == 0) {
+                        struct sockaddr_nl 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, (struct sockaddr *)&snl, &addrlen);
+                        if (err == 0)
+                                udev_monitor->snl.nl_pid = snl.nl_pid;
+                }
+        } else {
+                return -EINVAL;
+        }
+
+        if (err < 0) {
+                err(udev_monitor->udev, "bind failed: %m\n");
+                return err;
+        }
+
+        /* 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.
+ */
+UDEV_EXPORT int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size)
+{
+        if (udev_monitor == NULL)
+                return -1;
+        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;
+}
+
+/**
+ * udev_monitor_ref:
+ * @udev_monitor: udev monitor
+ *
+ * Take a reference of a udev monitor.
+ *
+ * Returns: the passed udev monitor
+ **/
+UDEV_EXPORT 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.
+ *
+ **/
+UDEV_EXPORT void udev_monitor_unref(struct udev_monitor *udev_monitor)
+{
+        if (udev_monitor == NULL)
+                return;
+        udev_monitor->refcount--;
+        if (udev_monitor->refcount > 0)
+                return;
+        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);
+        dbg(udev_monitor->udev, "monitor %p released\n", udev_monitor);
+        free(udev_monitor);
+}
+
+/**
+ * udev_monitor_get_udev:
+ * @udev_monitor: udev monitor
+ *
+ * Retrieve the udev library context the monitor was created with.
+ *
+ * Returns: the udev library context
+ **/
+UDEV_EXPORT 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
+ **/
+UDEV_EXPORT int udev_monitor_get_fd(struct udev_monitor *udev_monitor)
+{
+        if (udev_monitor == NULL)
+                return -1;
+        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 (strcmp(dsubsys, subsys) != 0)
+                        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 (strcmp(ddevtype, devtype) == 0)
+                        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 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
+ **/
+UDEV_EXPORT 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;
+        struct sockaddr_nl snl;
+        struct ucred *cred;
+        char buf[8192];
+        ssize_t buflen;
+        ssize_t bufpos;
+        struct udev_monitor_netlink_header *nlh;
+
+retry:
+        if (udev_monitor == NULL)
+                return NULL;
+        iov.iov_base = &buf;
+        iov.iov_len = sizeof(buf);
+        memset (&smsg, 0x00, sizeof(struct msghdr));
+        smsg.msg_iov = &iov;
+        smsg.msg_iovlen = 1;
+        smsg.msg_control = cred_msg;
+        smsg.msg_controllen = sizeof(cred_msg);
+
+        if (udev_monitor->snl.nl_family != 0) {
+                smsg.msg_name = &snl;
+                smsg.msg_namelen = sizeof(snl);
+        }
+
+        buflen = recvmsg(udev_monitor->sock, &smsg, 0);
+        if (buflen < 0) {
+                if (errno != EINTR)
+                        info(udev_monitor->udev, "unable to receive message\n");
+                return NULL;
+        }
+
+        if (buflen < 32 || (size_t)buflen >= sizeof(buf)) {
+                info(udev_monitor->udev, "invalid message length\n");
+                return NULL;
+        }
+
+        if (udev_monitor->snl.nl_family != 0) {
+                if (snl.nl_groups == 0) {
+                        /* unicast message, check if we trust the sender */
+                        if (udev_monitor->snl_trusted_sender.nl_pid == 0 ||
+                            snl.nl_pid != udev_monitor->snl_trusted_sender.nl_pid) {
+                                info(udev_monitor->udev, "unicast netlink message ignored\n");
+                                return NULL;
+                        }
+                } else if (snl.nl_groups == UDEV_MONITOR_KERNEL) {
+                        if (snl.nl_pid > 0) {
+                                info(udev_monitor->udev, "multicast kernel netlink message from pid %d ignored\n",
+                                     snl.nl_pid);
+                                return NULL;
+                        }
+                }
+        }
+
+        cmsg = CMSG_FIRSTHDR(&smsg);
+        if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
+                info(udev_monitor->udev, "no sender credentials received, message ignored\n");
+                return NULL;
+        }
+
+        cred = (struct ucred *)CMSG_DATA(cmsg);
+        if (cred->uid != 0) {
+                info(udev_monitor->udev, "sender uid=%d, message ignored\n", cred->uid);
+                return NULL;
+        }
+
+        if (memcmp(buf, "libudev", 8) == 0) {
+                /* udev message needs proper version magic */
+                nlh = (struct udev_monitor_netlink_header *) buf;
+                if (nlh->magic != htonl(UDEV_MONITOR_MAGIC)) {
+                        err(udev_monitor->udev, "unrecognized message signature (%x != %x)\n",
+                            nlh->magic, htonl(UDEV_MONITOR_MAGIC));
+                        return NULL;
+                }
+                if (nlh->properties_off+32 > buflen)
+                        return NULL;
+                bufpos = nlh->properties_off;
+        } else {
+                /* kernel message with header */
+                bufpos = strlen(buf) + 1;
+                if ((size_t)bufpos < sizeof("a@/d") || bufpos >= buflen) {
+                        info(udev_monitor->udev, "invalid message length\n");
+                        return NULL;
+                }
+
+                /* check message header */
+                if (strstr(buf, "@/") == NULL) {
+                        info(udev_monitor->udev, "unrecognized message header\n");
+                        return NULL;
+                }
+        }
+
+        udev_device = udev_device_new(udev_monitor->udev);
+        if (udev_device == NULL)
+                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) {
+                info(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;
+
+        blen = udev_device_get_properties_monitor_buf(udev_device, &buf);
+        if (blen < 32)
+                return -EINVAL;
+
+        if (udev_monitor->sun.sun_family != 0) {
+                struct msghdr smsg;
+                struct iovec iov[2];
+                const char *action;
+                char header[2048];
+                char *s;
+
+                /* header <action>@<devpath> */
+                action = udev_device_get_action(udev_device);
+                if (action == NULL)
+                        return -EINVAL;
+                s = header;
+                if (util_strpcpyl(&s, sizeof(header), action, "@", udev_device_get_devpath(udev_device), NULL) == 0)
+                        return -EINVAL;
+                iov[0].iov_base = header;
+                iov[0].iov_len = (s - header)+1;
+
+                /* add properties list */
+                iov[1].iov_base = (char *)buf;
+                iov[1].iov_len = blen;
+
+                memset(&smsg, 0x00, sizeof(struct msghdr));
+                smsg.msg_iov = iov;
+                smsg.msg_iovlen = 2;
+                smsg.msg_name = &udev_monitor->sun;
+                smsg.msg_namelen = udev_monitor->addrlen;
+                count = sendmsg(udev_monitor->sock, &smsg, 0);
+                info(udev_monitor->udev, "passed %zi bytes to socket monitor %p\n", count, udev_monitor);
+                return count;
+        }
+
+        if (udev_monitor->snl.nl_family != 0) {
+                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;
+
+                /* add versioned header */
+                memset(&nlh, 0x00, 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;
+
+                memset(&smsg, 0x00, 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);
+                info(udev_monitor->udev, "passed %zi bytes to netlink monitor %p\n", count, udev_monitor);
+                return count;
+        }
+
+        return -EINVAL;
+}
+
+/**
+ * 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.
+ */
+UDEV_EXPORT 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.
+ */
+UDEV_EXPORT 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.
+ */
+UDEV_EXPORT 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/udev/libudev-private.h b/src/udev/libudev-private.h
new file mode 100644 (file)
index 0000000..4bbd842
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.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.
+ */
+
+#ifndef _LIBUDEV_PRIVATE_H_
+#define _LIBUDEV_PRIVATE_H_
+
+#include <syslog.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include "libudev.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#define READ_END                                0
+#define WRITE_END                                1
+
+static inline void __attribute__((always_inline, format(printf, 2, 3)))
+udev_log_null(struct udev *udev, const char *format, ...) {}
+
+#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)
+
+#ifdef ENABLE_LOGGING
+#  ifdef ENABLE_DEBUG
+#    define dbg(udev, arg...) udev_log_cond(udev, LOG_DEBUG, ## arg)
+#  else
+#    define dbg(udev, arg...) udev_log_null(udev, ## arg)
+#  endif
+#  define info(udev, arg...) udev_log_cond(udev, LOG_INFO, ## arg)
+#  define err(udev, arg...) udev_log_cond(udev, LOG_ERR, ## arg)
+#else
+#  define dbg(udev, arg...) udev_log_null(udev, ## arg)
+#  define info(udev, arg...) udev_log_null(udev, ## arg)
+#  define err(udev, arg...) udev_log_null(udev, ## arg)
+#endif
+
+#define UDEV_EXPORT __attribute__ ((visibility("default")))
+
+static inline void udev_log_init(const char *program_name)
+{
+        openlog(program_name, LOG_PID | LOG_CONS, LOG_DAEMON);
+}
+
+static inline void udev_log_close(void)
+{
+        closelog();
+}
+
+/* libudev.c */
+void udev_log(struct udev *udev,
+              int priority, const char *file, int line, const char *fn,
+              const char *format, ...)
+              __attribute__((format(printf, 6, 7)));
+int udev_get_rules_path(struct udev *udev, char **path[], unsigned long long *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);
+struct udev_device *udev_device_new_from_id_filename(struct udev *udev, char *id);
+mode_t udev_device_get_devnode_mode(struct udev_device *udev_device);
+int udev_device_set_syspath(struct udev_device *udev_device, const char *syspath);
+int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode);
+int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink, int unique);
+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);
+unsigned long long udev_device_get_usec_initialized(struct udev_device *udev_device);
+void udev_device_set_usec_initialized(struct udev_device *udev_device, unsigned long long 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);
+void udev_list_entry_insert_before(struct udev_list_entry *new, struct udev_list_entry *entry);
+void udev_list_entry_append(struct udev_list_entry *new, struct udev_list *list);
+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-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);
+size_t util_path_decode(char *s);
+void util_remove_trailing_chars(char *path, char c);
+size_t util_strpcpy(char **dest, size_t size, const char *src);
+size_t util_strpcpyl(char **dest, size_t size, const char *src, ...) __attribute__((sentinel));
+size_t util_strscpy(char *dest, size_t size, const char *src);
+size_t util_strscpyl(char *dest, size_t size, const char *src, ...) __attribute__((sentinel));
+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_create_path(struct udev *udev, const char *path);
+int util_create_path_selinux(struct udev *udev, const char *path);
+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);
+unsigned long long ts_usec(const struct timespec *ts);
+unsigned long long now_usec(void);
+
+/* libudev-selinux-private.c */
+#ifndef HAVE_SELINUX
+static inline void udev_selinux_init(struct udev *udev) {}
+static inline void udev_selinux_exit(struct udev *udev) {}
+static inline void udev_selinux_lsetfilecon(struct udev *udev, const char *file, unsigned int mode) {}
+static inline void udev_selinux_setfscreatecon(struct udev *udev, const char *file, unsigned int mode) {}
+static inline void udev_selinux_setfscreateconat(struct udev *udev, int dfd, const char *file, unsigned int mode) {}
+static inline void udev_selinux_resetfscreatecon(struct udev *udev) {}
+#else
+void udev_selinux_init(struct udev *udev);
+void udev_selinux_exit(struct udev *udev);
+void udev_selinux_lsetfilecon(struct udev *udev, const char *file, unsigned int mode);
+void udev_selinux_setfscreatecon(struct udev *udev, const char *file, unsigned int mode);
+void udev_selinux_setfscreateconat(struct udev *udev, int dfd, const char *file, unsigned int mode);
+void udev_selinux_resetfscreatecon(struct udev *udev);
+#endif
+
+#endif
diff --git a/src/udev/libudev-queue-private.c b/src/udev/libudev-queue-private.c
new file mode 100644 (file)
index 0000000..7177195
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2009 Alan Jenkins <alan-jenkins@tuffmail.co.uk>
+ *
+ * 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.
+ */
+
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <limits.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#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 = calloc(1, sizeof(struct udev_queue_export));
+        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)
+{
+        char filename[UTIL_PATH_SIZE];
+
+        if (udev_queue_export == NULL)
+                return;
+        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev_queue_export->udev), "/queue.tmp", NULL);
+        unlink(filename);
+        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev_queue_export->udev), "/queue.bin", NULL);
+        unlink(filename);
+}
+
+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[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) {
+                err(udev_queue_export->udev, "queue file overflow\n");
+                return NULL;
+        }
+        devpaths = calloc(1, 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:
+        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;
+        char filename[UTIL_PATH_SIZE];
+        char filename_tmp[UTIL_PATH_SIZE];
+        FILE *new_queue_file = NULL;
+        unsigned int i;
+
+        /* read old queue file */
+        if (udev_queue_export->queue_file != NULL) {
+                dbg(udev_queue_export->udev, "compacting queue file, freeing %d bytes\n",
+                                                udev_queue_export->waste_bytes);
+
+                devpaths = build_index(udev_queue_export);
+                if (devpaths != NULL)
+                        udev_queue_export->seqnum_max += devpaths->devpaths_first;
+        }
+        if (devpaths == NULL) {
+                dbg(udev_queue_export->udev, "creating empty queue file\n");
+                udev_queue_export->queued_count = 0;
+                udev_queue_export->seqnum_max = udev_queue_export->seqnum_min;
+        }
+
+        /* create new queue file */
+        util_strscpyl(filename_tmp, sizeof(filename_tmp), udev_get_run_path(udev_queue_export->udev), "/queue.tmp", NULL);
+        new_queue_file = fopen(filename_tmp, "w+");
+        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 */
+        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev_queue_export->udev), "/queue.bin", NULL);
+        if (rename(filename_tmp, filename) != 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:
+        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) {
+                dbg(udev_queue_export->udev, "can't record event: queue file not available\n");
+                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. */
+        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/udev/libudev-queue.c b/src/udev/libudev-queue.c
new file mode 100644 (file)
index 0000000..0e82cb6
--- /dev/null
@@ -0,0 +1,474 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2009 Alan Jenkins <alan-jenkins@tuffmail.co.uk>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/stat.h>
+
+#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.
+ **/
+UDEV_EXPORT struct udev_queue *udev_queue_new(struct udev *udev)
+{
+        struct udev_queue *udev_queue;
+
+        if (udev == NULL)
+                return NULL;
+
+        udev_queue = calloc(1, sizeof(struct udev_queue));
+        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.
+ **/
+UDEV_EXPORT 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.
+ **/
+UDEV_EXPORT void udev_queue_unref(struct udev_queue *udev_queue)
+{
+        if (udev_queue == NULL)
+                return;
+        udev_queue->refcount--;
+        if (udev_queue->refcount > 0)
+                return;
+        udev_list_cleanup(&udev_queue->queue_list);
+        free(udev_queue);
+}
+
+/**
+ * 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.
+ **/
+UDEV_EXPORT 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)
+{
+        char filename[UTIL_PATH_SIZE];
+        unsigned long long int seqnum;
+        int fd;
+        char buf[32];
+        ssize_t len;
+
+        util_strscpyl(filename, sizeof(filename), udev_get_sys_path(udev), "/kernel/uevent_seqnum", NULL);
+        fd = open(filename, 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
+ *
+ * Returns: the current kernel event sequence number.
+ **/
+UDEV_EXPORT 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);
+        dbg(udev_queue->udev, "seqnum=%llu\n", seqnum);
+        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[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[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)
+{
+        char filename[UTIL_PATH_SIZE];
+        FILE *queue_file;
+
+        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev_queue->udev), "/queue.bin", NULL);
+        queue_file = fopen(filename, "re");
+        if (queue_file == NULL)
+                return NULL;
+
+        if (udev_queue_read_seqnum(queue_file, seqnum_start) < 0) {
+                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
+ *
+ * Returns: the last known udev event sequence number.
+ **/
+UDEV_EXPORT 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
+ *
+ * Returns: a flag indicating if udev is active.
+ **/
+UDEV_EXPORT 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
+ *
+ * Returns: a flag indicating if udev is currently handling events.
+ **/
+UDEV_EXPORT 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) {
+                dbg(udev_queue->udev, "queue is not empty\n");
+                goto out;
+        }
+
+        seqnum_kernel = udev_queue_get_kernel_seqnum(udev_queue);
+        if (seqnum_udev < seqnum_kernel) {
+                dbg(udev_queue->udev, "queue is empty but kernel events still pending [%llu]<->[%llu]\n",
+                                      seqnum_kernel, seqnum_udev);
+                goto out;
+        }
+
+        dbg(udev_queue->udev, "queue is empty\n");
+        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
+ *
+ * Returns: a flag indicating if any of the sequence numbers in the given range is currently active.
+ **/
+UDEV_EXPORT 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
+ *
+ * Returns: a flag indicating if the given sequence number is currently active.
+ **/
+UDEV_EXPORT 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;
+
+        dbg(udev_queue->udev, "seqnum: %llu finished\n", seqnum);
+        return 1;
+}
+
+/**
+ * udev_queue_get_queued_list_entry:
+ * @udev_queue: udev queue context
+ *
+ * Returns: the first entry of the list of queued events.
+ **/
+UDEV_EXPORT 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 = util_strpcpyl(&s, sizeof(syspath), udev_get_sys_path(udev_queue->udev), NULL);
+                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 (strcmp(seqnum_str, udev_list_entry_get_value(list_entry)) == 0) {
+                                        udev_list_entry_delete(list_entry);
+                                        break;
+                                }
+                        }
+                }
+        }
+        fclose(queue_file);
+
+        return udev_list_get_entry(&udev_queue->queue_list);
+}
+
+struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue);
+UDEV_EXPORT struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue)
+{
+        errno = ENOSYS;
+        return NULL;
+}
diff --git a/src/udev/libudev-selinux-private.c b/src/udev/libudev-selinux-private.c
new file mode 100644 (file)
index 0000000..0f2a617
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <selinux/selinux.h>
+
+#include "libudev.h"
+#include "libudev-private.h"
+
+static int selinux_enabled;
+security_context_t selinux_prev_scontext;
+
+void udev_selinux_init(struct udev *udev)
+{
+        /* record the present security context */
+        selinux_enabled = (is_selinux_enabled() > 0);
+        info(udev, "selinux=%i\n", selinux_enabled);
+        if (!selinux_enabled)
+                return;
+        matchpathcon_init_prefix(NULL, udev_get_dev_path(udev));
+        if (getfscreatecon(&selinux_prev_scontext) < 0) {
+                err(udev, "getfscreatecon failed\n");
+                selinux_prev_scontext = NULL;
+        }
+}
+
+void udev_selinux_exit(struct udev *udev)
+{
+        if (!selinux_enabled)
+                return;
+        freecon(selinux_prev_scontext);
+        selinux_prev_scontext = NULL;
+}
+
+void udev_selinux_lsetfilecon(struct udev *udev, const char *file, unsigned int mode)
+{
+        security_context_t scontext = NULL;
+
+        if (!selinux_enabled)
+                return;
+        if (matchpathcon(file, mode, &scontext) < 0) {
+                err(udev, "matchpathcon(%s) failed\n", file);
+                return;
+        }
+        if (lsetfilecon(file, scontext) < 0)
+                err(udev, "setfilecon %s failed: %m\n", file);
+        freecon(scontext);
+}
+
+void udev_selinux_setfscreatecon(struct udev *udev, const char *file, unsigned int mode)
+{
+        security_context_t scontext = NULL;
+
+        if (!selinux_enabled)
+                return;
+
+        if (matchpathcon(file, mode, &scontext) < 0) {
+                err(udev, "matchpathcon(%s) failed\n", file);
+                return;
+        }
+        if (setfscreatecon(scontext) < 0)
+                err(udev, "setfscreatecon %s failed: %m\n", file);
+        freecon(scontext);
+}
+
+void udev_selinux_resetfscreatecon(struct udev *udev)
+{
+        if (!selinux_enabled)
+                return;
+        if (setfscreatecon(selinux_prev_scontext) < 0)
+                err(udev, "setfscreatecon failed: %m\n");
+}
+
+void udev_selinux_setfscreateconat(struct udev *udev, int dfd, const char *file, unsigned int mode)
+{
+        char filename[UTIL_PATH_SIZE];
+
+        if (!selinux_enabled)
+                return;
+
+        /* resolve relative filename */
+        if (file[0] != '/') {
+                char procfd[UTIL_PATH_SIZE];
+                char target[UTIL_PATH_SIZE];
+                ssize_t len;
+
+                snprintf(procfd, sizeof(procfd), "/proc/%u/fd/%u", getpid(), dfd);
+                len = readlink(procfd, target, sizeof(target));
+                if (len <= 0 || len == sizeof(target))
+                        return;
+                target[len] = '\0';
+
+                util_strscpyl(filename, sizeof(filename), target, "/", file, NULL);
+                file = filename;
+        }
+        udev_selinux_setfscreatecon(udev, file, mode);
+}
diff --git a/src/udev/libudev-util-private.c b/src/udev/libudev-util-private.c
new file mode 100644 (file)
index 0000000..08f0ba2
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2003-2009 Kay Sievers <kay.sievers@vrfy.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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/param.h>
+
+#include "libudev.h"
+#include "libudev-private.h"
+
+static int create_path(struct udev *udev, const char *path, bool selinux)
+{
+        char p[UTIL_PATH_SIZE];
+        char *pos;
+        struct stat stats;
+        int err;
+
+        util_strscpy(p, sizeof(p), path);
+        pos = strrchr(p, '/');
+        if (pos == NULL)
+                return 0;
+        while (pos != p && pos[-1] == '/')
+                pos--;
+        if (pos == p)
+                return 0;
+        pos[0] = '\0';
+
+        dbg(udev, "stat '%s'\n", p);
+        if (stat(p, &stats) == 0) {
+                if ((stats.st_mode & S_IFMT) == S_IFDIR)
+                        return 0;
+                else
+                        return -ENOTDIR;
+        }
+
+        err = util_create_path(udev, p);
+        if (err != 0)
+                return err;
+
+        dbg(udev, "mkdir '%s'\n", p);
+        if (selinux)
+                udev_selinux_setfscreatecon(udev, p, S_IFDIR|0755);
+        err = mkdir(p, 0755);
+        if (err != 0) {
+                err = -errno;
+                if (err == -EEXIST && stat(p, &stats) == 0) {
+                        if ((stats.st_mode & S_IFMT) == S_IFDIR)
+                                err = 0;
+                        else
+                                err = -ENOTDIR;
+                }
+        }
+        if (selinux)
+                udev_selinux_resetfscreatecon(udev);
+        return err;
+}
+
+int util_create_path(struct udev *udev, const char *path)
+{
+        return create_path(udev, path, false);
+}
+
+int util_create_path_selinux(struct udev *udev, const char *path)
+{
+        return create_path(udev, path, true);
+}
+
+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++;
+        util_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;
+        size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
+        char buf[buflen];
+        struct passwd pwbuf;
+        struct passwd *pw;
+        uid_t uid;
+
+        if (strcmp(user, "root") == 0)
+                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)
+                err(udev, "specified user '%s' unknown\n", user);
+        else
+                err(udev, "error resolving user '%s': %m\n", user);
+        return 0;
+}
+
+gid_t util_lookup_group(struct udev *udev, const char *group)
+{
+        char *endptr;
+        size_t buflen = sysconf(_SC_GETGR_R_SIZE_MAX);
+        char *buf;
+        struct group grbuf;
+        struct group *gr;
+        gid_t gid = 0;
+
+        if (strcmp(group, "root") == 0)
+                return 0;
+        gid = strtoul(group, &endptr, 10);
+        if (endptr[0] == '\0')
+                return gid;
+        buf = NULL;
+        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) {
+                        err(udev, "specified group '%s' unknown\n", group);
+                } else {
+                        err(udev, "error resolving group '%s': %m\n", group);
+                }
+                break;
+        }
+        free(buf);
+        return gid;
+}
+
+/* handle "[<SUBSYSTEM>/<KERNEL>]<attribute>" 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;
+
+        util_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)
+                        util_strscpy(result, maxsize, val);
+                else
+                        result[0] = '\0';
+                info(udev, "value '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result);
+        } else {
+                size_t l;
+                char *s;
+
+                s = result;
+                l = util_strpcpyl(&s, maxsize, udev_device_get_syspath(dev), NULL);
+                if (attr != NULL)
+                        util_strpcpyl(&s, l, "/", attr, NULL);
+                info(udev, "path '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result);
+        }
+        udev_device_unref(dev);
+        return 0;
+}
diff --git a/src/udev/libudev-util.c b/src/udev/libudev-util.c
new file mode 100644 (file)
index 0000000..7e345f0
--- /dev/null
@@ -0,0 +1,570 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008-2011 Kay Sievers <kay.sievers@vrfy.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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+
+#include "libudev.h"
+#include "libudev-private.h"
+
+/**
+ * SECTION:libudev-util
+ * @short_description: utils
+ */
+
+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;
+
+        util_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];
+        dbg(udev, "resolved link to: '%s'\n", pos);
+        return util_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';
+        dbg(udev, "path link '%s' points to '%s'\n", syspath, link_target);
+
+        for (back = 0; strncmp(&link_target[back * 3], "../", 3) == 0; back++)
+                ;
+        dbg(udev, "base '%s', tail '%s', back %i\n", syspath, &link_target[back * 3], back);
+        for (i = 0; i <= back; i++) {
+                base = strrchr(syspath, '/');
+                if (base == NULL)
+                        return -EINVAL;
+                base[0] = '\0';
+        }
+        if (base == NULL)
+                return -EINVAL;
+        dbg(udev, "after moving back '%s'\n", syspath);
+        util_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 (strncmp(priority, "err", 3) == 0)
+                return LOG_ERR;
+        if (strncmp(priority, "info", 4) == 0)
+                return LOG_INFO;
+        if (strncmp(priority, "debug", 5) == 0)
+                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;
+}
+
+size_t util_path_decode(char *s)
+{
+        size_t i, j;
+
+        for (i = 0, j = 0; s[i] != '\0'; j++) {
+                if (memcmp(&s[i], "\\x2f", 4) == 0) {
+                        s[j] = '/';
+                        i += 4;
+                } else if (memcmp(&s[i], "\\x5c", 4) == 0) {
+                        s[j] = '\\';
+                        i += 4;
+                } else {
+                        s[j] = s[i];
+                        i++;
+                }
+        }
+        s[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';
+}
+
+/*
+ * Concatenates 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.
+ */
+size_t util_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;
+                *dest[0] = '\0';
+        } else {
+                if (len > 0) {
+                        *dest = mempcpy(*dest, src, len);
+                        size -= len;
+                }
+                *dest[0] = '\0';
+        }
+        return size;
+}
+
+/* concatenates list of strings, moves dest forward */
+size_t util_strpcpyl(char **dest, size_t size, const char *src, ...)
+{
+        va_list va;
+
+        va_start(va, src);
+        do {
+                size = util_strpcpy(dest, size, src);
+                src = va_arg(va, char *);
+        } while (src != NULL);
+        va_end(va);
+
+        return size;
+}
+
+/* copies string */
+size_t util_strscpy(char *dest, size_t size, const char *src)
+{
+        char *s;
+
+        s = dest;
+        return util_strpcpy(&s, size, src);
+}
+
+/* concatenates list of strings */
+size_t util_strscpyl(char *dest, size_t size, const char *src, ...)
+{
+        va_list va;
+        char *s;
+
+        va_start(va, src);
+        s = dest;
+        do {
+                size = util_strpcpy(&s, size, src);
+                src = va_arg(va, char *);
+        } while (src != NULL);
+        va_end(va);
+
+        return size;
+}
+
+/* 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 */
+static 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;
+}
+
+/* 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;
+}
+
+/* check if unicode char has a valid numeric range */
+static int utf8_unichar_valid_range(int unichar)
+{
+        if (unichar > 0x10ffff)
+                return 0;
+        if ((unichar & 0xfffff800) == 0xd800)
+                return 0;
+        if ((unichar > 0xfdcf) && (unichar < 0xfdf0))
+                return 0;
+        if ((unichar & 0xffff) == 0xffff)
+                return 0;
+        return 1;
+}
+
+/* validate one encoded unicode char and return its length */
+static 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 (!utf8_unichar_valid_range(unichar))
+                return -1;
+
+        return len;
+}
+
+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;
+}
+
+static int is_whitelisted(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;
+}
+
+/* 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 (is_whitelisted(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.
+ **/
+UDEV_EXPORT int udev_util_encode_string(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] == '\\' || !is_whitelisted(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;
+}
+
+/*
+ * http://sites.google.com/site/murmurhash/
+ *
+ * All code is released to the public domain. For business purposes,
+ * Murmurhash is under the MIT license.
+ *
+ */
+static unsigned int murmur_hash2(const char *key, int len, unsigned int seed)
+{
+        /*
+         *  'm' and 'r' are mixing constants generated offline.
+         *  They're not really 'magic', they just happen to work well.
+         */
+        const unsigned int m = 0x5bd1e995;
+        const int r = 24;
+
+        /* initialize the hash to a 'random' value */
+        unsigned int h = seed ^ len;
+
+        /* mix 4 bytes at a time into the hash */
+        const unsigned char * data = (const unsigned char *)key;
+
+        while(len >= 4) {
+                unsigned int k = *(unsigned int *)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;
+}
+
+unsigned int util_string_hash32(const char *str)
+{
+        return murmur_hash2(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;
+}
+
+#define USEC_PER_SEC  1000000ULL
+#define NSEC_PER_USEC 1000ULL
+unsigned long long ts_usec(const struct timespec *ts)
+{
+        return (unsigned long long) ts->tv_sec * USEC_PER_SEC +
+               (unsigned long long) ts->tv_nsec / NSEC_PER_USEC;
+}
+
+unsigned long long now_usec(void)
+{
+        struct timespec ts;
+
+        if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
+                return 0;
+        return ts_usec(&ts);
+}
diff --git a/src/udev/libudev.c b/src/udev/libudev.c
new file mode 100644 (file)
index 0000000..dcba15d
--- /dev/null
@@ -0,0 +1,457 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+
+#include "libudev.h"
+#include "libudev-private.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;
+        char *sys_path;
+        char *dev_path;
+        char *rules_path[4];
+        unsigned long long rules_path_ts[4];
+        int rules_path_count;
+        char *run_path;
+        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);
+}
+
+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
+ **/
+UDEV_EXPORT 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.
+ **/
+UDEV_EXPORT void udev_set_userdata(struct udev *udev, void *userdata)
+{
+        if (udev == NULL)
+                return;
+        udev->userdata = userdata;
+}
+
+static char *set_value(char **s, const char *v)
+{
+        free(*s);
+        *s = strdup(v);
+        util_remove_trailing_chars(*s, '/');
+        return *s;
+}
+
+/**
+ * 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
+ **/
+UDEV_EXPORT struct udev *udev_new(void)
+{
+        struct udev *udev;
+        const char *env;
+        char *config_file = NULL;
+        FILE *f;
+
+        udev = calloc(1, sizeof(struct udev));
+        if (udev == NULL)
+                return NULL;
+        udev->refcount = 1;
+        udev->log_fn = log_stderr;
+        udev->log_priority = LOG_ERR;
+        udev_list_init(udev, &udev->properties_list, true);
+
+        /* custom config file */
+        env = getenv("UDEV_CONFIG_FILE");
+        if (env != NULL) {
+                if (set_value(&config_file, env) == NULL)
+                        goto err;
+                udev_add_property(udev, "UDEV_CONFIG_FILE", config_file);
+        }
+
+        /* default config file */
+        if (config_file == NULL)
+                config_file = strdup(SYSCONFDIR "/udev/udev.conf");
+        if (config_file == NULL)
+                goto err;
+
+        f = fopen(config_file, "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) {
+                                err(udev, "missing <key>=<value> in '%s'[%i], skip line\n", config_file, 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]) {
+                                        err(udev, "inconsistent quoting in '%s'[%i], skip line\n", config_file, line_nr);
+                                        continue;
+                                }
+                                val[len-1] = '\0';
+                                val++;
+                        }
+
+                        if (strcmp(key, "udev_log") == 0) {
+                                udev_set_log_priority(udev, util_log_priority(val));
+                                continue;
+                        }
+                        if (strcmp(key, "udev_root") == 0) {
+                                set_value(&udev->dev_path, val);
+                                continue;
+                        }
+                        if (strcmp(key, "udev_run") == 0) {
+                                set_value(&udev->run_path, val);
+                                continue;
+                        }
+                        if (strcmp(key, "udev_sys") == 0) {
+                                set_value(&udev->sys_path, val);
+                                continue;
+                        }
+                        if (strcmp(key, "udev_rules") == 0) {
+                                set_value(&udev->rules_path[0], val);
+                                udev->rules_path_count = 1;
+                                continue;
+                        }
+                }
+                fclose(f);
+        }
+
+        /* environment overrides config */
+        env = getenv("UDEV_LOG");
+        if (env != NULL)
+                udev_set_log_priority(udev, util_log_priority(env));
+
+        /* set defaults */
+        if (udev->dev_path == NULL)
+                if (set_value(&udev->dev_path, "/dev") == NULL)
+                        goto err;
+
+        if (udev->sys_path == NULL)
+                if (set_value(&udev->sys_path, "/sys") == NULL)
+                        goto err;
+
+        if (udev->run_path == NULL)
+                if (set_value(&udev->run_path, "/run/udev") == NULL)
+                        goto err;
+
+        if (udev->rules_path[0] == NULL) {
+                /* /usr/lib/udev -- system rules */
+                udev->rules_path[0] = strdup(UDEVLIBEXECDIR "/rules.d");
+                if (!udev->rules_path[0])
+                        goto err;
+
+                /* /run/udev -- runtime rules */
+                if (asprintf(&udev->rules_path[2], "%s/rules.d", udev->run_path) < 0)
+                        goto err;
+
+                /* /etc/udev -- local administration rules */
+                udev->rules_path[1] = strdup(SYSCONFDIR "/udev/rules.d");
+                if (!udev->rules_path[1])
+                        goto err;
+
+                udev->rules_path_count = 3;
+        }
+
+        dbg(udev, "context %p created\n", udev);
+        dbg(udev, "log_priority=%d\n", udev->log_priority);
+        dbg(udev, "config_file='%s'\n", config_file);
+        dbg(udev, "dev_path='%s'\n", udev->dev_path);
+        dbg(udev, "sys_path='%s'\n", udev->sys_path);
+        dbg(udev, "run_path='%s'\n", udev->run_path);
+        dbg(udev, "rules_path='%s':'%s':'%s'\n", udev->rules_path[0], udev->rules_path[1], udev->rules_path[2]);
+        free(config_file);
+        return udev;
+err:
+        free(config_file);
+        err(udev, "context creation failed\n");
+        udev_unref(udev);
+        return NULL;
+}
+
+/**
+ * udev_ref:
+ * @udev: udev library context
+ *
+ * Take a reference of the udev library context.
+ *
+ * Returns: the passed udev library context
+ **/
+UDEV_EXPORT 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.
+ *
+ **/
+UDEV_EXPORT void udev_unref(struct udev *udev)
+{
+        if (udev == NULL)
+                return;
+        udev->refcount--;
+        if (udev->refcount > 0)
+                return;
+        udev_list_cleanup(&udev->properties_list);
+        free(udev->dev_path);
+        free(udev->sys_path);
+        free(udev->rules_path[0]);
+        free(udev->rules_path[1]);
+        free(udev->rules_path[2]);
+        free(udev->run_path);
+        dbg(udev, "context %p released\n", udev);
+        free(udev);
+}
+
+/**
+ * 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.
+ *
+ **/
+UDEV_EXPORT 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;
+        info(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
+ **/
+UDEV_EXPORT 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.
+ **/
+UDEV_EXPORT 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);
+}
+
+int udev_get_rules_path(struct udev *udev, char **path[], unsigned long long *stamp_usec[])
+{
+        *path = udev->rules_path;
+        if (stamp_usec)
+                *stamp_usec = udev->rules_path_ts;
+        return udev->rules_path_count;
+}
+
+/**
+ * udev_get_sys_path:
+ * @udev: udev library context
+ *
+ * Retrieve the sysfs mount point. The default is "/sys". For
+ * testing purposes, it can be overridden with udev_sys=
+ * in the udev configuration file.
+ *
+ * Returns: the sys mount point
+ **/
+UDEV_EXPORT const char *udev_get_sys_path(struct udev *udev)
+{
+        if (udev == NULL)
+                return NULL;
+        return udev->sys_path;
+}
+
+/**
+ * udev_get_dev_path:
+ * @udev: udev library context
+ *
+ * Retrieve the device directory path. The default value is "/dev",
+ * the actual value may be overridden in the udev configuration
+ * file.
+ *
+ * Returns: the device directory path
+ **/
+UDEV_EXPORT const char *udev_get_dev_path(struct udev *udev)
+{
+        if (udev == NULL)
+                return NULL;
+        return udev->dev_path;
+}
+
+/**
+ * udev_get_run_path:
+ * @udev: udev library context
+ *
+ * Retrieve the udev runtime directory path. The default is "/run/udev".
+ *
+ * Returns: the runtime directory path
+ **/
+UDEV_EXPORT const char *udev_get_run_path(struct udev *udev)
+{
+        if (udev == NULL)
+                return NULL;
+        return udev->run_path;
+}
+
+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/udev/libudev.h b/src/udev/libudev.h
new file mode 100644 (file)
index 0000000..10e098d
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008-2011 Kay Sievers <kay.sievers@vrfy.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.
+ */
+
+#ifndef _LIBUDEV_H_
+#define _LIBUDEV_H_
+
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#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);
+void 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);
+const char *udev_get_sys_path(struct udev *udev);
+const char *udev_get_dev_path(struct udev *udev);
+const char *udev_get_run_path(struct udev *udev);
+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);
+void 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_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_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);
+void 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);
+/* custom socket (use netlink and filters instead) */
+struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path);
+/* 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);
+void 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);
+void 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_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/udev/libudev.pc.in b/src/udev/libudev.pc.in
new file mode 100644 (file)
index 0000000..c9a47fc
--- /dev/null
@@ -0,0 +1,11 @@
+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 -lrt
+Libs.private:
+Cflags: -I${includedir}
diff --git a/src/udev/m4/.gitignore b/src/udev/m4/.gitignore
deleted file mode 100644 (file)
index 0ca2c03..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-libtool.m4
-lt*m4
-gtk-doc.m4
-
diff --git a/src/udev/mtd_probe/75-probe_mtd.rules b/src/udev/mtd_probe/75-probe_mtd.rules
new file mode 100644 (file)
index 0000000..c0e0839
--- /dev/null
@@ -0,0 +1,8 @@
+# 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"
+KERNEL=="mtd*ro", ENV{MTD_FTL}=="smartmedia", IMPORT{builtin}="kmod load sm_ftl"
+
+LABEL="mtd_probe_end"
diff --git a/src/udev/mtd_probe/mtd_probe.c b/src/udev/mtd_probe/mtd_probe.c
new file mode 100644 (file)
index 0000000..1aa08d3
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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 <stdio.h>
+#include <sys/ioctl.h>
+#include <mtd/mtd-user.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+int main(int argc, char** argv)
+{
+        if (argc != 2) {
+                printf("usage: mtd_probe /dev/mtd[n]\n");
+                return 1;
+        }
+
+        int mtd_fd = open(argv[1], O_RDONLY);
+        if (mtd_fd == -1) {
+                perror("open");
+                exit(-1);
+        }
+
+        mtd_info_t mtd_info;
+        int 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 (file)
index 0000000..2a37ede
--- /dev/null
@@ -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 <mtd/mtd-user.h>
+
+/* 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 (file)
index 0000000..b3cdefc
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <mtd/mtd-user.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdlib.h>
+#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)
+{
+        char* cis_buffer = malloc(SM_SECTOR_SIZE);
+
+        if (!cis_buffer)
+                return;
+
+        if (info->type != MTD_NANDFLASH)
+                goto exit;
+
+        int sector_size = info->writesize;
+        int block_size = info->erasesize;
+        int size_in_megs = info->size / (1024 * 1024);
+        int spare_count;
+
+
+        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;
+        }
+
+
+        int offset;
+        int cis_found = 0;
+
+        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/rules/42-usb-hid-pm.rules b/src/udev/rules/42-usb-hid-pm.rules
deleted file mode 100644 (file)
index d5d5897..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-#
-# 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"
-
-#
-# Enable autosuspend for KVM and iLO usb hid devices. These are
-# effectively self-powered (despite what some claim in their USB
-# profiles) and so it's safe to do so.
-#
-
-# AMI 046b:ff10
-ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="046b", ATTR{idProduct}=="ff10", 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"
-
-# Hewlett Packard iLO
-ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="03f0", ATTR{idProduct}=="7029", TEST=="power/control", ATTR{power/control}="auto"
-ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="03f0", ATTR{idProduct}=="1027", 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", ATTR{bInterfaceClass}=="03", ATTRS{removable}=="fixed", TEST=="../power/control", ATTR{../power/control}="auto"
diff --git a/src/udev/rules/50-udev-default.rules b/src/udev/rules/50-udev-default.rules
deleted file mode 100644 (file)
index 5ad787f..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-# do not edit this file, it will be overwritten on update
-
-KERNEL=="pty[pqrstuvwxyzabcdef][0123456789abcdef]", GROUP="tty", MODE="0660"
-KERNEL=="tty[pqrstuvwxyzabcdef][0123456789abcdef]", GROUP="tty", MODE="0660"
-KERNEL=="ptmx", GROUP="tty", MODE="0666"
-KERNEL=="tty", GROUP="tty", MODE="0666"
-KERNEL=="tty[0-9]*", GROUP="tty", MODE="0620"
-KERNEL=="vcs|vcs[0-9]*|vcsa|vcsa[0-9]*", GROUP="tty"
-
-# serial
-KERNEL=="tty[A-Z]*[0-9]|pppox[0-9]*|ircomm[0-9]*|noz[0-9]*|rfcomm[0-9]*", GROUP="dialout"
-KERNEL=="mwave", GROUP="dialout"
-KERNEL=="hvc*|hvsi*", GROUP="dialout"
-
-# virtio serial / console ports
-KERNEL=="vport*", ATTR{name}=="?*", SYMLINK+="virtio-ports/$attr{name}"
-
-# mem
-KERNEL=="null|zero|full|random|urandom", MODE="0666"
-KERNEL=="mem|kmem|port|nvram", GROUP="kmem", MODE="0640"
-
-# input
-SUBSYSTEM=="input", ENV{ID_INPUT}=="", IMPORT{builtin}="input_id"
-KERNEL=="mouse*|mice|event*", MODE="0640"
-KERNEL=="ts[0-9]*|uinput", MODE="0640"
-KERNEL=="js[0-9]*", MODE="0644"
-
-# video4linux
-SUBSYSTEM=="video4linux", GROUP="video"
-KERNEL=="vttuner*", GROUP="video"
-KERNEL=="vtx*|vbi*", GROUP="video"
-KERNEL=="winradio*", GROUP="video"
-
-# graphics
-KERNEL=="agpgart", GROUP="video"
-KERNEL=="pmu", GROUP="video"
-KERNEL=="nvidia*|nvidiactl*", GROUP="video"
-SUBSYSTEM=="graphics", GROUP="video"
-SUBSYSTEM=="drm", GROUP="video"
-
-# sound
-SUBSYSTEM=="sound", GROUP="audio", \
-  OPTIONS+="static_node=snd/seq", OPTIONS+="static_node=snd/timer"
-
-# DVB (video)
-SUBSYSTEM=="dvb", GROUP="video"
-
-# FireWire (firewire-core driver: IIDC devices, AV/C devices)
-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"
-
-# 'libusb' device nodes
-SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", MODE="0664"
-SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", IMPORT{builtin}="usb_id"
-
-# printer
-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"
-
-# block
-SUBSYSTEM=="block", GROUP="disk"
-
-# floppy
-SUBSYSTEM=="block", KERNEL=="fd[0-9]", GROUP="floppy"
-
-# cdrom
-SUBSYSTEM=="block", KERNEL=="sr[0-9]*", GROUP="cdrom"
-SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="4|5", GROUP="cdrom"
-KERNEL=="pktcdvd[0-9]*", GROUP="cdrom"
-KERNEL=="pktcdvd", GROUP="cdrom"
-
-# tape
-KERNEL=="ht[0-9]*|nht[0-9]*", GROUP="tape"
-KERNEL=="pt[0-9]*|npt[0-9]*|pht[0-9]*", GROUP="tape"
-SUBSYSTEM=="scsi_generic|scsi_tape", SUBSYSTEMS=="scsi", ATTRS{type}=="1|8", GROUP="tape"
-
-# block-related
-KERNEL=="sch[0-9]*", GROUP="disk"
-SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="0", GROUP="disk"
-KERNEL=="pg[0-9]*", 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"
-
-# network
-KERNEL=="tun", MODE="0666", OPTIONS+="static_node=net/tun"
-KERNEL=="rfkill", MODE="0644"
-
-# CPU
-KERNEL=="cpu[0-9]*", MODE="0444"
-
-KERNEL=="fuse", ACTION=="add", MODE="0666", OPTIONS+="static_node=fuse"
-
-SUBSYSTEM=="rtc", ATTR{hctosys}=="1", SYMLINK+="rtc"
-KERNEL=="mmtimer", MODE="0644"
-KERNEL=="rflash[0-9]*", MODE="0400"
-KERNEL=="rrom[0-9]*", MODE="0400"
-
-SUBSYSTEM=="firmware", ACTION=="add", IMPORT{builtin}="firmware"
diff --git a/src/udev/rules/60-persistent-alsa.rules b/src/udev/rules/60-persistent-alsa.rules
deleted file mode 100644 (file)
index 8154e2d..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-# 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/src/udev/rules/60-persistent-input.rules b/src/udev/rules/60-persistent-input.rules
deleted file mode 100644 (file)
index fb798dd..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-# 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}=="?*", 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}=="?*", 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/src/udev/rules/60-persistent-serial.rules b/src/udev/rules/60-persistent-serial.rules
deleted file mode 100644 (file)
index 2948200..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-# 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/src/udev/rules/60-persistent-storage-tape.rules b/src/udev/rules/60-persistent-storage-tape.rules
deleted file mode 100644 (file)
index f2eabd9..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-# 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/src/udev/rules/60-persistent-storage.rules b/src/udev/rules/60-persistent-storage.rules
deleted file mode 100644 (file)
index b74821e..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-# 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 <hare@suse.de>
-
-# 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*", 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 with their own "ata" kernel subsystem
-KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="ata", IMPORT{program}="ata_id --export $devnode"
-# 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/src/udev/rules/75-net-description.rules b/src/udev/rules/75-net-description.rules
deleted file mode 100644 (file)
index ce57d48..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-# do not edit this file, it will be overwritten on update
-
-ACTION=="remove", GOTO="net_end"
-SUBSYSTEM!="net", GOTO="net_end"
-
-SUBSYSTEMS=="usb", ENV{ID_MODEL}=="", IMPORT{builtin}="usb_id"
-SUBSYSTEMS=="usb", IMPORT{builtin}="usb-db"
-SUBSYSTEMS=="usb", ATTRS{idVendor}!="", ATTRS{idProduct}!="", ENV{ID_VENDOR_ID}="$attr{idVendor}", ENV{ID_MODEL_ID}="$attr{idProduct}"
-SUBSYSTEMS=="usb", GOTO="net_end"
-
-SUBSYSTEMS=="pci", IMPORT{builtin}="pci-db"
-SUBSYSTEMS=="pci", ENV{ID_BUS}="pci", ENV{ID_VENDOR_ID}="$attr{vendor}", ENV{ID_MODEL_ID}="$attr{device}"
-
-LABEL="net_end"
diff --git a/src/udev/rules/75-tty-description.rules b/src/udev/rules/75-tty-description.rules
deleted file mode 100644 (file)
index 2e63e14..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-# do not edit this file, it will be overwritten on update
-
-ACTION=="remove", GOTO="tty_end"
-SUBSYSTEM!="tty", GOTO="tty_end"
-
-SUBSYSTEMS=="usb", ENV{ID_MODEL}=="", IMPORT{builtin}="usb_id"
-SUBSYSTEMS=="usb", IMPORT{builtin}="usb-db"
-SUBSYSTEMS=="usb", ATTRS{idVendor}!="", ATTRS{idProduct}!="", ENV{ID_VENDOR_ID}="$attr{idVendor}", ENV{ID_MODEL_ID}="$attr{idProduct}"
-SUBSYSTEMS=="usb", GOTO="tty_end"
-
-SUBSYSTEMS=="pci", IMPORT{builtin}="pci-db"
-SUBSYSTEMS=="pci", ENV{ID_BUS}="pci", ENV{ID_VENDOR_ID}="$attr{vendor}", ENV{ID_MODEL_ID}="$attr{device}"
-
-LABEL="tty_end"
diff --git a/src/udev/rules/78-sound-card.rules b/src/udev/rules/78-sound-card.rules
deleted file mode 100644 (file)
index e564441..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-# 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"
-
-SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id"
-SUBSYSTEMS=="usb", IMPORT{builtin}="usb-db"
-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", IMPORT{builtin}="pci-db"
-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/src/udev/rules/80-drivers.rules b/src/udev/rules/80-drivers.rules
deleted file mode 100644 (file)
index 38ebfeb..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# do not edit this file, it will be overwritten on update
-
-ACTION=="remove", GOTO="drivers_end"
-
-DRIVER!="?*", ENV{MODALIAS}=="?*", IMPORT{builtin}="kmod load $env{MODALIAS}"
-SUBSYSTEM=="tifm", ENV{TIFM_CARD_TYPE}=="SD", IMPORT{builtin}="kmod load tifm_sd"
-SUBSYSTEM=="tifm", ENV{TIFM_CARD_TYPE}=="MS", IMPORT{builtin}="kmod load tifm_ms"
-SUBSYSTEM=="memstick", IMPORT{builtin}="kmod load ms_block mspro_block"
-SUBSYSTEM=="i2o", IMPORT{builtin}="kmod load i2o_block"
-SUBSYSTEM=="module", KERNEL=="parport_pc", IMPORT{builtin}="kmod load ppdev"
-
-LABEL="drivers_end"
diff --git a/src/udev/rules/95-udev-late.rules b/src/udev/rules/95-udev-late.rules
deleted file mode 100644 (file)
index eca0faa..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-# 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/src/udev/scsi_id/.gitignore b/src/udev/scsi_id/.gitignore
new file mode 100644 (file)
index 0000000..6aebddd
--- /dev/null
@@ -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 (file)
index 0000000..9cfe739
--- /dev/null
@@ -0,0 +1,4 @@
+scsi_id - generate a SCSI unique identifier for a given SCSI device
+
+Please send questions, comments or patches to <patmans@us.ibm.com> or
+<linux-hotplug-devel@lists.sourceforge.net>.
diff --git a/src/udev/scsi_id/scsi.h b/src/udev/scsi_id/scsi.h
new file mode 100644 (file)
index 0000000..c423cac
--- /dev/null
@@ -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 <scsi/scsi.h>
+
+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 <scsi/scsi.h>) 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 (file)
index 0000000..9bb0d7f
--- /dev/null
@@ -0,0 +1,657 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <sys/stat.h>
+
+#include "libudev.h"
+#include "libudev-private.h"
+#include "scsi_id.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' },
+        { "export", no_argument, NULL, 'x' },
+        { "help", no_argument, NULL, 'h' },
+        {}
+};
+
+static const char short_options[] = "d:f:ghip:uvVx";
+static const char dev_short_options[] = "bgp:";
+
+static int all_good;
+static int dev_specified;
+static char config_file[MAX_PATH_LEN] = SYSCONFDIR "/scsi_id.config";
+static enum page_code default_page_code;
+static int sg_version = 4;
+static int use_stderr;
+static int debug;
+static int reformat_serial;
+static int export;
+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];
+
+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;
+        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;
+                }
+        }
+        util_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 char *quote_string = "\"\n";
+        static char *comma_string = ",\n";
+        char *val;
+        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;
+        FILE *fd;
+        char *buf;
+        char *str1;
+        char *vendor_in, *model_in, *options_in; /* read in from file */
+        int lineno;
+        int c;
+        int retval = 0;
+
+        dbg(udev, "vendor='%s'; model='%s'\n", vendor, model);
+        fd = fopen(config_file, "r");
+        if (fd == NULL) {
+                dbg(udev, "can't open %s\n", config_file);
+                if (errno == ENOENT) {
+                        return 1;
+                } else {
+                        err(udev, "can't open %s: %s\n", config_file, strerror(errno));
+                        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) {
+                fclose(fd);
+                err(udev, "can't allocate memory\n");
+                return -1;
+        }
+
+        *newargv = NULL;
+        lineno = 0;
+        while (1) {
+                vendor_in = model_in = options_in = NULL;
+
+                buf = fgets(buffer, MAX_BUFFER_LEN, fd);
+                if (buf == NULL)
+                        break;
+                lineno++;
+                if (buf[strlen(buffer) - 1] != '\n') {
+                        err(udev, "Config file line %d too long\n", lineno);
+                        break;
+                }
+
+                while (isspace(*buf))
+                        buf++;
+
+                /* blank or all whitespace line */
+                if (*buf == '\0')
+                        continue;
+
+                /* comment line */
+                if (*buf == '#')
+                        continue;
+
+                dbg(udev, "lineno %d: '%s'\n", lineno, buf);
+                str1 = strsep(&buf, "=");
+                if (str1 && strcasecmp(str1, "VENDOR") == 0) {
+                        str1 = get_value(&buf);
+                        if (!str1) {
+                                retval = -1;
+                                break;
+                        }
+                        vendor_in = str1;
+
+                        str1 = strsep(&buf, "=");
+                        if (str1 && strcasecmp(str1, "MODEL") == 0) {
+                                str1 = get_value(&buf);
+                                if (!str1) {
+                                        retval = -1;
+                                        break;
+                                }
+                                model_in = str1;
+                                str1 = strsep(&buf, "=");
+                        }
+                }
+
+                if (str1 && strcasecmp(str1, "OPTIONS") == 0) {
+                        str1 = get_value(&buf);
+                        if (!str1) {
+                                retval = -1;
+                                break;
+                        }
+                        options_in = str1;
+                }
+                dbg(udev, "config file line %d:\n"
+                        " vendor '%s'; model '%s'; options '%s'\n",
+                        lineno, vendor_in, model_in, options_in);
+                /*
+                 * Only allow: [vendor=foo[,model=bar]]options=stuff
+                 */
+                if (!options_in || (!vendor_in && model_in)) {
+                        err(udev, "Error parsing config file line %d '%s'\n", lineno, buffer);
+                        retval = -1;
+                        break;
+                }
+                if (vendor == NULL) {
+                        if (vendor_in == NULL) {
+                                dbg(udev, "matched global option\n");
+                                break;
+                        }
+                } else if ((vendor_in && strncmp(vendor, vendor_in,
+                                                 strlen(vendor_in)) == 0) &&
+                           (!model_in || (strncmp(model, model_in,
+                                                  strlen(model_in)) == 0))) {
+                                /*
+                                 * Matched vendor and optionally model.
+                                 *
+                                 * Note: a short vendor_in or model_in can
+                                 * give a partial match (that is FOO
+                                 * matches FOOBAR).
+                                 */
+                                dbg(udev, "matched vendor/model\n");
+                                break;
+                } else {
+                        dbg(udev, "no match\n");
+                }
+        }
+
+        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) {
+                                err(udev, "can't allocate memory\n");
+                                retval = -1;
+                        } 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);
+        fclose(fd);
+        return retval;
+}
+
+static int set_options(struct udev *udev,
+                       int argc, char **argv, const char *short_opts,
+                       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 (1) {
+                option = getopt_long(argc, argv, short_opts, options, NULL);
+                if (option == -1)
+                        break;
+
+                if (optarg)
+                        dbg(udev, "option '%c' arg '%s'\n", option, optarg);
+                else
+                        dbg(udev, "option '%c'\n", option);
+
+                switch (option) {
+                case 'b':
+                        all_good = 0;
+                        break;
+
+                case 'd':
+                        dev_specified = 1;
+                        util_strscpy(maj_min_dev, MAX_PATH_LEN, optarg);
+                        break;
+
+                case 'e':
+                        use_stderr = 1;
+                        break;
+
+                case 'f':
+                        util_strscpy(config_file, MAX_PATH_LEN, optarg);
+                        break;
+
+                case 'g':
+                        all_good = 1;
+                        break;
+
+                case 'h':
+                        printf("Usage: scsi_id OPTIONS <device>\n"
+                               "  --device=                     device node for SG_IO commands\n"
+                               "  --config=                     location of config file\n"
+                               "  --page=0x80|0x83|pre-spc3-83  SCSI page (0x80, 0x83, pre-spc3-83)\n"
+                               "  --sg-version=3|4              use SGv3 or SGv4\n"
+                               "  --blacklisted                 threat device as blacklisted\n"
+                               "  --whitelisted                 threat device as whitelisted\n"
+                               "  --replace-whitespace          replace all whitespaces by underscores\n"
+                               "  --verbose                     verbose logging\n"
+                               "  --version                     print version\n"
+                               "  --export                      print values as environment keys\n"
+                               "  --help                        print this help text\n\n");
+                        exit(0);
+
+                case 'p':
+                        if (strcmp(optarg, "0x80") == 0) {
+                                default_page_code = PAGE_80;
+                        } else if (strcmp(optarg, "0x83") == 0) {
+                                default_page_code = PAGE_83;
+                        } else if (strcmp(optarg, "pre-spc3-83") == 0) {
+                                default_page_code = PAGE_83_PRE_SPC3;
+                        } else {
+                                err(udev, "Unknown page code '%s'\n", optarg);
+                                return -1;
+                        }
+                        break;
+
+                case 's':
+                        sg_version = atoi(optarg);
+                        if (sg_version < 3 || sg_version > 4) {
+                                err(udev, "Unknown SG version '%s'\n", optarg);
+                                return -1;
+                        }
+                        break;
+
+                case 'u':
+                        reformat_serial = 1;
+                        break;
+
+                case 'x':
+                        export = 1;
+                        break;
+
+                case 'v':
+                        debug++;
+                        break;
+
+                case 'V':
+                        printf("%s\n", VERSION);
+                        exit(0);
+                        break;
+
+                default:
+                        exit(1);
+                }
+        }
+        if (optind < argc && !dev_specified) {
+                dev_specified = 1;
+                util_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, dev_short_options, options, NULL);
+                if (option == -1)
+                        break;
+
+                if (optarg)
+                        dbg(udev, "option '%c' arg '%s'\n", option, optarg);
+                else
+                        dbg(udev, "option '%c'\n", option);
+
+                switch (option) {
+                case 'b':
+                        *good_bad = 0;
+                        break;
+
+                case 'g':
+                        *good_bad = 1;
+                        break;
+
+                case 'p':
+                        if (strcmp(optarg, "0x80") == 0) {
+                                *page_code = PAGE_80;
+                        } else if (strcmp(optarg, "0x83") == 0) {
+                                *page_code = PAGE_83;
+                        } else if (strcmp(optarg, "pre-spc3-83") == 0) {
+                                *page_code = PAGE_83_PRE_SPC3;
+                        } else {
+                                err(udev, "Unknown page code '%s'\n", optarg);
+                                retval = -1;
+                        }
+                        break;
+
+                default:
+                        err(udev, "Unknown or bad option '%c' (0x%x)\n", 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;
+
+        memset(&dev_scsi, 0x00, sizeof(struct scsi_id_device));
+
+        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);
+        dbg(udev, "per dev options: good %d; page code 0x%x\n", 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)
+{
+        struct udev *udev;
+        int retval = 0;
+        char maj_min_dev[MAX_PATH_LEN];
+        int newargc;
+        char **newargv;
+
+        udev = udev_new();
+        if (udev == NULL)
+                goto exit;
+
+        udev_log_init("scsi_id");
+        udev_set_log_fn(udev, log_fn);
+
+        /*
+         * Get config file options.
+         */
+        newargv = NULL;
+        retval = get_file_options(udev, NULL, NULL, &newargc, &newargv);
+        if (retval < 0) {
+                retval = 1;
+                goto exit;
+        }
+        if (newargv && (retval == 0)) {
+                if (set_options(udev, newargc, newargv, short_options, maj_min_dev) < 0) {
+                        retval = 2;
+                        goto exit;
+                }
+                free(newargv);
+        }
+
+        /*
+         * Get command line options (overriding any config file settings).
+         */
+        if (set_options(udev, argc, argv, short_options, maj_min_dev) < 0)
+                exit(1);
+
+        if (!dev_specified) {
+                err(udev, "no device specified\n");
+                retval = 1;
+                goto exit;
+        }
+
+        retval = scsi_id(udev, maj_min_dev);
+
+exit:
+        udev_unref(udev);
+        udev_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 (file)
index 0000000..828a983
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+ */
+
+#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];
+};
+
+extern int scsi_std_inquiry(struct udev *udev, struct scsi_id_device *dev_scsi, const char *devname);
+extern 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 (file)
index 0000000..f1d63f4
--- /dev/null
@@ -0,0 +1,990 @@
+/*
+ * Copyright (C) IBM Corp. 2003
+ *
+ * Author: Patrick Mansfield<patmans@us.ibm.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <time.h>
+#include <inttypes.h>
+#include <scsi/scsi.h>
+#include <scsi/sg.h>
+#include <linux/types.h>
+#include <linux/bsg.h>
+
+#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.
+         */
+
+        dbg(udev, "got check condition\n");
+
+        if (sb_len < 1) {
+                info(udev, "%s: sense buffer empty\n", 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) {
+                        info(udev, "%s: sense buffer too small %d bytes, %d bytes too short\n",
+                            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?
+                                 */
+                                info(udev, "%s: sense result too" " small %d bytes\n",
+                                    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 {
+                        info(udev, "%s: invalid sense code 0x%x\n",
+                            dev_scsi->kernel, code);
+                        return -1;
+                }
+                info(udev, "%s: sense key 0x%x ASC 0x%x ASCQ 0x%x\n",
+                    dev_scsi->kernel, sense_key, asc, ascq);
+        } else {
+                if (sb_len < 4) {
+                        info(udev, "%s: sense buffer too small %d bytes, %d bytes too short\n",
+                            dev_scsi->kernel, sb_len, 4 - sb_len);
+                        return -1;
+                }
+
+                if (sense_buffer[0] < 15)
+                        info(udev, "%s: old sense key: 0x%x\n", dev_scsi->kernel, sense_buffer[0] & 0x0f);
+                else
+                        info(udev, "%s: sense = %2x %2x\n",
+                            dev_scsi->kernel, sense_buffer[0], sense_buffer[2]);
+                info(udev, "%s: non-extended sense class %d code 0x%0x\n",
+                    dev_scsi->kernel, sense_class, code);
+
+        }
+
+#ifdef DUMP_SENSE
+        for (i = 0, j = 0; (i < s) && (j < 254); i++) {
+                dbg(udev, "i %d, j %d\n", i, j);
+                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';
+        info(udev, "%s: sense dump:\n", dev_scsi->kernel);
+        info(udev, "%s: %s\n", 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.
+                 */
+                info(udev, "%s: called with no error\n", __FUNCTION__);
+                return -1;
+        }
+
+        info(udev, "%s: sg_io failed status 0x%x 0x%x 0x%x 0x%x\n",
+            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.
+                 */
+                info(udev, "%s: called with no error\n", __FUNCTION__);
+                return -1;
+        }
+
+        info(udev, "%s: sg_io failed status 0x%x 0x%x 0x%x\n",
+            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) {
+                info(udev, "buflen %d too long\n", buflen);
+                return -1;
+        }
+
+resend:
+        dbg(udev, "%s evpd %d, page 0x%x\n", dev_scsi->kernel, evpd, page);
+
+        if (dev_scsi->use_sg == 4) {
+                memset(&io_v4, 0, 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 {
+                memset(&io_hdr, 0, 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;
+                }
+                info(udev, "%s: ioctl failed: %s\n", dev_scsi->kernel, strerror(errno));
+                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) {
+                        dbg(udev, "%s: Retrying ...\n", dev_scsi->kernel);
+                        goto resend;
+                }
+                retval = -1;
+        }
+
+error:
+        if (retval < 0)
+                info(udev, "%s: Unable to get INQUIRY vpd %d page 0x%x.\n",
+                    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;
+
+        memset(buffer, 0, len);
+        retval = scsi_inquiry(udev, dev_scsi, fd, 1, 0x0, buffer, len);
+        if (retval < 0)
+                return 1;
+
+        if (buffer[1] != 0) {
+                info(udev, "%s: page 0 not available.\n", dev_scsi->kernel);
+                return 1;
+        }
+        if (buffer[3] > len) {
+                info(udev, "%s: page 0 buffer too long %d\n", 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 (!strncmp((char *)&buffer[VENDOR_LENGTH], dev_scsi->vendor, VENDOR_LENGTH)) {
+                        info(udev, "%s: invalid page0 data\n", 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)) {
+                info(udev, "%s: expected length %d, got length %d\n",
+                     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) {
+                info(udev, "%s: length %d too short - need %d\n",
+                    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) {
+                        dbg(udev, "prepend failed\n");
+                        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;
+
+        dbg(udev, "using pre-spc3-83 for %s\n", dev_scsi->kernel);
+        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);
+
+        memset(page_83, 0, 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) {
+                info(udev, "%s: Invalid page 0x83\n", 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);
+                        dbg(udev, "%s id desc %d/%d/%d\n", dev_scsi->kernel,
+                                id_search_list[id_ind].id_type,
+                                id_search_list[id_ind].naa_type,
+                                id_search_list[id_ind].code_set);
+                        if (!retval) {
+                                dbg(udev, "  used\n");
+                                return retval;
+                        } else if (retval < 0) {
+                                dbg(udev, "  failed\n");
+                                return retval;
+                        } else {
+                                dbg(udev, "  not used\n");
+                        }
+                }
+        }
+        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];
+
+        memset(page_83, 0, 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) {
+                info(udev, "%s: Invalid page 0x83\n", 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++;
+        }
+        dbg(udev, "using pre-spc3-83 for %s\n", dev_scsi->kernel);
+        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];
+
+        memset(buf, 0, 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) {
+                info(udev, "%s: Invalid page 0x80\n", dev_scsi->kernel);
+                return 1;
+        }
+
+        len = 1 + VENDOR_LENGTH + MODEL_LENGTH + buf[3];
+        if (max_len < len) {
+                info(udev, "%s: length %d too short - need %d\n",
+                     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;
+                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;
+
+        dbg(udev, "opening %s\n", devname);
+        fd = open(devname, O_RDONLY | O_NONBLOCK);
+        if (fd < 0) {
+                info(udev, "scsi_id: cannot open %s: %s\n",
+                     devname, strerror(errno));
+                return 1;
+        }
+
+        if (fstat(fd, &statbuf) < 0) {
+                info(udev, "scsi_id: cannot stat %s: %s\n",
+                     devname, strerror(errno));
+                err = 2;
+                goto out;
+        }
+        sprintf(dev_scsi->kernel,"%d:%d", major(statbuf.st_rdev),
+                minor(statbuf.st_rdev));
+
+        memset(buf, 0, 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;
+
+        memset(dev_scsi->serial, 0, len);
+        dbg(udev, "opening %s\n", devname);
+        srand((unsigned int)getpid());
+        for (cnt = 20; cnt > 0; cnt--) {
+                struct timespec duration;
+
+                fd = open(devname, O_RDONLY | O_NONBLOCK);
+                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) {
+                info(udev, "%s: unsupported page code 0x%d\n", dev_scsi->kernel, page_code);
+                return 1;
+        }
+
+        /*
+         * 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;
+        }
+
+        dbg(udev, "%s: Checking page0\n", dev_scsi->kernel);
+
+        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/src/.gitignore b/src/udev/src/.gitignore
deleted file mode 100644 (file)
index beb8604..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-*.[78]
-*.html
-udev.pc
-libudev.pc
-udev*.service
diff --git a/src/udev/src/COPYING b/src/udev/src/COPYING
deleted file mode 100644 (file)
index d2e3127..0000000
+++ /dev/null
@@ -1,502 +0,0 @@
-                  GNU LESSER GENERAL PUBLIC LICENSE
-                       Version 2.1, February 1999
-
- Copyright (C) 1991, 1999 Free Software Foundation, Inc.
-     51 Franklin St, 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.
-\f
-  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.
-\f
-                  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.
-\f
-  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.
-\f
-  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.
-\f
-  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.
-\f
-  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.
-\f
-  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
-\f
-           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.
-
-    <one line to give the library's name and a brief idea of what it does.>
-    Copyright (C) <year>  <name of author>
-
-    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 St, 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.
-
-  <signature of Ty Coon>, 1 April 1990
-  Ty Coon, President of Vice
-
-That's all there is to it!
diff --git a/src/udev/src/accelerometer/61-accelerometer.rules b/src/udev/src/accelerometer/61-accelerometer.rules
deleted file mode 100644 (file)
index a6a2bfd..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-# 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/src/udev/src/accelerometer/accelerometer.c b/src/udev/src/accelerometer/accelerometer.c
deleted file mode 100644 (file)
index bc9715b..0000000
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * 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 <hadess@hadess.net>
- *
- * orientation_calc() from the sensorfw package
- * Copyright (C) 2009-2010 Nokia Corporation
- * Authors:
- *   Üstün Ergenoglu <ext-ustun.ergenoglu@nokia.com>
- *   Timo Rongas <ext-timo.2.rongas@nokia.com>
- *   Lihan Guo <lihan.guo@digia.com>
- *
- * 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 keymap; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <limits.h>
-#include <linux/limits.h>
-#include <linux/input.h>
-
-#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(x))
-#define LONG(x) ((x)/BITS_PER_LONG)
-#define test_bit(bit, array)    ((array[LONG(bit)] >> OFF(bit)) & 1)
-
-static int debug = 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 (strcmp (orientation, orientations[i]) == 0)
-                        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 = 1; } }
-
-/* accelerometers */
-static void test_orientation(struct udev *udev,
-                             struct udev_device *dev,
-                             const char *devpath)
-{
-        OrientationUp old, new;
-        int fd, r;
-        struct input_event ev[64];
-        int got_syn = 0;
-        int got_x, got_y, got_z;
-        int x = 0, y = 0, z = 0;
-        char text[64];
-
-        old = get_prev_orientation(dev);
-
-        if ((fd = open(devpath, O_RDONLY)) < 0)
-                return;
-
-        got_x = got_y = got_z = 0;
-
-        while (1) {
-                int i;
-
-                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 == 1) {
-                                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 = 1;
-                        }
-                        if (got_x && got_y && got_z)
-                                goto read_dev;
-                }
-        }
-
-read_dev:
-        close(fd);
-
-        if (!got_x || !got_y || !got_z)
-                return;
-
-        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] <device path>\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;
-        const char *id_path;
-        struct udev_enumerate *enumerate;
-        struct udev_list_entry *list_entry;
-
-        udev = udev_new();
-        if (udev == NULL)
-                return 1;
-
-        udev_log_init("input_id");
-        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;
-                        if (udev_get_log_priority(udev) < LOG_INFO)
-                                udev_set_log_priority(udev, LOG_INFO);
-                        break;
-                case 'h':
-                        help();
-                        exit(0);
-                default:
-                        exit(1);
-                }
-        }
-
-        if (argv[optind] == NULL) {
-                help();
-                exit(1);
-        }
-
-        /* get the device */
-        snprintf(devpath, sizeof(devpath), "%s/%s", udev_get_sys_path(udev), argv[optind]);
-        dev = udev_device_new_from_syspath(udev, devpath);
-        if (dev == NULL) {
-                fprintf(stderr, "unable to access '%s'\n", devpath);
-                return 1;
-        }
-
-        id_path = udev_device_get_property_value(dev, "ID_PATH");
-        if (id_path == NULL) {
-                fprintf (stderr, "unable to get property ID_PATH for '%s'", devpath);
-                return 0;
-        }
-
-        /* Get the children devices and find the devnode
-         * FIXME: use udev_enumerate_add_match_children() instead
-         * when it's available */
-        devnode = NULL;
-        enumerate = udev_enumerate_new(udev);
-        udev_enumerate_add_match_property(enumerate, "ID_PATH", id_path);
-        udev_enumerate_add_match_subsystem(enumerate, "input");
-        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;
-        }
-
-        info(udev, "Opening accelerometer device %s\n", devnode);
-        test_orientation(udev, dev, devnode);
-        free(devnode);
-
-        return 0;
-}
diff --git a/src/udev/src/ata_id/ata_id.c b/src/udev/src/ata_id/ata_id.c
deleted file mode 100644 (file)
index 846a73b..0000000
+++ /dev/null
@@ -1,721 +0,0 @@
-/*
- * ata_id - reads product/serial number from ATA drives
- *
- * Copyright (C) 2005-2008 Kay Sievers <kay.sievers@vrfy.org>
- * Copyright (C) 2009 Lennart Poettering <lennart@poettering.net>
- * Copyright (C) 2009-2010 David Zeuthen <zeuthen@gmail.com>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <assert.h>
-#include <string.h>
-#include <errno.h>
-#include <getopt.h>
-#include <scsi/scsi.h>
-#include <scsi/sg.h>
-#include <scsi/scsi_ioctl.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <linux/types.h>
-#include <linux/hdreg.h>
-#include <linux/fs.h>
-#include <linux/cdrom.h>
-#include <linux/bsg.h>
-#include <arpa/inet.h>
-
-#include "libudev.h"
-#include "libudev-private.h"
-
-#define COMMAND_TIMEOUT_MSEC (30 * 1000)
-
-static int disk_scsi_inquiry_command(int      fd,
-                                     void    *buf,
-                                     size_t   buf_len)
-{
-        struct sg_io_v4 io_v4;
-        uint8_t cdb[6];
-        uint8_t sense[32];
-        int ret;
-
-        /*
-         * INQUIRY, see SPC-4 section 6.4
-         */
-        memset(cdb, 0, sizeof(cdb));
-        cdb[0] = 0x12;                         /* OPERATION CODE: INQUIRY */
-        cdb[3] = (buf_len >> 8);         /* ALLOCATION LENGTH */
-        cdb[4] = (buf_len & 0xff);
-
-        memset(sense, 0, sizeof(sense));
-
-        memset(&io_v4, 0, 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 (cdb);
-        io_v4.request = (uintptr_t) cdb;
-        io_v4.max_response_len = sizeof (sense);
-        io_v4.response = (uintptr_t) sense;
-        io_v4.din_xfer_len = buf_len;
-        io_v4.din_xferp = (uintptr_t) buf;
-        io_v4.timeout = COMMAND_TIMEOUT_MSEC;
-
-        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;
-
-                        memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
-                        io_hdr.interface_id = 'S';
-                        io_hdr.cmdp = (unsigned char*) cdb;
-                        io_hdr.cmd_len = sizeof (cdb);
-                        io_hdr.dxferp = buf;
-                        io_hdr.dxfer_len = buf_len;
-                        io_hdr.sbp = sense;
-                        io_hdr.mx_sb_len = sizeof (sense);
-                        io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
-                        io_hdr.timeout = COMMAND_TIMEOUT_MSEC;
-
-                        ret = ioctl(fd, SG_IO, &io_hdr);
-                        if (ret != 0)
-                                goto out;
-
-                        /* 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;
-                                ret = -1;
-                                goto out;
-                        }
-                } else {
-                        goto out;
-                }
-        }
-
-        /* 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;
-                ret = -1;
-                goto out;
-        }
-
- out:
-        return ret;
-}
-
-static int disk_identify_command(int          fd,
-                                 void         *buf,
-                                 size_t          buf_len)
-{
-        struct sg_io_v4 io_v4;
-        uint8_t cdb[12];
-        uint8_t sense[32];
-        uint8_t *desc = sense+8;
-        int ret;
-
-        /*
-         * 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
-         */
-        memset(cdb, 0, sizeof(cdb));
-        cdb[0] = 0xa1;                        /* OPERATION CODE: 12 byte pass through */
-        cdb[1] = 4 << 1;                /* PROTOCOL: PIO Data-in */
-        cdb[2] = 0x2e;                        /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */
-        cdb[3] = 0;                        /* FEATURES */
-        cdb[4] = 1;                        /* SECTORS */
-        cdb[5] = 0;                        /* LBA LOW */
-        cdb[6] = 0;                        /* LBA MID */
-        cdb[7] = 0;                        /* LBA HIGH */
-        cdb[8] = 0 & 0x4F;                /* SELECT */
-        cdb[9] = 0xEC;                        /* Command: ATA IDENTIFY DEVICE */;
-        memset(sense, 0, sizeof(sense));
-
-        memset(&io_v4, 0, 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 (cdb);
-        io_v4.request = (uintptr_t) cdb;
-        io_v4.max_response_len = sizeof (sense);
-        io_v4.response = (uintptr_t) sense;
-        io_v4.din_xfer_len = buf_len;
-        io_v4.din_xferp = (uintptr_t) buf;
-        io_v4.timeout = COMMAND_TIMEOUT_MSEC;
-
-        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;
-
-                        memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
-                        io_hdr.interface_id = 'S';
-                        io_hdr.cmdp = (unsigned char*) cdb;
-                        io_hdr.cmd_len = sizeof (cdb);
-                        io_hdr.dxferp = buf;
-                        io_hdr.dxfer_len = buf_len;
-                        io_hdr.sbp = sense;
-                        io_hdr.mx_sb_len = sizeof (sense);
-                        io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
-                        io_hdr.timeout = COMMAND_TIMEOUT_MSEC;
-
-                        ret = ioctl(fd, SG_IO, &io_hdr);
-                        if (ret != 0)
-                                goto out;
-                } else {
-                        goto out;
-                }
-        }
-
-        if (!(sense[0] == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c)) {
-                errno = EIO;
-                ret = -1;
-                goto out;
-        }
-
- out:
-        return ret;
-}
-
-static int disk_identify_packet_device_command(int          fd,
-                                               void         *buf,
-                                               size_t          buf_len)
-{
-        struct sg_io_v4 io_v4;
-        uint8_t cdb[16];
-        uint8_t sense[32];
-        uint8_t *desc = sense+8;
-        int ret;
-
-        /*
-         * 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
-         */
-        memset(cdb, 0, sizeof(cdb));
-        cdb[0] = 0x85;                        /* OPERATION CODE: 16 byte pass through */
-        cdb[1] = 4 << 1;                /* PROTOCOL: PIO Data-in */
-        cdb[2] = 0x2e;                        /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */
-        cdb[3] = 0;                        /* FEATURES */
-        cdb[4] = 0;                        /* FEATURES */
-        cdb[5] = 0;                        /* SECTORS */
-        cdb[6] = 1;                        /* SECTORS */
-        cdb[7] = 0;                        /* LBA LOW */
-        cdb[8] = 0;                        /* LBA LOW */
-        cdb[9] = 0;                        /* LBA MID */
-        cdb[10] = 0;                        /* LBA MID */
-        cdb[11] = 0;                        /* LBA HIGH */
-        cdb[12] = 0;                        /* LBA HIGH */
-        cdb[13] = 0;                        /* DEVICE */
-        cdb[14] = 0xA1;                        /* Command: ATA IDENTIFY PACKET DEVICE */;
-        cdb[15] = 0;                        /* CONTROL */
-        memset(sense, 0, sizeof(sense));
-
-        memset(&io_v4, 0, 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 (cdb);
-        io_v4.request = (uintptr_t) cdb;
-        io_v4.max_response_len = sizeof (sense);
-        io_v4.response = (uintptr_t) sense;
-        io_v4.din_xfer_len = buf_len;
-        io_v4.din_xferp = (uintptr_t) buf;
-        io_v4.timeout = COMMAND_TIMEOUT_MSEC;
-
-        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;
-
-                        memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
-                        io_hdr.interface_id = 'S';
-                        io_hdr.cmdp = (unsigned char*) cdb;
-                        io_hdr.cmd_len = sizeof (cdb);
-                        io_hdr.dxferp = buf;
-                        io_hdr.dxfer_len = buf_len;
-                        io_hdr.sbp = sense;
-                        io_hdr.mx_sb_len = sizeof (sense);
-                        io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
-                        io_hdr.timeout = COMMAND_TIMEOUT_MSEC;
-
-                        ret = ioctl(fd, SG_IO, &io_hdr);
-                        if (ret != 0)
-                                goto out;
-                } else {
-                        goto out;
-                }
-        }
-
-        if (!(sense[0] == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c)) {
-                errno = EIO;
-                ret = -1;
-                goto out;
-        }
-
- out:
-        return ret;
-}
-
-/**
- * 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;
-
-        assert(identify != NULL);
-        assert(dest != NULL);
-        assert((dest_len & 1) == 0);
-
-        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;
-
-        assert(out_identify != NULL);
-
-        /* init results */
-        ret = -1;
-        memset(out_identify, '\0', 512);
-        is_packet_device = 0;
-
-        /* 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;
-}
-
-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;
-
-        udev_log_init("ata_id");
-        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] <device>\n"
-                               "  --export    print values as environment keys\n"
-                               "  --help      print this help text\n\n");
-                        goto exit;
-                }
-        }
-
-        node = argv[optind];
-        if (node == NULL) {
-                err(udev, "no node specified\n");
-                rc = 1;
-                goto exit;
-        }
-
-        fd = open(node, O_RDONLY|O_NONBLOCK);
-        if (fd < 0) {
-                err(udev, "unable to open '%s'\n", 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,  6); /* 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) {
-                        info(udev, "HDIO_GET_IDENTITY failed for '%s': %m\n", 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);
-        udev_log_close();
-        return rc;
-}
diff --git a/src/udev/src/cdrom_id/60-cdrom_id.rules b/src/udev/src/cdrom_id/60-cdrom_id.rules
deleted file mode 100644 (file)
index 6eaf76a..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-# 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/src/udev/src/cdrom_id/cdrom_id.c b/src/udev/src/cdrom_id/cdrom_id.c
deleted file mode 100644 (file)
index f90d52e..0000000
+++ /dev/null
@@ -1,1099 +0,0 @@
-/*
- * cdrom_id - optical drive and media information prober
- *
- * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE 1
-#endif
-
-#include <stdio.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <getopt.h>
-#include <time.h>
-#include <scsi/sg.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/ioctl.h>
-#include <linux/cdrom.h>
-
-#include "libudev.h"
-#include "libudev-private.h"
-
-static bool debug;
-
-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", "r");
-        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, char *cmd, int err)
-{
-        if (err == -1) {
-                info(udev, "%s failed\n", cmd);
-                return;
-        }
-        info(udev, "%s failed with SK=%Xh/ASC=%02Xh/ACQ=%02Xh\n", 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)
-{
-        memset(cmd, 0x00, 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)
-                info(udev, "CDROM_CLEAR_OPTIONS, CDO_LOCK failed\n");
-
-        err = ioctl(fd, CDROM_LOCKDOOR, lock ? 1 : 0);
-        if (err < 0)
-                info(udev, "CDROM_LOCKDOOR failed\n");
-
-        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) {
-                info(udev, "CDROM_GET_CAPABILITY failed\n");
-                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) {
-                info(udev, "CDROM_DRIVE_STATUS != CDS_DISC_OK\n");
-                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) {
-                info(udev, "not an MMC unit\n");
-                return -1;
-        }
-
-        info(udev, "INQUIRY: [%.8s][%.16s][%.4s]\n", 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:
-                info(udev, "profile 0x%02x \n", cur_profile);
-                cd_media = 1;
-                cd_media_mo = 1;
-                break;
-        case 0x08:
-                info(udev, "profile 0x%02x media_cd_rom\n", cur_profile);
-                cd_media = 1;
-                cd_media_cd_rom = 1;
-                break;
-        case 0x09:
-                info(udev, "profile 0x%02x media_cd_r\n", cur_profile);
-                cd_media = 1;
-                cd_media_cd_r = 1;
-                break;
-        case 0x0a:
-                info(udev, "profile 0x%02x media_cd_rw\n", cur_profile);
-                cd_media = 1;
-                cd_media_cd_rw = 1;
-                break;
-        case 0x10:
-                info(udev, "profile 0x%02x media_dvd_ro\n", cur_profile);
-                cd_media = 1;
-                cd_media_dvd_rom = 1;
-                break;
-        case 0x11:
-                info(udev, "profile 0x%02x media_dvd_r\n", cur_profile);
-                cd_media = 1;
-                cd_media_dvd_r = 1;
-                break;
-        case 0x12:
-                info(udev, "profile 0x%02x media_dvd_ram\n", cur_profile);
-                cd_media = 1;
-                cd_media_dvd_ram = 1;
-                break;
-        case 0x13:
-                info(udev, "profile 0x%02x media_dvd_rw_ro\n", cur_profile);
-                cd_media = 1;
-                cd_media_dvd_rw = 1;
-                cd_media_dvd_rw_ro = 1;
-                break;
-        case 0x14:
-                info(udev, "profile 0x%02x media_dvd_rw_seq\n", cur_profile);
-                cd_media = 1;
-                cd_media_dvd_rw = 1;
-                cd_media_dvd_rw_seq = 1;
-                break;
-        case 0x1B:
-                info(udev, "profile 0x%02x media_dvd_plus_r\n", cur_profile);
-                cd_media = 1;
-                cd_media_dvd_plus_r = 1;
-                break;
-        case 0x1A:
-                info(udev, "profile 0x%02x media_dvd_plus_rw\n", cur_profile);
-                cd_media = 1;
-                cd_media_dvd_plus_rw = 1;
-                break;
-        case 0x2A:
-                info(udev, "profile 0x%02x media_dvd_plus_rw_dl\n", cur_profile);
-                cd_media = 1;
-                cd_media_dvd_plus_rw_dl = 1;
-                break;
-        case 0x2B:
-                info(udev, "profile 0x%02x media_dvd_plus_r_dl\n", cur_profile);
-                cd_media = 1;
-                cd_media_dvd_plus_r_dl = 1;
-                break;
-        case 0x40:
-                info(udev, "profile 0x%02x media_bd\n", cur_profile);
-                cd_media = 1;
-                cd_media_bd = 1;
-                break;
-        case 0x41:
-        case 0x42:
-                info(udev, "profile 0x%02x media_bd_r\n", cur_profile);
-                cd_media = 1;
-                cd_media_bd_r = 1;
-                break;
-        case 0x43:
-                info(udev, "profile 0x%02x media_bd_re\n", cur_profile);
-                cd_media = 1;
-                cd_media_bd_re = 1;
-                break;
-        case 0x50:
-                info(udev, "profile 0x%02x media_hddvd\n", cur_profile);
-                cd_media = 1;
-                cd_media_hddvd = 1;
-                break;
-        case 0x51:
-                info(udev, "profile 0x%02x media_hddvd_r\n", cur_profile);
-                cd_media = 1;
-                cd_media_hddvd_r = 1;
-                break;
-        case 0x52:
-                info(udev, "profile 0x%02x media_hddvd_rw\n", cur_profile);
-                cd_media = 1;
-                cd_media_hddvd_rw = 1;
-                break;
-        default:
-                info(udev, "profile 0x%02x <ignored>\n", 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:
-                        info(udev, "profile 0x%02x mo\n", profile);
-                        cd_mo = 1;
-                        break;
-                case 0x08:
-                        info(udev, "profile 0x%02x cd_rom\n", profile);
-                        cd_cd_rom = 1;
-                        break;
-                case 0x09:
-                        info(udev, "profile 0x%02x cd_r\n", profile);
-                        cd_cd_r = 1;
-                        break;
-                case 0x0A:
-                        info(udev, "profile 0x%02x cd_rw\n", profile);
-                        cd_cd_rw = 1;
-                        break;
-                case 0x10:
-                        info(udev, "profile 0x%02x dvd_rom\n", profile);
-                        cd_dvd_rom = 1;
-                        break;
-                case 0x12:
-                        info(udev, "profile 0x%02x dvd_ram\n", profile);
-                        cd_dvd_ram = 1;
-                        break;
-                case 0x13:
-                case 0x14:
-                        info(udev, "profile 0x%02x dvd_rw\n", profile);
-                        cd_dvd_rw = 1;
-                        break;
-                case 0x1B:
-                        info(udev, "profile 0x%02x dvd_plus_r\n", profile);
-                        cd_dvd_plus_r = 1;
-                        break;
-                case 0x1A:
-                        info(udev, "profile 0x%02x dvd_plus_rw\n", profile);
-                        cd_dvd_plus_rw = 1;
-                        break;
-                case 0x2A:
-                        info(udev, "profile 0x%02x dvd_plus_rw_dl\n", profile);
-                        cd_dvd_plus_rw_dl = 1;
-                        break;
-                case 0x2B:
-                        info(udev, "profile 0x%02x dvd_plus_r_dl\n", profile);
-                        cd_dvd_plus_r_dl = 1;
-                        break;
-                case 0x40:
-                        cd_bd = 1;
-                        info(udev, "profile 0x%02x bd\n", profile);
-                        break;
-                case 0x41:
-                case 0x42:
-                        cd_bd_r = 1;
-                        info(udev, "profile 0x%02x bd_r\n", profile);
-                        break;
-                case 0x43:
-                        cd_bd_re = 1;
-                        info(udev, "profile 0x%02x bd_re\n", profile);
-                        break;
-                case 0x50:
-                        cd_hddvd = 1;
-                        info(udev, "profile 0x%02x hddvd\n", profile);
-                        break;
-                case 0x51:
-                        cd_hddvd_r = 1;
-                        info(udev, "profile 0x%02x hddvd_r\n", profile);
-                        break;
-                case 0x52:
-                        cd_hddvd_rw = 1;
-                        info(udev, "profile 0x%02x hddvd_rw\n", profile);
-                        break;
-                default:
-                        info(udev, "profile 0x%02x <ignored>\n", 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) {
-                        info(udev, "no current profile, but disc is present; assuming CD-ROM\n");
-                        cd_media_cd_rom = 1;
-                        return 0;
-                } else {
-                        info(udev, "no current profile, assuming no media\n");
-                        return -1;
-                }
-        };
-
-        cd_media = 1;
-
-        if (header[2] & 16) {
-                cd_media_cd_rw = 1;
-                info(udev, "profile 0x0a media_cd_rw\n");
-        } else if ((header[2] & 3) < 2 && cd_cd_r) {
-                cd_media_cd_r = 1;
-                info(udev, "profile 0x09 media_cd_r\n");
-        } else {
-                cd_media_cd_rom = 1;
-                info(udev, "profile 0x08 media_cd_rom\n");
-        }
-        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) {
-                        info(udev, "drive is pre-MMC2 and does not support 46h get configuration command\n");
-                        info(udev, "trying to work around the problem\n");
-                        ret = cd_profiles_old_mmc(udev, fd);
-                }
-                goto out;
-        }
-
-        cur_profile = features[6] << 8 | features[7];
-        if (cur_profile > 0) {
-                info(udev, "current profile 0x%02x\n", cur_profile);
-                feature_profile_media (udev, cur_profile);
-                ret = 0; /* we have media */
-        } else {
-                info(udev, "no current profile, assuming no media\n");
-        }
-
-        len = features[0] << 24 | features[1] << 16 | features[2] << 8 | features[3];
-        info(udev, "GET CONFIGURATION: size of features buffer 0x%04x\n", len);
-
-        if (len > sizeof(features)) {
-                info(udev, "can not get features in a single query, truncating\n");
-                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];
-        info(udev, "GET CONFIGURATION: size of features buffer 0x%04x\n", len);
-
-        if (len > sizeof(features)) {
-                info(udev, "can not get features in a single query, truncating\n");
-                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:
-                        info(udev, "GET CONFIGURATION: feature 'profiles', with %i entries\n", features[i+3] / 4);
-                        feature_profiles(udev, &features[i]+4, features[i+3]);
-                        break;
-                default:
-                        info(udev, "GET CONFIGURATION: feature 0x%04x <ignored>, with 0x%02x bytes\n", 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;
-        info(udev, "disk type %02x\n", header[8]);
-        info(udev, "hardware reported media status: %s\n", 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];
-                                info(udev, "write-protected DVD-RAM media inserted\n");
-                                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) {
-                                info(udev, "invalid format capacities length\n");
-                                return -1;
-                        }
-
-                        switch(format[8] & 3) {
-                            case 1:
-                                info(udev, "unformatted DVD-RAM media inserted\n");
-                                /* 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:
-                                info(udev, "formatted DVD-RAM media inserted\n");
-                                break;
-
-                            case 3:
-                                cd_media = 0; //return no media
-                                info(udev, "format capacities returned no media\n");
-                                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];
-                        info(udev, "no data in blocks 0 or 16, assuming blank\n");
-                } else {
-                        info(udev, "data in blocks 0 or 16, assuming complete\n");
-                }
-        }
-
-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;
-        info(udev, "READ TOC: len: %d, start track: %d, end track: %d\n", 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];
-                info(udev, "track=%u info=0x%x(%s) start_block=%u\n",
-                     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];
-        info(udev, "last track %u starts at block %u\n", 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;
-
-        udev_log_init("cdrom_id");
-        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;
-                        if (udev_get_log_priority(udev) < LOG_INFO)
-                                udev_set_log_priority(udev, LOG_INFO);
-                        break;
-                case 'h':
-                        printf("Usage: cdrom_id [options] <device>\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) {
-                err(udev, "no device\n");
-                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|(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) {
-                info(udev, "unable to open '%s'\n", node);
-                fprintf(stderr, "unable to open '%s'\n", node);
-                rc = 1;
-                goto exit;
-        }
-        info(udev, "probing: '%s'\n", 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) {
-                info(udev, "PREVENT_ALLOW_MEDIUM_REMOVAL (lock)\n");
-                media_lock(udev, fd, true);
-        }
-
-        if (unlock && cd_media) {
-                info(udev, "PREVENT_ALLOW_MEDIUM_REMOVAL (unlock)\n");
-                media_lock(udev, fd, false);
-        }
-
-        if (eject) {
-                info(udev, "PREVENT_ALLOW_MEDIUM_REMOVAL (unlock)\n");
-                media_lock(udev, fd, false);
-                info(udev, "START_STOP_UNIT (eject)\n");
-                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);
-        udev_log_close();
-        return rc;
-}
diff --git a/src/udev/src/collect/collect.c b/src/udev/src/collect/collect.c
deleted file mode 100644 (file)
index 076fe47..0000000
+++ /dev/null
@@ -1,473 +0,0 @@
-/*
- * Collect variables across events.
- *
- * usage: collect [--add|--remove] <checkpoint> <id> <idlist>
- *
- * Adds ID <id> to the list governed by <checkpoint>.
- * <id> must be part of the ID list <idlist>.
- * If all IDs given by <idlist> are listed (ie collect has been
- * invoked for each ID in <idlist>) collect returns 0, the
- * number of missing IDs otherwise.
- * A negative number is returned on error.
- *
- * Copyright(C) 2007, Hannes Reinecke <hare@suse.de>
- *
- * 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 <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <string.h>
-#include <getopt.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include "libudev.h"
-#include "libudev-private.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 struct _mate *node_to_mate(struct udev_list_node *node)
-{
-        char *mate;
-
-        mate = (char *)node;
-        mate -= offsetof(struct _mate, node);
-        return (struct _mate *)mate;
-}
-
-static void sig_alrm(int signo)
-{
-        exit(4);
-}
-
-static void usage(void)
-{
-        printf("usage: collect [--add|--remove] [--debug] <checkpoint> <id> <idlist>\n"
-               "\n"
-               "  Adds ID <id> to the list governed by <checkpoint>.\n"
-               "  <id> must be part of the list <idlist>.\n"
-               "  If all IDs given by <idlist> are listed (ie collect has been\n"
-               "  invoked for each ID in <idlist>) 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);
-
-        sprintf(buf, "%s/%s", dir, filename);
-
-        fd = open(buf,O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
-        if (fd < 0)
-                fprintf(stderr, "Cannot open %s: %s\n", buf, strerror(errno));
-
-        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: %s\n", buf, strerror(errno));
-                }
-        }
-
-        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 = calloc(1,bufsize + 1);
-        if (!buf) {
-                fprintf(stderr, "Out of memory\n");
-                return -1;
-        }
-        memset(buf, ' ', bufsize);
-        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));
-                                him->name = strdup(word);
-                                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 (!strcmp(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 (!strcmp(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 -1;
-
-        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 -1;
-                                }
-                                buf = tmpbuf;
-                        }
-                        snprintf(buf, strlen(him->name)+2, "%s ", him->name);
-                        write(fd, buf, strlen(buf));
-                }
-        }
-
-        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: %s\n", strerror(errno));
-                ret = 2;
-                goto exit;
-        }
-
-        udev_list_node_init(&bunch);
-
-        if (debug)
-                fprintf(stderr, "Using checkpoint '%s'\n", checkpoint);
-
-        util_strscpyl(tmpdir, sizeof(tmpdir), udev_get_run_path(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 (!strcmp(him->name, argv[i]))
-                                who = him;
-                }
-                if (!who) {
-                        struct _mate *him;
-
-                        if (debug)
-                                fprintf(stderr, "ID %s: not in database\n", argv[i]);
-                        him = malloc(sizeof (struct _mate));
-                        him->name = malloc(strlen(argv[i]) + 1);
-                        strcpy(him->name, argv[i]);
-                        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/src/docs/.gitignore b/src/udev/src/docs/.gitignore
deleted file mode 100644 (file)
index dca700a..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-libudev-overrides.txt
-html/
-tmpl/
-xml/
-*.stamp
-*.bak
-version.xml
-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
diff --git a/src/udev/src/docs/Makefile.am b/src/udev/src/docs/Makefile.am
deleted file mode 100644 (file)
index 07d06eb..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-## Process this file with automake to produce Makefile.in
-
-# We require automake 1.10 at least.
-AUTOMAKE_OPTIONS = 1.10
-
-# 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
-
-# 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=--sgml-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=
-
-# 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*.h
-CFILE_GLOB=$(top_srcdir)/src/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
-
-# 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=
-
-# 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)/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
-#TESTS_ENVIRONMENT = cd $(srcsrc)
-#TESTS = $(GTKDOC_CHECK)
-endif
diff --git a/src/udev/src/docs/libudev-docs.xml b/src/udev/src/docs/libudev-docs.xml
deleted file mode 100644 (file)
index b7feb45..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
-               "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
-[
-  <!ENTITY version SYSTEM "version.xml">
-]>
-<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
-  <bookinfo>
-    <title>libudev Reference Manual</title>
-    <releaseinfo>for libudev version &version;</releaseinfo>
-    <copyright>
-      <year>2009-2011</year>
-      <holder>Kay Sievers &lt;kay.sievers@vrfy.org&gt;</holder>
-    </copyright>
-  </bookinfo>
-
-  <chapter>
-    <title>libudev</title>
-    <xi:include href="xml/libudev.xml"/>
-    <xi:include href="xml/libudev-list.xml"/>
-    <xi:include href="xml/libudev-device.xml"/>
-    <xi:include href="xml/libudev-monitor.xml"/>
-    <xi:include href="xml/libudev-enumerate.xml"/>
-    <xi:include href="xml/libudev-queue.xml"/>
-    <xi:include href="xml/libudev-util.xml"/>
-  </chapter>
-
-  <index id="api-index-full">
-    <title>API Index</title>
-    <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
-  </index>
-</book>
diff --git a/src/udev/src/docs/libudev-sections.txt b/src/udev/src/docs/libudev-sections.txt
deleted file mode 100644 (file)
index 15c3e93..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-<SECTION>
-<FILE>libudev</FILE>
-<TITLE>udev</TITLE>
-udev
-udev_ref
-udev_unref
-udev_new
-udev_set_log_fn
-udev_get_log_priority
-udev_set_log_priority
-udev_get_sys_path
-udev_get_dev_path
-udev_get_run_path
-udev_get_userdata
-udev_set_userdata
-</SECTION>
-
-<SECTION>
-<FILE>libudev-list</FILE>
-<TITLE>udev_list</TITLE>
-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
-</SECTION>
-
-<SECTION>
-<FILE>libudev-device</FILE>
-<TITLE>udev_device</TITLE>
-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_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_get_sysattr_list_entry
-udev_device_get_seqnum
-udev_device_get_usec_since_initialized
-udev_device_has_tag
-</SECTION>
-
-<SECTION>
-<FILE>libudev-monitor</FILE>
-<TITLE>udev_monitor</TITLE>
-udev_monitor
-udev_monitor_ref
-udev_monitor_unref
-udev_monitor_get_udev
-udev_monitor_new_from_netlink
-udev_monitor_new_from_socket
-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
-</SECTION>
-
-<SECTION>
-<FILE>libudev-enumerate</FILE>
-<TITLE>udev_enumerate</TITLE>
-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
-</SECTION>
-
-<SECTION>
-<FILE>libudev-queue</FILE>
-<TITLE>udev_queue</TITLE>
-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
-</SECTION>
-
-<SECTION>
-<FILE>libudev-util</FILE>
-<TITLE>udev_util</TITLE>
-udev_util_encode_string
-</SECTION>
diff --git a/src/udev/src/docs/libudev.types b/src/udev/src/docs/libudev.types
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/src/udev/src/docs/version.xml.in b/src/udev/src/docs/version.xml.in
deleted file mode 100644 (file)
index d78bda9..0000000
+++ /dev/null
@@ -1 +0,0 @@
-@VERSION@
diff --git a/src/udev/src/floppy/60-floppy.rules b/src/udev/src/floppy/60-floppy.rules
deleted file mode 100644 (file)
index 53e4a9e..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-# do not edit this file, it will be overwritten on update
-
-SUBSYSTEM=="block", KERNEL=="fd[0-9]", ACTION=="add", ATTRS{cmos}=="?*", ENV{CMOS_TYPE}="$attr{cmos}", \
-  RUN+="create_floppy_devices -c -t $env{CMOS_TYPE} -m %M -M 0660 -G floppy $root/%k"
diff --git a/src/udev/src/floppy/create_floppy_devices.c b/src/udev/src/floppy/create_floppy_devices.c
deleted file mode 100644 (file)
index f71ef0d..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Create all possible floppy device based on the CMOS type.
- * Based upon code from drivers/block/floppy.c
- *
- * Copyright(C) 2005, SUSE Linux Products GmbH
- *
- * Author: Hannes Reinecke <hare@suse.de>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <pwd.h>
-#include <grp.h>
-
-#include "libudev.h"
-#include "libudev-private.h"
-
-static char *table[] = {
-        "", "d360", "h1200", "u360", "u720", "h360", "h720",
-        "u1440", "u2880", "CompaQ", "h1440", "u1680", "h410",
-        "u820", "h1476", "u1722", "h420", "u830", "h1494", "u1743",
-        "h880", "u1040", "u1120", "h1600", "u1760", "u1920",
-        "u3200", "u3520", "u3840", "u1840", "u800", "u1600",
-        NULL
-};
-
-static int t360[] = { 1, 0 };
-static int t1200[] = { 2, 5, 6, 10, 12, 14, 16, 18, 20, 23, 0 };
-static int t3in[] = { 8, 9, 26, 27, 28, 7, 11, 15, 19, 24, 25, 29, 31, 3, 4, 13, 17, 21, 22, 30, 0 };
-static int *table_sup[] = { NULL, t360, t1200, t3in+5+8, t3in+5, t3in, t3in };
-
-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;
-        char *dev;
-        char *devname;
-        char node[64];
-        int type = 0, i, fdnum, c;
-        int major = 2, minor;
-        uid_t uid = 0;
-        gid_t gid = 0;
-        mode_t mode = 0660;
-        int create_nodes = 0;
-        int print_nodes = 0;
-        int is_err = 0;
-
-        udev = udev_new();
-        if (udev == NULL)
-                goto exit;
-
-        udev_log_init("create_floppy_devices");
-        udev_set_log_fn(udev, log_fn);
-        udev_selinux_init(udev);
-
-        while ((c = getopt(argc, argv, "cudm:U:G:M:t:")) != -1) {
-                switch (c) {
-                case 'c':
-                        create_nodes = 1;
-                        break;
-                case 'd':
-                        print_nodes = 1;
-                        break;
-                case 'U':
-                        uid = util_lookup_user(udev, optarg);
-                        break;
-                case 'G':
-                        gid = util_lookup_group(udev, optarg);
-                        break;
-                case 'M':
-                        mode = strtol(optarg, NULL, 0);
-                        mode = mode & 0666;
-                        break;
-                case 'm':
-                        major = strtol(optarg, NULL, 0);
-                        break;
-                case 't':
-                        type = strtol(optarg, NULL, 0);
-                        break;
-                default:
-                        is_err++;
-                        break;
-                }
-        }
-
-        if (is_err || optind >= argc) {
-                printf("Usage:  %s [OPTION] device\n"
-                       "  -c   create\n"
-                       "  -d   debug\n"
-                       "  -m   Major number\n"
-                       "  -t   floppy type number\n"
-                       "  -U   device node user ownership\n"
-                       "  -G   device node group owner\n"
-                       "  -M   device node mode\n"
-                       "\n", argv[0]);
-                return 1;
-        }
-
-        dev = argv[optind];
-        devname = strrchr(dev, '/');
-        if (devname != NULL)
-                devname = &devname[1];
-        else
-                devname = dev;
-        if (strncmp(devname, "fd", 2) != 0) {
-                fprintf(stderr,"Device '%s' is not a floppy device\n", dev);
-                return 1;
-        }
-
-        fdnum = strtol(&devname[2], NULL, 10);
-        if (fdnum < 0 || fdnum > 7) {
-                fprintf(stderr,"Floppy device number %d out of range (0-7)\n", fdnum);
-                return 1;
-        }
-        if (fdnum > 3)
-                fdnum += 124;
-
-        if (major < 1) {
-                fprintf(stderr,"Invalid major number %d\n", major);
-                return 1;
-        }
-
-        if (type < 0 || type >= (int) ARRAY_SIZE(table_sup)) {
-                fprintf(stderr,"Invalid CMOS type %d\n", type);
-                return 1;
-        }
-
-        if (type == 0)
-                return 0;
-
-        i = 0;
-        while (table_sup[type][i]) {
-                sprintf(node, "%s%s", dev, table[table_sup[type][i]]);
-                minor = (table_sup[type][i] << 2) + fdnum;
-                if (print_nodes)
-                        printf("%s b %.4o %d %d\n", node, mode, major, minor);
-                if (create_nodes) {
-                        unlink(node);
-                        udev_selinux_setfscreatecon(udev, node, S_IFBLK | mode);
-                        mknod(node, S_IFBLK | mode, makedev(major,minor));
-                        udev_selinux_resetfscreatecon(udev);
-                        chown(node, uid, gid);
-                        chmod(node, S_IFBLK | mode);
-                }
-                i++;
-        }
-
-        udev_selinux_exit(udev);
-        udev_unref(udev);
-        udev_log_close();
-exit:
-        return 0;
-}
diff --git a/src/udev/src/gudev/.gitignore b/src/udev/src/gudev/.gitignore
deleted file mode 100644 (file)
index d20fa52..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-gtk-doc.make
-docs/version.xml
-gudev-1.0.pc
-gudevenumtypes.c
-gudevenumtypes.h
-gudevmarshal.c
-gudevmarshal.h
-GUdev-1.0.gir
-GUdev-1.0.typelib
diff --git a/src/udev/src/gudev/COPYING b/src/udev/src/gudev/COPYING
deleted file mode 100644 (file)
index da97db2..0000000
+++ /dev/null
@@ -1,502 +0,0 @@
-                  GNU LESSER GENERAL PUBLIC LICENSE
-                       Version 2.1, February 1999
-
- Copyright (C) 1991, 1999 Free Software Foundation, Inc.
-     51 Franklin St, 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.
-\f
-  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.
-\f
-                  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.
-\f
-  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.
-\f
-  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.
-\f
-  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.
-\f
-  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.
-\f
-  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.
-\f
-  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
-\f
-           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.
-
-    <one line to give the library's name and a brief idea of what it does.>
-    Copyright (C) <year>  <name of author>
-
-    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 St, 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.
-
-  <signature of Ty Coon>, 1 April 1990
-  Ty Coon, President of Vice
-
-That's all there is to it!
diff --git a/src/udev/src/gudev/docs/.gitignore b/src/udev/src/gudev/docs/.gitignore
deleted file mode 100644 (file)
index 8eada6d..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-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.stamp
-html/*
-xml/*
-tmpl/*
-*.stamp
diff --git a/src/udev/src/gudev/docs/Makefile.am b/src/udev/src/gudev/docs/Makefile.am
deleted file mode 100644 (file)
index cfe696c..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-## Process this file with automake to produce Makefile.in
-
-# We require automake 1.10 at least.
-AUTOMAKE_OPTIONS = 1.10
-
-# 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
-
-# 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=--sgml-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=
-
-# 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=
-
-# 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=
-
-# 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 = \
-        $(DBUS_GLIB_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)/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
-#TESTS_ENVIRONMENT = cd $(srcsrc)
-#TESTS = $(GTKDOC_CHECK)
-endif
diff --git a/src/udev/src/gudev/docs/gudev-docs.xml b/src/udev/src/gudev/docs/gudev-docs.xml
deleted file mode 100644 (file)
index f876c3b..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
-               "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
-<!ENTITY version SYSTEM "version.xml">
-]>
-<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
-  <bookinfo>
-    <title>GUDev Reference Manual</title>
-    <releaseinfo>For GUdev version &version;</releaseinfo>
-    <authorgroup>
-      <author>
-        <firstname>David</firstname>
-        <surname>Zeuthen</surname>
-        <affiliation>
-          <address>
-            <email>davidz@redhat.com</email>
-          </address>
-        </affiliation>
-      </author>
-      <author>
-        <firstname>Bastien</firstname>
-        <surname>Nocera</surname>
-        <affiliation>
-          <address>
-            <email>hadess@hadess.net</email>
-          </address>
-        </affiliation>
-      </author>
-    </authorgroup>
-
-    <copyright>
-      <year>2011</year>
-      <holder>The GUDev Authors</holder>
-    </copyright>
-
-    <legalnotice>
-      <para>
-        Permission is granted to copy, distribute and/or modify this
-        document under the terms of the <citetitle>GNU Free
-        Documentation License</citetitle>, Version 1.1 or any later
-        version published by the Free Software Foundation with no
-        Invariant Sections, no Front-Cover Texts, and no Back-Cover
-        Texts. You may obtain a copy of the <citetitle>GNU Free
-        Documentation License</citetitle> from the Free Software
-        Foundation by visiting <ulink type="http"
-        url="http://www.fsf.org">their Web site</ulink> or by writing
-        to:
-
-        <address>
-          The Free Software Foundation, Inc.,
-          <street>59 Temple Place</street> - Suite 330,
-          <city>Boston</city>, <state>MA</state> <postcode>02111-1307</postcode>,
-          <country>USA</country>
-        </address>
-      </para>
-
-      <para>
-        Many of the names used by companies to distinguish their
-        products and services are claimed as trademarks. Where those
-        names appear in any freedesktop.org documentation, and those
-        trademarks are made aware to the members of the
-        freedesktop.org Project, the names have been printed in caps
-        or initial caps.
-      </para>
-    </legalnotice>
-  </bookinfo>
-
-  <reference id="ref-API">
-    <title>API Reference</title>
-    <partintro>
-      <para>
-        This part presents the class and function reference for the
-        <literal>libgudev</literal> library.
-      </para>
-    </partintro>
-    <xi:include href="xml/gudevclient.xml"/>
-    <xi:include href="xml/gudevdevice.xml"/>
-    <xi:include href="xml/gudevenumerator.xml"/>
-  </reference>
-
-  <chapter id="gudev-hierarchy">
-    <title>Object Hierarchy</title>
-      <xi:include href="xml/tree_index.sgml"/>
-  </chapter>
-  <index>
-    <title>Index</title>
-  </index>
-  <index role="165">
-    <title>Index of new symbols in 165</title>
-    <xi:include href="xml/api-index-165.xml"><xi:fallback /></xi:include>
-  </index>
-
-</book>
diff --git a/src/udev/src/gudev/docs/gudev-sections.txt b/src/udev/src/gudev/docs/gudev-sections.txt
deleted file mode 100644 (file)
index 213e1a7..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-<SECTION>
-<FILE>gudevclient</FILE>
-<TITLE>GUdevClient</TITLE>
-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
-<SUBSECTION Standard>
-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
-<SUBSECTION Private>
-GUdevClientPrivate
-</SECTION>
-
-<SECTION>
-<FILE>gudevdevice</FILE>
-<TITLE>GUdevDevice</TITLE>
-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
-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
-<SUBSECTION Standard>
-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
-<SUBSECTION Private>
-GUdevDevicePrivate
-</SECTION>
-
-<SECTION>
-<FILE>gudevenumerator</FILE>
-<TITLE>GUdevEnumerator</TITLE>
-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
-<SUBSECTION Standard>
-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
-<SUBSECTION Private>
-GUdevEnumeratorPrivate
-</SECTION>
-
-<SECTION>
-<FILE>gudevmarshal</FILE>
-<SUBSECTION Private>
-g_udev_marshal_VOID__STRING_OBJECT
-</SECTION>
-
-<SECTION>
-<FILE>gudevenumtypes</FILE>
-<SUBSECTION Private>
-G_TYPE_UDEV_DEVICE_TYPE
-g_udev_device_type_get_type
-</SECTION>
diff --git a/src/udev/src/gudev/docs/gudev.types b/src/udev/src/gudev/docs/gudev.types
deleted file mode 100644 (file)
index a89857a..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-g_udev_device_type_get_type
-g_udev_device_get_type
-g_udev_client_get_type
-g_udev_enumerator_get_type
diff --git a/src/udev/src/gudev/docs/version.xml.in b/src/udev/src/gudev/docs/version.xml.in
deleted file mode 100644 (file)
index d78bda9..0000000
+++ /dev/null
@@ -1 +0,0 @@
-@VERSION@
diff --git a/src/udev/src/gudev/gjs-example.js b/src/udev/src/gudev/gjs-example.js
deleted file mode 100755 (executable)
index 5586fd6..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-#!/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/udev/src/gudev/gudev-1.0.pc.in b/src/udev/src/gudev/gudev-1.0.pc.in
deleted file mode 100644 (file)
index 058262d..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-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/udev/src/gudev/gudev.h b/src/udev/src/gudev/gudev.h
deleted file mode 100644 (file)
index a313460..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
- *
- * 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.
- *
- * 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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __G_UDEV_H__
-#define __G_UDEV_H__
-
-#define _GUDEV_INSIDE_GUDEV_H 1
-#include <gudev/gudevenums.h>
-#include <gudev/gudevenumtypes.h>
-#include <gudev/gudevtypes.h>
-#include <gudev/gudevclient.h>
-#include <gudev/gudevdevice.h>
-#include <gudev/gudevenumerator.h>
-#undef _GUDEV_INSIDE_GUDEV_H
-
-#endif /* __G_UDEV_H__ */
diff --git a/src/udev/src/gudev/gudevclient.c b/src/udev/src/gudev/gudevclient.c
deleted file mode 100644 (file)
index 2b94102..0000000
+++ /dev/null
@@ -1,527 +0,0 @@
-/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2008-2010 David Zeuthen <davidz@redhat.com>
- *
- * 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.
- *
- * 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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-
-#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
- * <literal>sysfs</literal> filesystem) and the udev daemon (through a
- * <literal>tmpfs</literal> 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
-   * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
-   * 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
- * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
- * 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/udev/src/gudev/gudevclient.h b/src/udev/src/gudev/gudevclient.h
deleted file mode 100644 (file)
index b425d03..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
- *
- * 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.
- *
- * 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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H)
-#error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents."
-#endif
-
-#ifndef __G_UDEV_CLIENT_H__
-#define __G_UDEV_CLIENT_H__
-
-#include <gudev/gudevtypes.h>
-
-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/udev/src/gudev/gudevdevice.c b/src/udev/src/gudev/gudevdevice.c
deleted file mode 100644 (file)
index 62a26f9..0000000
+++ /dev/null
@@ -1,963 +0,0 @@
-/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
- *
- * 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.
- *
- * 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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-
-#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(),
- * 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 **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->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 <literal>/dev</literal>) 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:
- * @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/udev/src/gudev/gudevdevice.h b/src/udev/src/gudev/gudevdevice.h
deleted file mode 100644 (file)
index d4873ba..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
- *
- * 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.
- *
- * 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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H)
-#error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents."
-#endif
-
-#ifndef __G_UDEV_DEVICE_H__
-#define __G_UDEV_DEVICE_H__
-
-#include <gudev/gudevtypes.h>
-
-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        *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/udev/src/gudev/gudevenumerator.c b/src/udev/src/gudev/gudevenumerator.c
deleted file mode 100644 (file)
index db09074..0000000
+++ /dev/null
@@ -1,431 +0,0 @@
-/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2008-2010 David Zeuthen <davidz@redhat.com>
- *
- * 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.
- *
- * 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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-
-#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/udev/src/gudev/gudevenumerator.h b/src/udev/src/gudev/gudevenumerator.h
deleted file mode 100644 (file)
index 3fddccf..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2008-2010 David Zeuthen <davidz@redhat.com>
- *
- * 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.
- *
- * 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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H)
-#error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents."
-#endif
-
-#ifndef __G_UDEV_ENUMERATOR_H__
-#define __G_UDEV_ENUMERATOR_H__
-
-#include <gudev/gudevtypes.h>
-
-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/udev/src/gudev/gudevenums.h b/src/udev/src/gudev/gudevenums.h
deleted file mode 100644 (file)
index c3a0aa8..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
- *
- * 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.
- *
- * 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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H)
-#error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents."
-#endif
-
-#ifndef __G_UDEV_ENUMS_H__
-#define __G_UDEV_ENUMS_H__
-
-#include <glib-object.h>
-
-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/udev/src/gudev/gudevenumtypes.c.template b/src/udev/src/gudev/gudevenumtypes.c.template
deleted file mode 100644 (file)
index fc30b39..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*** BEGIN file-header ***/
-#include <gudev.h>
-
-/*** 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/udev/src/gudev/gudevenumtypes.h.template b/src/udev/src/gudev/gudevenumtypes.h.template
deleted file mode 100644 (file)
index d0ab339..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*** BEGIN file-header ***/
-#ifndef __GUDEV_ENUM_TYPES_H__
-#define __GUDEV_ENUM_TYPES_H__
-
-#include <glib-object.h>
-
-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/udev/src/gudev/gudevmarshal.list b/src/udev/src/gudev/gudevmarshal.list
deleted file mode 100644 (file)
index 7e66599..0000000
+++ /dev/null
@@ -1 +0,0 @@
-VOID:STRING,OBJECT
diff --git a/src/udev/src/gudev/gudevprivate.h b/src/udev/src/gudev/gudevprivate.h
deleted file mode 100644 (file)
index 8866f52..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
- *
- * 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.
- *
- * 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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H)
-#error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents."
-#endif
-
-#ifndef __G_UDEV_PRIVATE_H__
-#define __G_UDEV_PRIVATE_H__
-
-#include <gudev/gudevtypes.h>
-
-#include <libudev.h>
-
-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/udev/src/gudev/gudevtypes.h b/src/udev/src/gudev/gudevtypes.h
deleted file mode 100644 (file)
index 8884827..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
- *
- * 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.
- *
- * 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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H)
-#error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents."
-#endif
-
-#ifndef __G_UDEV_TYPES_H__
-#define __G_UDEV_TYPES_H__
-
-#include <gudev/gudevenums.h>
-#include <sys/types.h>
-
-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/udev/src/gudev/seed-example-enum.js b/src/udev/src/gudev/seed-example-enum.js
deleted file mode 100755 (executable)
index 66206ad..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/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/udev/src/gudev/seed-example.js b/src/udev/src/gudev/seed-example.js
deleted file mode 100755 (executable)
index e2ac324..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-#!/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/udev/src/keymap/.gitignore b/src/udev/src/keymap/.gitignore
deleted file mode 100644 (file)
index 4567584..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-keyboard-force-release.sh
-keys-from-name.gperf
-keys-from-name.h
-keys-to-name.h
-keys.txt
diff --git a/src/udev/src/keymap/95-keyboard-force-release.rules b/src/udev/src/keymap/95-keyboard-force-release.rules
deleted file mode 100644 (file)
index 03d56e8..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-# Set model specific atkbd force_release quirk
-#
-# Several laptops have hotkeys which don't generate release events,
-# which can cause problems with software key repeat.
-# The atkbd driver has a quirk handler for generating synthetic
-# release events, which can be configured via sysfs since 2.6.32.
-# Simply add a file with a list of scancodes for your laptop model
-# in /usr/lib/udev/keymaps, and add a rule here.
-# If the hotkeys also need a keymap assignment you can copy the
-# scancodes from the keymap file, otherwise you can run
-# /usr/lib/udev/keymap -i /dev/input/eventX
-# on a Linux vt to find out.
-
-ACTION=="remove", GOTO="force_release_end"
-SUBSYSTEM!="serio", GOTO="force_release_end"
-KERNEL!="serio*", GOTO="force_release_end"
-DRIVER!="atkbd", GOTO="force_release_end"
-
-ENV{DMI_VENDOR}="$attr{[dmi/id]sys_vendor}"
-
-ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", RUN+="keyboard-force-release.sh $devpath samsung-other"
-ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", ATTR{[dmi/id]product_name}=="*90X3A*", RUN+="keyboard-force-release.sh $devpath samsung-90x3a"
-
-ENV{DMI_VENDOR}=="Dell Inc.", ATTR{[dmi/id]product_name}=="Studio 1557|Studio 1558", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
-ENV{DMI_VENDOR}=="Dell Inc.", ATTR{[dmi/id]product_name}=="Latitude E*|Precision M*", RUN+="keyboard-force-release.sh $devpath dell-touchpad"
-
-ENV{DMI_VENDOR}=="FUJITSU SIEMENS", ATTR{[dmi/id]product_name}=="AMILO Si 1848+u|AMILO Xi 2428", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
-
-ENV{DMI_VENDOR}=="FOXCONN", ATTR{[dmi/id]product_name}=="QBOOK", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
-
-ENV{DMI_VENDOR}=="MTC", ATTR{[dmi/id]product_version}=="A0", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
-
-ENV{DMI_VENDOR}=="PEGATRON CORP.", ATTR{[dmi/id]product_name}=="Spring Peak", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
-
-ENV{DMI_VENDOR}=="TOSHIBA", ATTR{[dmi/id]product_name}=="Satellite [uU]300*|Satellite Pro [uU]300*|Satellite [uU]305*|SATELLITE [uU]500*", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
-
-ENV{DMI_VENDOR}=="Viooo Corporation", ATTR{[dmi/id]product_name}=="PT17", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
-
-# These are all the HP laptops that setup a touchpad toggle key
-ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*[pP][aA][vV][iI][lL][iI][oO][nN]*", RUN+="keyboard-force-release.sh $devpath hp-other"
-ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*[tT][xX]2*", RUN+="keyboard-force-release.sh $devpath hp-other"
-ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*2510p*|*2530p*|HP G60 Notebook PC", RUN+="keyboard-force-release.sh $devpath hp-other"
-
-ENV{DMI_VENDOR}=="Zepto", ATTR{[dmi/id]product_name}=="Znote 6615WD", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
-
-ENV{DMI_VENDOR}=="Zepto", ATTR{[dmi/id]product_name}=="Znote", ATTR{[dmi/id]product_version}=="6625WD", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
-
-ENV{DMI_VENDOR}=="HANNspree", ATTR{[dmi/id]product_name}=="SN10E100", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
-
-ENV{DMI_VENDOR}=="GIGABYTE", ATTR{[dmi/id]product_name}=="i1520M", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
-
-ENV{DMI_VENDOR}=="BenQ", ATTR{[dmi/id]product_name}=="*nScreen*", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
-
-LABEL="force_release_end"
diff --git a/src/udev/src/keymap/95-keymap.rules b/src/udev/src/keymap/95-keymap.rules
deleted file mode 100644 (file)
index bbf311a..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-# Set model specific hotkey keycodes.
-#
-# Key map overrides can be specified by either giving scancode/keyname pairs
-# directly as keymap arguments (if there are just one or two to change), or as
-# a file name (in /usr/lib/udev/keymaps), which has to contain scancode/keyname
-# pairs.
-
-ACTION=="remove", GOTO="keyboard_end"
-KERNEL!="event*", GOTO="keyboard_end"
-ENV{ID_INPUT_KEY}=="", GOTO="keyboard_end"
-SUBSYSTEMS=="bluetooth", GOTO="keyboard_end"
-
-SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id"
-SUBSYSTEMS=="usb", GOTO="keyboard_usbcheck"
-GOTO="keyboard_modulecheck"
-
-#
-# The following are external USB keyboards
-#
-
-LABEL="keyboard_usbcheck"
-
-ENV{ID_VENDOR}=="Genius", ENV{ID_MODEL_ID}=="0708", ENV{ID_USB_INTERFACE_NUM}=="01", RUN+="keymap $name genius-slimstar-320"
-ENV{ID_VENDOR}=="Logitech*", ATTRS{name}=="Logitech USB Multimedia Keyboard", RUN+="keymap $name logitech-wave"
-ENV{ID_VENDOR}=="Logitech*", ATTRS{name}=="Logitech USB Receiver", RUN+="keymap $name logitech-wave-cordless"
-# Logitech Cordless Wave Pro looks slightly weird; some hotkeys are coming through the mouse interface
-ENV{ID_VENDOR_ID}=="046d", ENV{ID_MODEL_ID}=="c52[9b]", ATTRS{name}=="Logitech USB Receiver", RUN+="keymap $name logitech-wave-pro-cordless"
-
-ENV{ID_VENDOR}=="Lite-On_Technology_Corp*", ATTRS{name}=="Lite-On Technology Corp. ThinkPad USB Keyboard with TrackPoint", RUN+="keymap $name lenovo-thinkpad-usb-keyboard-trackpoint"
-ENV{ID_VENDOR_ID}=="04b3", ENV{ID_MODEL_ID}=="301[89]", RUN+="keymap $name ibm-thinkpad-usb-keyboard-trackpoint"
-
-ENV{ID_VENDOR}=="Microsoft", ENV{ID_MODEL_ID}=="00db", RUN+="keymap $name 0xc022d zoomin 0xc022e zoomout"
-
-GOTO="keyboard_end"
-
-#
-# The following are exposed as separate input devices with low key codes, thus
-# we need to check their input device product name
-#
-
-LABEL="keyboard_modulecheck"
-
-ENV{DMI_VENDOR}="$attr{[dmi/id]sys_vendor}"
-ENV{DMI_VENDOR}=="", GOTO="keyboard_end"
-
-ENV{DMI_VENDOR}=="LENOVO*", KERNELS=="input*", ATTRS{name}=="ThinkPad Extra Buttons", RUN+="keymap $name module-lenovo"
-ENV{DMI_VENDOR}=="LENOVO*", KERNELS=="input*", ATTRS{name}=="Lenovo ThinkPad SL Series extra buttons", RUN+="keymap $name 0x0E bluetooth"
-
-ENV{DMI_VENDOR}=="ASUS*", KERNELS=="input*", ATTRS{name}=="Asus Extra Buttons", ATTR{[dmi/id]product_name}=="W3J", RUN+="keymap $name module-asus-w3j"
-ENV{DMI_VENDOR}=="ASUS*", KERNELS=="input*", ATTRS{name}=="Eee PC WMI hotkeys|Asus Laptop Support|Asus*WMI*", RUN+="keymap $name 0x6B f21"
-ENV{DMI_VENDOR}=="ASUS*", KERNELS=="input*", ATTRS{name}=="Eee PC Hotkey Driver", RUN+="keymap $name 0x37 f21"
-
-ENV{DMI_VENDOR}=="IBM*", KERNELS=="input*", ATTRS{name}=="ThinkPad Extra Buttons", RUN+="keymap $name module-ibm"
-ENV{DMI_VENDOR}=="Sony*", KERNELS=="input*", ATTRS{name}=="Sony Vaio Keys", RUN+="keymap $name module-sony"
-ENV{DMI_VENDOR}=="Acer*", KERNELS=="input*", ATTRS{name}=="Acer WMI hotkeys", RUN+="keymap $name 0x82 f21"
-ENV{DMI_VENDOR}=="MICRO-STAR*|Micro-Star*", KERNELS=="input*", ATTRS{name}=="MSI Laptop hotkeys", RUN+="keymap $name 0x213 f22 0x214 f23"
-
-# Older Vaios have some different keys
-ENV{DMI_VENDOR}=="Sony*", ATTR{[dmi/id]product_name}=="*PCG-C1*|*PCG-K25*|*PCG-F1*|*PCG-F2*|*PCG-F3*|*PCG-F4*|*PCG-F5*|*PCG-F6*|*PCG-FX*|*PCG-FRV*|*PCG-GR*|*PCG-TR*|*PCG-NV*|*PCG-Z*|*VGN-S360*", ATTRS{name}=="Sony Vaio Keys", RUN+="keymap $name module-sony-old"
-
-# Some Sony VGN models have yet another one
-ENV{DMI_VENDOR}=="Sony*", ATTR{[dmi/id]product_name}=="VGN-AR71*|VGN-FW*|VGN-Z21*", ATTRS{name}=="Sony Vaio Keys", RUN+="keymap $name module-sony-vgn"
-
-
-#
-# The following rules belong to standard i8042 AT keyboard with high key codes.
-#
-
-DRIVERS=="atkbd", GOTO="keyboard_vendorcheck"
-GOTO="keyboard_end"
-
-LABEL="keyboard_vendorcheck"
-
-ENV{DMI_VENDOR}=="Dell*", RUN+="keymap $name dell"
-ENV{DMI_VENDOR}=="Dell*", ATTR{[dmi/id]product_name}=="Inspiron 910|Inspiron 1010|Inspiron 1011|Inspiron 1012|Inspiron 1110|Inspiron 1210", RUN+="keymap $name 0x84 wlan"
-ENV{DMI_VENDOR}=="Dell*", ATTR{[dmi/id]product_name}=="Latitude XT2", RUN+="keymap $name dell-latitude-xt2"
-
-ENV{DMI_VENDOR}=="Compaq*", ATTR{[dmi/id]product_name}=="*E500*|*Evo N*", RUN+="keymap $name compaq-e_evo"
-
-ENV{DMI_VENDOR}=="LENOVO*", ATTR{[dmi/id]product_version}=="*3000*", RUN+="keymap $name lenovo-3000"
-ENV{DMI_VENDOR}=="LENOVO*", ATTR{[dmi/id]product_version}=="ThinkPad X6*", ATTR{[dmi/id]product_version}=="* Tablet", RUN+="keymap $name lenovo-thinkpad_x6_tablet"
-ENV{DMI_VENDOR}=="LENOVO*", ATTR{[dmi/id]product_version}=="ThinkPad X2[02]* Tablet*", ATTR{[dmi/id]product_version}=="* Tablet", RUN+="keymap $name lenovo-thinkpad_x200_tablet"
-ENV{DMI_VENDOR}=="LENOVO*", ATTR{[dmi/id]product_version}=="*IdeaPad*", RUN+="keymap $name lenovo-ideapad"
-ENV{DMI_VENDOR}=="LENOVO*", ATTR{[dmi/id]product_name}=="S10-*", RUN+="keymap $name lenovo-ideapad"
-ENV{DMI_VENDOR}=="LENOVO", ATTR{[dmi/id]product_version}=="*IdeaPad Y550*", RUN+="keymap $name 0x95 media 0xA3 play"
-
-ENV{DMI_VENDOR}=="Hewlett-Packard*", RUN+="keymap $name hewlett-packard"
-ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*[tT][aA][bB][lL][eE][tT]*", RUN+="keymap $name hewlett-packard-tablet"
-ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*[pP][aA][vV][iI][lL][iI][oO][nN]*", RUN+="keymap $name hewlett-packard-pavilion"
-ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*Compaq*|*EliteBook*|*2230s*", RUN+="keymap $name hewlett-packard-compaq_elitebook"
-ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*2510p*|*2530p*|HP G60 Notebook PC", RUN+="keymap $name hewlett-packard-2510p_2530p"
-ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*[tT][xX]2*", RUN+="keymap $name hewlett-packard-tx2"
-ENV{DMI_VENDOR}=="Hewlett-Packard", ATTR{[dmi/id]product_name}=="Presario 2100*", RUN+="keymap $name hewlett-packard-presario-2100"
-ENV{DMI_VENDOR}=="Hewlett-Packard", ATTR{[dmi/id]product_name}=="HP G62 Notebook PC", RUN+="keymap $name 0xB2 www"
-ENV{DMI_VENDOR}=="Hewlett-Packard", ATTR{[dmi/id]product_name}=="HP ProBook*", RUN+="keymap $name 0xF8 rfkill"
-# HP Pavillion dv6315ea has empty DMI_VENDOR
-ATTR{[dmi/id]board_vendor}=="Quanta", ATTR{[dmi/id]board_name}=="30B7", ATTR{[dmi/id]board_version}=="65.2B", RUN+="keymap $name 0x88 media" # "quick play
-
-# Gateway clone of Acer Aspire One AOA110/AOA150
-ENV{DMI_VENDOR}=="Gateway*", ATTR{[dmi/id]product_name}=="*AOA1*", RUN+="keymap $name acer"
-
-ENV{DMI_VENDOR}=="Acer*", RUN+="keymap $name acer"
-ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="Extensa*", ATTR{[dmi/id]product_name}=="*5210*|*5220*|*5610*|*5620*|*5720*", RUN+="keymap $name 0xEE screenlock"
-ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="TravelMate*C3[01]0*", RUN+="keymap $name acer-travelmate_c300"
-ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="TravelMate*6292*|TravelMate*8471*|TravelMate*4720*|TravelMate*7720*|Aspire 1810T*|AO751h|AO531h", RUN+="keymap $name 0xD9 bluetooth"
-ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="TravelMate*4720*", RUN+="keymap $name 0xB2 www 0xEE screenlock"
-ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="TravelMate 6593|Aspire 1640", RUN+="keymap $name 0xB2 www 0xEE screenlock"
-ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="Aspire 6920", RUN+="keymap $name acer-aspire_6920"
-ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="Aspire 5920G", RUN+="keymap $name acer-aspire_5920g"
-ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="Aspire 5720*", RUN+="keymap $name acer-aspire_5720"
-ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="Aspire 8930", RUN+="keymap $name acer-aspire_8930"
-ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_serial}=="ZG8*", RUN+="keymap $name acer-aspire_5720"
-
-ENV{DMI_VENDOR}=="*BenQ*", ATTR{[dmi/id]product_name}=="*Joybook R22*", RUN+="keymap $name 0x6E wlan"
-
-ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="*AMILO Pro V3205*", RUN+="keymap $name fujitsu-amilo_pro_v3205"
-ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="*AMILO Pa 2548*", RUN+="keymap $name fujitsu-amilo_pa_2548"
-ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="*ESPRIMO Mobile V5*", RUN+="keymap $name fujitsu-esprimo_mobile_v5"
-ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="*ESPRIMO Mobile V6*", RUN+="keymap $name fujitsu-esprimo_mobile_v6"
-ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="*AMILO Pro Edition V3505*", RUN+="keymap $name fujitsu-amilo_pro_edition_v3505"
-ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="*Amilo Si 1520*", RUN+="keymap $name fujitsu-amilo_si_1520"
-ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="AMILO*M*", RUN+="keymap $name 0x97 prog2 0x9F prog1"
-ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="Amilo Li 1718", RUN+="keymap $name 0xD6 wlan"
-ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="AMILO Li 2732", RUN+="keymap $name fujitsu-amilo_li_2732"
-
-ENV{DMI_VENDOR}=="LG*", ATTR{[dmi/id]product_name}=="*X110*", RUN+="keymap $name lg-x110"
-
-ENV{DMI_VENDOR}=="MEDION*", ATTR{[dmi/id]product_name}=="*FID2060*", RUN+="keymap $name medion-fid2060"
-ENV{DMI_VENDOR}=="MEDIONNB", ATTR{[dmi/id]product_name}=="A555*", RUN+="keymap $name medionnb-a555"
-
-ENV{DMI_VENDOR}=="MICRO-STAR*|Micro-Star*", RUN+="keymap $name micro-star"
-
-# some MSI models generate ACPI/input events on the LNXVIDEO input devices,
-# plus some extra synthesized ones on atkbd as an echo of actually changing the
-# brightness; so ignore those atkbd ones, to avoid loops
-ENV{DMI_VENDOR}=="MICRO-STAR*", ATTR{[dmi/id]product_name}=="*U-100*|*U100*|*N033", RUN+="keymap $name 0xF7 reserved 0xF8 reserved"
-
-ENV{DMI_VENDOR}=="INVENTEC", ATTR{[dmi/id]product_name}=="SYMPHONY 6.0/7.0", RUN+="keymap $name inventec-symphony_6.0_7.0"
-
-ENV{DMI_VENDOR}=="MAXDATA", ATTR{[dmi/id]product_name}=="Pro 7000*", RUN+="keymap $name maxdata-pro_7000"
-
-ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", RUN+="keymap $name samsung-other"
-ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", ATTR{[dmi/id]product_name}=="*SX20S*", RUN+="keymap $name samsung-sx20s"
-ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", ATTR{[dmi/id]product_name}=="SQ1US", RUN+="keymap $name samsung-sq1us"
-ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", ATTR{[dmi/id]product_name}=="*700Z*", RUN+="keymap $name 0xBA ejectcd 0x96 keyboardbrightnessup 0x97 keyboardbrightnessdown"
-ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", ATTR{[dmi/id]product_name}=="*90X3A*", RUN+="keymap $name samsung-90x3a"
-
-ENV{DMI_VENDOR}=="TOSHIBA", ATTR{[dmi/id]product_name}=="SATELLITE A100", RUN+="keymap $name toshiba-satellite_a100"
-ENV{DMI_VENDOR}=="TOSHIBA", ATTR{[dmi/id]product_name}=="Satellite A110", RUN+="keymap $name toshiba-satellite_a110"
-ENV{DMI_VENDOR}=="TOSHIBA", ATTR{[dmi/id]product_name}=="Satellite M30X", RUN+="keymap $name toshiba-satellite_m30x"
-
-ENV{DMI_VENDOR}=="OQO Inc.*", ATTR{[dmi/id]product_name}=="OQO Model 2*", RUN+="keymap $name oqo-model2"
-
-ENV{DMI_VENDOR}=="ONKYO CORPORATION", ATTR{[dmi/id]product_name}=="ONKYOPC", RUN+="keymap $name onkyo"
-
-ENV{DMI_VENDOR}=="ASUS", RUN+="keymap $name asus"
-
-ENV{DMI_VENDOR}=="VIA", ATTR{[dmi/id]product_name}=="K8N800", ATTR{[dmi/id]product_version}=="VT8204B", RUN+="keymap $name 0x81 prog1"
-
-ENV{DMI_VENDOR}=="Zepto", ATTR{[dmi/id]product_name}=="Znote", ATTR{[dmi/id]product_version}=="62*|63*", RUN+="keymap $name zepto-znote"
-
-ENV{DMI_VENDOR}=="Everex", ATTR{[dmi/id]product_name}=="XT5000*", RUN+="keymap $name everex-xt5000"
-
-ENV{DMI_VENDOR}=="COMPAL", ATTR{[dmi/id]product_name}=="HEL80I", RUN+="keymap $name 0x84 wlan"
-
-ENV{DMI_VENDOR}=="OLPC", ATTR{[dmi/id]product_name}=="XO", RUN+="keymap $name olpc-xo"
-
-ENV{DMI_VENDOR}=="Alienware*", ATTR{[dmi/id]product_name}=="M14xR1", RUN+="keymap $name 0x8A ejectcd"
-
-LABEL="keyboard_end"
diff --git a/src/udev/src/keymap/README.keymap.txt b/src/udev/src/keymap/README.keymap.txt
deleted file mode 100644 (file)
index 52d50ed..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-= The udev keymap tool =
-
-== Introduction ==
-
-This udev extension configures computer model specific key mappings. This is
-particularly necessary for the non-standard extra keys found on many laptops,
-such as "brightness up", "next song", "www browser", or "suspend". Often these
-are accessed with the Fn key.
-
-Every key produces a "scan code", which is highly vendor/model specific for the
-nonstandard keys. This tool maintains mappings for these scan codes to standard
-"key codes", which denote the "meaning" of the key. The key codes are defined
-in /usr/include/linux/input.h.
-
-If some of your keys on your keyboard are not working at all, or produce the
-wrong effect, then a very likely cause of this is that the scan code -> key
-code mapping is incorrect on your computer.
-
-== Structure ==
-
-udev-keymap consists of the following parts:
-
- keymaps/*:: mappings of scan codes to key code names
-
- 95-keymap.rules:: udev rules for mapping system vendor/product names and
- input module names to one of the keymaps above
-
- keymap:: manipulate an evdev input device:
-  * write a key map file into a device (used by udev rules)
-  * dump current scan → key code mapping
-  * interactively display scan and key codes of pressed keys
-
- findkeyboards:: display evdev input devices which belong to actual keyboards,
- i. e. those suitable for the keymap program
-
- fdi2rules.py:: convert hal keymap FDIs into udev rules and key map files
- (Please note that this is far from perfect, since the mapping between fdi and
-  udev rules is not straightforward, and impossible in some cases.)
-
-== Fixing broken keys ==
-
-In order to make a broken key work on your system and send it back to upstream
-for inclusion you need to do the following steps:
-
- 1. Find the keyboard device.
-
- Run /usr/lib/udev/findkeyboards. This should always give you an "AT
- keyboard" and possibly a "module". Some laptops (notably Thinkpads, Sonys, and
- Acers) have multimedia/function keys on a separate input device instead of the
- primary keyboard. The keyboard device should have a name like "input/event3".
- In the following commands, the name will be written as "input/eventX" (replace
- X with the appropriate number).
-
- 2. Find broken scan codes:
-
- sudo /usr/lib/udev/keymap -i input/eventX
-
- Press all multimedia/function keys and check if the key name that gets printed
- out is plausible. If it is unknown or wrong, write down the scan code (looks
- like "0x1E") and the intended functionality of this key. Look in
- /usr/include/linux/input.h for an available KEY_XXXXX constant which most
- closely approximates this functionality and write it down as the new key code.
-
- For example, you might press a key labeled "web browser" which currently
- produces "unknown". Note down this:
-
-   0x1E www # Fn+F2 web browser
-
- Repeat that for all other keys. Write the resulting list into a file. Look at
- /usr/lib/udev/keymaps/ for existing key map files and make sure that you use the
- same structure.
-
- If the key only ever works once and then your keyboard (or the entire desktop)
- gets stuck for a long time, then it is likely that the BIOS fails to send a
- corresponding "key release" event after the key press event. Please note down
- this case as well, as it can be worked around in
- /usr/lib/udev/keymaps/95-keyboard-force-release.rules .
-
- 3. Find out your system vendor and product:
-
- cat /sys/class/dmi/id/sys_vendor
- cat /sys/class/dmi/id/product_name
-
- 4. Generate a device dump with "udevadm info --export-db > /tmp/udev-db.txt".
-
- 6. Send the system vendor/product names, the key mapping from step 2,
- and /tmp/udev-db.txt from step 4 to the linux-hotplug@vger.kernel.org mailing
- list, so that they can be included in the next release.
-
-For local testing, copy your map file to /usr/lib/udev/keymaps/ with an appropriate
-name, and add an appropriate udev rule to /usr/lib/udev/rules.d/95-keymap.rules:
-
-  * If you selected an "AT keyboard", add the rule to the section after
-  'LABEL="keyboard_vendorcheck"'.
-
-  * If you selected a "module", add the rule to the top section where the
-  "ThinkPad Extra Buttons" are.
-
-== Author ==
-
-keymap is written and maintained by Martin Pitt <martin.pitt@ubuntu.com>.
diff --git a/src/udev/src/keymap/check-keymaps.sh b/src/udev/src/keymap/check-keymaps.sh
deleted file mode 100755 (executable)
index 405168c..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/bin/bash
-
-# check that all key names in keymaps/* are known in <linux/input.h>
-# and that all key maps listed in the rules are valid and present in
-# Makefile.am
-SRCDIR=${1:-.}
-KEYLIST=${2:-src/keymap/keys.txt}
-KEYMAPS_DIR=$SRCDIR/src/keymap/keymaps
-RULES=$SRCDIR/src/keymap/95-keymap.rules
-
-[ -e "$KEYLIST" ] || {
-        echo "need $KEYLIST please build first" >&2
-        exit 1
-}
-
-missing=$(join -v 2 <(awk '{print tolower(substr($1,5))}' $KEYLIST | sort -u) \
-                    <(grep -hv '^#' ${KEYMAPS_DIR}/*| awk '{print $2}' | sort -u))
-[ -z "$missing" ] || {
-        echo "ERROR: unknown key names in src/keymap/keymaps/*:" >&2
-        echo "$missing" >&2
-        exit 1
-}
-
-# check that all maps referred to in $RULES exist
-maps=$(sed -rn '/keymap \$name/ { s/^.*\$name ([^"[:space:]]+).*$/\1/; p }' $RULES)
-for m in $maps; do
-        # ignore inline mappings
-        [ "$m" = "${m#0x}" ] || continue
-
-        [ -e ${KEYMAPS_DIR}/$m ] || {
-                echo "ERROR: unknown map name in $RULES: $m" >&2
-                exit 1
-        }
-        grep -q "src/keymap/keymaps/$m\>" $SRCDIR/Makefile.am || {
-                echo "ERROR: map file $m is not added to Makefile.am" >&2
-                exit 1
-        }
-done
diff --git a/src/udev/src/keymap/findkeyboards b/src/udev/src/keymap/findkeyboards
deleted file mode 100755 (executable)
index 9ce2742..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/bin/sh -e
-# Find "real" keyboard devices and print their device path.
-# Author: Martin Pitt <martin.pitt@ubuntu.com>
-#
-# Copyright (C) 2009, Canonical Ltd.
-#
-# 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.
-
-# returns OK if $1 contains $2
-strstr() {
-        [ "${1#*$2*}" != "$1" ]
-}
-
-# returns OK if $1 contains $2 at the beginning
-str_starts() {
-        [ "${1#$2*}" != "$1" ]
-}
-
-str_line_starts() {
-        while read a; do str_starts "$a" "$1" && return 0;done
-        return 1;
-}
-
-# print a list of input devices which are keyboard-like
-keyboard_devices() {
-        # standard AT keyboard
-        for dev in `udevadm trigger --dry-run --verbose --property-match=ID_INPUT_KEYBOARD=1`; do
-                walk=`udevadm info --attribute-walk --path=$dev`
-                env=`udevadm info --query=env --path=$dev`
-                # filter out non-event devices, such as the parent input devices which have no devnode
-                if ! echo "$env" | str_line_starts 'DEVNAME='; then
-                        continue
-                fi
-                if strstr "$walk" 'DRIVERS=="atkbd"'; then
-                        echo -n 'AT keyboard: '
-                elif echo "$env" | str_line_starts 'ID_USB_DRIVER=usbhid'; then
-                        echo -n 'USB keyboard: '
-                else
-                        echo -n 'Unknown type: '
-               fi
-                       udevadm info --query=name --path=$dev
-        done
-
-        # modules
-        module=$(udevadm trigger --verbose --dry-run --subsystem-match=input --attr-match=name='*Extra Buttons')
-        module="$module
-        $(udevadm trigger --verbose --dry-run --subsystem-match=input --attr-match=name='*extra buttons')"
-        module="$module
-        $(udevadm trigger --verbose --dry-run --subsystem-match=input --attr-match=name='Sony Vaio Keys')"
-        for m in $module; do
-                for evdev in $m/event*/dev; do
-                        if [ -e "$evdev" ]; then
-                                echo -n 'module: '
-                                udevadm info --query=name --path=${evdev%%/dev}
-                        fi
-                done
-        done
-}
-
-keyboard_devices
diff --git a/src/udev/src/keymap/force-release-maps/common-volume-keys b/src/udev/src/keymap/force-release-maps/common-volume-keys
deleted file mode 100644 (file)
index 3a7654d..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-0xa0 #mute
-0xae #volume down
-0xb0 #volume up
diff --git a/src/udev/src/keymap/force-release-maps/dell-touchpad b/src/udev/src/keymap/force-release-maps/dell-touchpad
deleted file mode 100644 (file)
index 18e9bde..0000000
+++ /dev/null
@@ -1 +0,0 @@
-0x9E
diff --git a/src/udev/src/keymap/force-release-maps/hp-other b/src/udev/src/keymap/force-release-maps/hp-other
deleted file mode 100644 (file)
index 6621370..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-# list of scancodes (hex or decimal), optional comment
-0xd8 # Touchpad off
-0xd9 # Touchpad on
diff --git a/src/udev/src/keymap/force-release-maps/samsung-90x3a b/src/udev/src/keymap/force-release-maps/samsung-90x3a
deleted file mode 100644 (file)
index 65707ef..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-# list of scancodes (hex or decimal), optional comment
-0xCE # Fn+F8 keyboard backlit up
-0x8D # Fn+F7 keyboard backlit down
-0x97 # Fn+F12 wifi on/off
-0x96 # Fn+F1 performance mode (?)
-0xD5 # Fn+F6 battery life extender
diff --git a/src/udev/src/keymap/force-release-maps/samsung-other b/src/udev/src/keymap/force-release-maps/samsung-other
deleted file mode 100644 (file)
index c51123a..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-# list of scancodes (hex or decimal), optional comment
-0x82 # Fn+F4 CRT/LCD
-0x83 # Fn+F2 battery
-0x84 # Fn+F5 backlight on/off
-0x86 # Fn+F9 WLAN
-0x88 # Fn-Up brightness up
-0x89 # Fn-Down brightness down
-0xB3 # Fn+F8 switch power mode (battery/dynamic/performance)
-0xF7 # Fn+F10 Touchpad on
-0xF9 # Fn+F10 Touchpad off
diff --git a/src/udev/src/keymap/keyboard-force-release.sh.in b/src/udev/src/keymap/keyboard-force-release.sh.in
deleted file mode 100755 (executable)
index dd040ce..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#!@rootprefix@/bin/sh -e
-# read list of scancodes, convert hex to decimal and
-# append to the atkbd force_release sysfs attribute
-# $1 sysfs devpath for serioX
-# $2 file with scancode list (hex or dec)
-
-case "$2" in
-        /*) scf="$2" ;;
-        *)  scf="@pkglibexecdir@/keymaps/force-release/$2" ;;
-esac
-
-read attr <"/sys/$1/force_release"
-while read scancode dummy; do
-        case "$scancode" in
-                \#*) ;;
-                *)
-                        scancode=$(($scancode))
-                        attr="$attr${attr:+,}$scancode"
-                        ;;
-        esac
-done <"$scf"
-echo "$attr" >"/sys/$1/force_release"
diff --git a/src/udev/src/keymap/keymap.c b/src/udev/src/keymap/keymap.c
deleted file mode 100644 (file)
index 92ec67b..0000000
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- * keymap - dump keymap of an evdev device or set a new keymap from a file
- *
- * Based on keyfuzz by Lennart Poettering <mzqrovna@0pointer.net>
- * Adapted for udev-extras by Martin Pitt <martin.pitt@ubuntu.com>
- *
- * Copyright (C) 2006, Lennart Poettering
- * Copyright (C) 2009, Canonical Ltd.
- *
- * keymap is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * keymap is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY 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 keymap; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <errno.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <sys/ioctl.h>
-#include <linux/limits.h>
-#include <linux/input.h>
-
-const struct key* lookup_key (const char *str, unsigned int len);
-
-#include "keys-from-name.h"
-#include "keys-to-name.h"
-
-#define MAX_SCANCODES 1024
-
-static int evdev_open(const char *dev)
-{
-        int fd;
-        char fn[PATH_MAX];
-
-        if (strncmp(dev, "/dev", 4) != 0) {
-                snprintf(fn, sizeof(fn), "/dev/%s", dev);
-                dev = fn;
-        }
-
-        if ((fd = open(dev, O_RDWR)) < 0) {
-                fprintf(stderr, "error open('%s'): %m\n", dev);
-                return -1;
-        }
-        return fd;
-}
-
-static int evdev_get_keycode(int fd, int scancode, int e)
-{
-        int codes[2];
-
-        codes[0] = scancode;
-        if (ioctl(fd, EVIOCGKEYCODE, codes) < 0) {
-                if (e && errno == EINVAL) {
-                        return -2;
-                } else {
-                        fprintf(stderr, "EVIOCGKEYCODE: %m\n");
-                        return -1;
-                }
-        }
-        return codes[1];
-}
-
-static int evdev_set_keycode(int fd, int scancode, int keycode)
-{
-        int codes[2];
-
-        codes[0] = scancode;
-        codes[1] = keycode;
-
-        if (ioctl(fd, EVIOCSKEYCODE, codes) < 0) {
-                fprintf(stderr, "EVIOCSKEYCODE: %m\n");
-                return -1;
-        }
-        return 0;
-}
-
-static int evdev_driver_version(int fd, char *v, size_t l)
-{
-        int version;
-
-        if (ioctl(fd, EVIOCGVERSION, &version)) {
-                fprintf(stderr, "EVIOCGVERSION: %m\n");
-                return -1;
-        }
-
-        snprintf(v, l, "%i.%i.%i.", version >> 16, (version >> 8) & 0xff, version & 0xff);
-        return 0;
-}
-
-static int evdev_device_name(int fd, char *n, size_t l)
-{
-        if (ioctl(fd, EVIOCGNAME(l), n) < 0) {
-                fprintf(stderr, "EVIOCGNAME: %m\n");
-                return -1;
-        }
-        return 0;
-}
-
-/* Return a lower-case string with KEY_ prefix removed */
-static const char* format_keyname(const char* key) {
-        static char result[101];
-        const char* s;
-        int len;
-
-        for (s = key+4, len = 0; *s && len < 100; ++len, ++s)
-                result[len] = tolower(*s);
-        result[len] = '\0';
-        return result;
-}
-
-static int dump_table(int fd) {
-        char version[256], name[256];
-        int scancode, r = -1;
-
-        if (evdev_driver_version(fd, version, sizeof(version)) < 0)
-                goto fail;
-
-        if (evdev_device_name(fd, name, sizeof(name)) < 0)
-                goto fail;
-
-        printf("### evdev %s, driver '%s'\n", version, name);
-
-        r = 0;
-        for (scancode = 0; scancode < MAX_SCANCODES; scancode++) {
-                int keycode;
-
-                if ((keycode = evdev_get_keycode(fd, scancode, 1)) < 0) {
-                        if (keycode == -2)
-                                continue;
-                        r = -1;
-                        break;
-                }
-
-                if (keycode < KEY_MAX && key_names[keycode])
-                        printf("0x%03x %s\n", scancode, format_keyname(key_names[keycode]));
-                else
-                        printf("0x%03x 0x%03x\n", scancode, keycode);
-        }
-fail:
-        return r;
-}
-
-static void set_key(int fd, const char* scancode_str, const char* keyname)
-{
-        unsigned scancode;
-        char *endptr;
-        char t[105] = "KEY_UNKNOWN";
-        const struct key *k;
-
-        scancode = (unsigned) strtol(scancode_str, &endptr, 0);
-        if (*endptr != '\0') {
-                fprintf(stderr, "ERROR: Invalid scancode\n");
-                exit(1);
-        }
-
-        snprintf(t, sizeof(t), "KEY_%s", keyname);
-
-        if (!(k = lookup_key(t, strlen(t)))) {
-                fprintf(stderr, "ERROR: Unknown key name '%s'\n", keyname);
-                exit(1);
-        }
-
-        if (evdev_set_keycode(fd, scancode, k->id) < 0)
-                fprintf(stderr, "setting scancode 0x%2X to key code %i failed\n",
-                        scancode, k->id);
-        else
-                printf("setting scancode 0x%2X to key code %i\n",
-                        scancode, k->id);
-}
-
-static int merge_table(int fd, FILE *f) {
-        int r = 0;
-        int line = 0;
-
-        while (!feof(f)) {
-                char s[256], *p;
-                int scancode, new_keycode, old_keycode;
-
-                if (!fgets(s, sizeof(s), f))
-                        break;
-
-                line++;
-                p = s+strspn(s, "\t ");
-                if (*p == '#' || *p == '\n')
-                        continue;
-
-                if (sscanf(p, "%i %i", &scancode, &new_keycode) != 2) {
-                        char t[105] = "KEY_UNKNOWN";
-                        const struct key *k;
-
-                        if (sscanf(p, "%i %100s", &scancode, t+4) != 2) {
-                                fprintf(stderr, "WARNING: Parse failure at line %i, ignoring.\n", line);
-                                r = -1;
-                                continue;
-                        }
-
-                        if (!(k = lookup_key(t, strlen(t)))) {
-                                fprintf(stderr, "WARNING: Unknown key '%s' at line %i, ignoring.\n", t, line);
-                                r = -1;
-                                continue;
-                        }
-
-                        new_keycode = k->id;
-                }
-
-
-                if ((old_keycode = evdev_get_keycode(fd, scancode, 0)) < 0) {
-                        r = -1;
-                        goto fail;
-                }
-
-                if (evdev_set_keycode(fd, scancode, new_keycode) < 0) {
-                        r = -1;
-                        goto fail;
-                }
-
-                if (new_keycode != old_keycode)
-                        fprintf(stderr, "Remapped scancode 0x%02x to 0x%02x (prior: 0x%02x)\n",
-                                scancode, new_keycode, old_keycode);
-        }
-fail:
-        fclose(f);
-        return r;
-}
-
-
-/* read one event; return 1 if valid */
-static int read_event(int fd, struct input_event* ev)
-{
-        int ret;
-        ret = read(fd, ev, sizeof(struct input_event));
-
-        if (ret < 0) {
-                perror("read");
-                return 0;
-        }
-        if (ret != sizeof(struct input_event)) {
-                fprintf(stderr, "did not get enough data for event struct, aborting\n");
-                return 0;
-        }
-
-        return 1;
-}
-
-static void print_key(uint32_t scancode, uint16_t keycode, int has_scan, int has_key)
-{
-        const char *keyname;
-
-        /* ignore key release events */
-        if (has_key == 1)
-                return;
-
-        if (has_key == 0 && has_scan != 0) {
-                fprintf(stderr, "got scan code event 0x%02X without a key code event\n",
-                        scancode);
-                return;
-        }
-
-        if (has_scan != 0)
-                printf("scan code: 0x%02X   ", scancode);
-        else
-                printf("(no scan code received)  ");
-
-        keyname = key_names[keycode];
-        if (keyname != NULL)
-                printf("key code: %s\n", format_keyname(keyname));
-        else
-                printf("key code: %03X\n", keycode);
-}
-
-static void interactive(int fd)
-{
-        struct input_event ev;
-        uint32_t last_scan = 0;
-        uint16_t last_key = 0;
-        int has_scan; /* boolean */
-        int has_key; /* 0: none, 1: release, 2: press */
-
-        /* grab input device */
-        ioctl(fd, EVIOCGRAB, 1);
-        puts("Press ESC to finish, or Control-C if this device is not your primary keyboard");
-
-        has_scan = has_key = 0;
-        while (read_event(fd, &ev)) {
-                /* Drivers usually send the scan code first, then the key code,
-                 * then a SYN. Some drivers (like thinkpad_acpi) send the key
-                 * code first, and some drivers might not send SYN events, so
-                 * keep a robust state machine which can deal with any of those
-                 */
-
-                if (ev.type == EV_MSC && ev.code == MSC_SCAN) {
-                        if (has_scan) {
-                                fputs("driver did not send SYN event in between key events; previous event:\n",
-                                      stderr);
-                                print_key(last_scan, last_key, has_scan, has_key);
-                                has_key = 0;
-                        }
-
-                        last_scan = ev.value;
-                        has_scan = 1;
-                        /*printf("--- got scan %u; has scan %i key %i\n", last_scan, has_scan, has_key); */
-                }
-                else if (ev.type == EV_KEY) {
-                        if (has_key) {
-                                fputs("driver did not send SYN event in between key events; previous event:\n",
-                                      stderr);
-                                print_key(last_scan, last_key, has_scan, has_key);
-                                has_scan = 0;
-                        }
-
-                        last_key = ev.code;
-                        has_key = 1 + ev.value;
-                        /*printf("--- got key %hu; has scan %i key %i\n", last_key, has_scan, has_key);*/
-
-                        /* Stop on ESC */
-                        if (ev.code == KEY_ESC && ev.value == 0)
-                                break;
-                }
-                else if (ev.type == EV_SYN) {
-                        /*printf("--- got SYN; has scan %i key %i\n", has_scan, has_key);*/
-                        print_key(last_scan, last_key, has_scan, has_key);
-
-                        has_scan = has_key = 0;
-                }
-
-        }
-
-        /* release input device */
-        ioctl(fd, EVIOCGRAB, 0);
-}
-
-static void help(int error)
-{
-        const char* h = "Usage: keymap <event device> [<map file>]\n"
-                        "       keymap <event device> scancode keyname [...]\n"
-                        "       keymap -i <event device>\n";
-        if (error) {
-                fputs(h, stderr);
-                exit(2);
-        } else {
-                fputs(h, stdout);
-                exit(0);
-        }
-}
-
-int main(int argc, char **argv)
-{
-        static const struct option options[] = {
-                { "help", no_argument, NULL, 'h' },
-                { "interactive", no_argument, NULL, 'i' },
-                {}
-        };
-        int fd = -1;
-        int opt_interactive = 0;
-        int i;
-
-        while (1) {
-                int option;
-
-                option = getopt_long(argc, argv, "hi", options, NULL);
-                if (option == -1)
-                        break;
-
-                switch (option) {
-                case 'h':
-                        help(0);
-
-                case 'i':
-                        opt_interactive = 1;
-                        break;
-                default:
-                        return 1;
-                }
-        }
-
-        if (argc < optind+1)
-                help (1);
-
-        if ((fd = evdev_open(argv[optind])) < 0)
-                return 3;
-
-        /* one argument (device): dump or interactive */
-        if (argc == optind+1) {
-                if (opt_interactive)
-                        interactive(fd);
-                else
-                        dump_table(fd);
-                return 0;
-        }
-
-        /* two arguments (device, mapfile): set map file */
-        if (argc == optind+2) {
-                const char *filearg = argv[optind+1];
-                if (strchr(filearg, '/')) {
-                        /* Keymap file argument is a path */
-                        FILE *f = fopen(filearg, "r");
-                        if (f)
-                                merge_table(fd, f);
-                        else
-                                perror(filearg);
-                } else {
-                        /* Keymap file argument is a filename */
-                        /* Open override file if present, otherwise default file */
-                        char keymap_path[PATH_MAX];
-                        snprintf(keymap_path, sizeof(keymap_path), "%s%s", SYSCONFDIR "/udev/keymaps/", filearg);
-                        FILE *f = fopen(keymap_path, "r");
-                        if (f) {
-                                merge_table(fd, f);
-                        } else {
-                                snprintf(keymap_path, sizeof(keymap_path), "%s%s", PKGLIBEXECDIR "/keymaps/", filearg);
-                                f = fopen(keymap_path, "r");
-                                if (f)
-                                        merge_table(fd, f);
-                                else
-                                        perror(keymap_path);
-                        }
-                }
-                return 0;
-        }
-
-        /* more arguments (device, scancode/keyname pairs): set keys directly */
-        if ((argc - optind - 1) % 2 == 0) {
-                for (i = optind+1; i < argc; i += 2)
-                        set_key(fd, argv[i], argv[i+1]);
-                return 0;
-        }
-
-        /* invalid number of arguments */
-        help(1);
-        return 1; /* not reached */
-}
diff --git a/src/udev/src/keymap/keymaps/acer b/src/udev/src/keymap/keymaps/acer
deleted file mode 100644 (file)
index 4e7c297..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-0xA5 help # Fn+F1
-0xA6 setup # Fn+F2 Acer eSettings
-0xA7 battery # Fn+F3 Power Management
-0xA9 switchvideomode # Fn+F5
-0xB3 euro
-0xB4 dollar
-0xCE brightnessup # Fn+Right
-0xD4 bluetooth # (toggle) off-to-on
-0xD5 wlan # (toggle) on-to-off
-0xD6 wlan # (toggle) off-to-on
-0xD7 bluetooth # (toggle) on-to-off
-0xD8 bluetooth # (toggle) off-to-on
-0xD9 brightnessup # Fn+Right
-0xEE brightnessup # Fn+Right
-0xEF brightnessdown # Fn+Left
-0xF1 f22 # Fn+F7 Touchpad toggle (off-to-on)
-0xF2 f23 # Fn+F7 Touchpad toggle (on-to-off)
-0xF3 prog2 # "P2" programmable button
-0xF4 prog1 # "P1" programmable button
-0xF5 presentation
-0xF8 fn
-0xF9 f23 # Launch NTI shadow
diff --git a/src/udev/src/keymap/keymaps/acer-aspire_5720 b/src/udev/src/keymap/keymaps/acer-aspire_5720
deleted file mode 100644 (file)
index 1496d63..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-0x84 bluetooth  # sent when bluetooth module missing, and key pressed
-0x92 media      # acer arcade
-0xD4 bluetooth  # bluetooth on
-0xD9 bluetooth  # bluetooth off
diff --git a/src/udev/src/keymap/keymaps/acer-aspire_5920g b/src/udev/src/keymap/keymaps/acer-aspire_5920g
deleted file mode 100644 (file)
index 633c4e8..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-0x8A media
-0x92 media
-0xA6 setup
-0xB2 www
-0xD9 bluetooth # (toggle) on-to-off
diff --git a/src/udev/src/keymap/keymaps/acer-aspire_6920 b/src/udev/src/keymap/keymaps/acer-aspire_6920
deleted file mode 100644 (file)
index 699c954..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-0xD9 bluetooth # (toggle) on-to-off
-0x92 media
-0x9E back
-0x83 rewind
-0x89 fastforward
diff --git a/src/udev/src/keymap/keymaps/acer-aspire_8930 b/src/udev/src/keymap/keymaps/acer-aspire_8930
deleted file mode 100644 (file)
index fb27bfb..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-0xCA prog3        # key 'HOLD' on cine dash media console
-0x83 rewind
-0x89 fastforward
-0x92 media        # key 'ARCADE' on cine dash media console
-0x9E back
diff --git a/src/udev/src/keymap/keymaps/acer-travelmate_c300 b/src/udev/src/keymap/keymaps/acer-travelmate_c300
deleted file mode 100644 (file)
index bfef4cf..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-0x67 f24 # FIXME: rotate screen
-0x68 up
-0x69 down
-0x6B fn
-0x6C screenlock # FIXME: lock tablet device/buttons
diff --git a/src/udev/src/keymap/keymaps/asus b/src/udev/src/keymap/keymaps/asus
deleted file mode 100644 (file)
index 2a5995f..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-0xED volumeup
-0xEE volumedown
-0xEF mute
diff --git a/src/udev/src/keymap/keymaps/compaq-e_evo b/src/udev/src/keymap/keymaps/compaq-e_evo
deleted file mode 100644 (file)
index 5fbc573..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-0xA3 www # I key
-0x9A search
-0x9E email
-0x9F homepage
diff --git a/src/udev/src/keymap/keymaps/dell b/src/udev/src/keymap/keymaps/dell
deleted file mode 100644 (file)
index 4f907b3..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-0x81 playpause # Play/Pause
-0x82 stopcd # Stop
-0x83 previoussong # Previous song
-0x84 nextsong # Next song
-0x85 brightnessdown # Fn+Down arrow Brightness Down
-0x86 brightnessup # Fn+Up arrow Brightness Up
-0x87 battery # Fn+F3 battery icon
-0x88 unknown # Fn+F2 Turn On/Off Wireless - handled in hardware
-0x89 ejectclosecd # Fn+F10 Eject CD
-0x8A suspend # Fn+F1 hibernate
-0x8B switchvideomode # Fn+F8 CRT/LCD (high keycode: "displaytoggle")
-0x8C f23 # Fn+Right arrow Auto Brightness
-0x8F switchvideomode # Fn+F7 aspect ratio
-0x90 previoussong # Front panel previous song
-0x91 prog1 # Wifi Catcher (DELL Specific)
-0x92 media # MediaDirect button (house icon)
-0x93 f23 # FIXME Fn+Left arrow Auto Brightness
-0x95 camera # Shutter button Takes a picture if optional camera available
-0x97 email # Tablet email button
-0x98 f21 # FIXME: Tablet screen rotatation
-0x99 nextsong # Front panel next song
-0x9A setup # Tablet tools button
-0x9B switchvideomode # Display Toggle button
-0x9E f21 #touchpad toggle
-0xA2 playpause # Front panel play/pause
-0xA4 stopcd # Front panel stop
-0xED media # MediaDirect button
-0xD8 screenlock # FIXME: Tablet lock button
-0xD9 f21 # touchpad toggle
diff --git a/src/udev/src/keymap/keymaps/dell-latitude-xt2 b/src/udev/src/keymap/keymaps/dell-latitude-xt2
deleted file mode 100644 (file)
index 39872f5..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-0x9B up # tablet rocker up
-0x9E enter # tablet rocker press
-0x9F back # tablet back
-0xA3 down # tablet rocker down
diff --git a/src/udev/src/keymap/keymaps/everex-xt5000 b/src/udev/src/keymap/keymaps/everex-xt5000
deleted file mode 100644 (file)
index 4823a83..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-0x5C media
-0x65 f21 # Fn+F5 Touchpad toggle
-0x67 prog3 # Fan Speed Control button
-0x6F brightnessup
-0x7F brightnessdown
-0xB2 www
-0xEC mail
diff --git a/src/udev/src/keymap/keymaps/fujitsu-amilo_li_2732 b/src/udev/src/keymap/keymaps/fujitsu-amilo_li_2732
deleted file mode 100644 (file)
index 9b8b36a..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-0xD9 brightnessdown # Fn+F8 brightness down
-0xEF brightnessup # Fn+F9 brightness up
-0xA9 switchvideomode # Fn+F10 Cycle between available video outputs
diff --git a/src/udev/src/keymap/keymaps/fujitsu-amilo_pa_2548 b/src/udev/src/keymap/keymaps/fujitsu-amilo_pa_2548
deleted file mode 100644 (file)
index f7b0c52..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-0xE0 volumedown
-0xE1 volumeup
-0xE5 prog1
diff --git a/src/udev/src/keymap/keymaps/fujitsu-amilo_pro_edition_v3505 b/src/udev/src/keymap/keymaps/fujitsu-amilo_pro_edition_v3505
deleted file mode 100644 (file)
index d2e38cb..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-0xA5 help # Fn-F1
-0xA9 switchvideomode # Fn-F3
-0xD9 brightnessdown # Fn-F8
-0xE0 brightnessup # Fn-F9
diff --git a/src/udev/src/keymap/keymaps/fujitsu-amilo_pro_v3205 b/src/udev/src/keymap/keymaps/fujitsu-amilo_pro_v3205
deleted file mode 100644 (file)
index 43e3199..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-0xF4 f21 # FIXME: silent-mode decrease CPU/GPU clock
-0xF7 switchvideomode # Fn+F3
diff --git a/src/udev/src/keymap/keymaps/fujitsu-amilo_si_1520 b/src/udev/src/keymap/keymaps/fujitsu-amilo_si_1520
deleted file mode 100644 (file)
index 1419bd9..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-0xE1 wlan
-0xF3 wlan
-0xEE brightnessdown
-0xE0 brightnessup
-0xE2 bluetooth
-0xF7 video
diff --git a/src/udev/src/keymap/keymaps/fujitsu-esprimo_mobile_v5 b/src/udev/src/keymap/keymaps/fujitsu-esprimo_mobile_v5
deleted file mode 100644 (file)
index d3d056b..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-0xA9 switchvideomode
-0xD9 brightnessdown
-0xDF sleep
-0xEF brightnessup
diff --git a/src/udev/src/keymap/keymaps/fujitsu-esprimo_mobile_v6 b/src/udev/src/keymap/keymaps/fujitsu-esprimo_mobile_v6
deleted file mode 100644 (file)
index 52c70c5..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-0xCE brightnessup
-0xEF brightnessdown
diff --git a/src/udev/src/keymap/keymaps/genius-slimstar-320 b/src/udev/src/keymap/keymaps/genius-slimstar-320
deleted file mode 100644 (file)
index d0a3656..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-# Genius SlimStar 320
-#
-# Only buttons which are not properly mapped yet are configured below
-
-# "Scroll wheel", a circular up/down/left/right button. Aimed for scolling,
-# but since there are no scrollleft/scrollright, let's map to back/forward.
-0x900f0 scrollup
-0x900f1 scrolldown
-0x900f3 back
-0x900f2 forward
-
-# Multimedia buttons, left side (from left to right)
-# [W]
-0x900f5 wordprocessor
-# [Ex]
-0x900f6 spreadsheet
-# [P]
-0x900f4 presentation
-# Other five (calculator, playpause, stop, mute and eject) are OK
-
-# Right side, from left to right
-# [e]
-0xc0223 www
-# "man"
-0x900f7 chat
-# "Y"
-0x900fb prog1
-# [X]
-0x900f8 close
-# "picture"
-0x900f9 graphicseditor
-# "two windows"
-0x900fd scale
-# "lock"
-0x900fc screenlock
diff --git a/src/udev/src/keymap/keymaps/hewlett-packard b/src/udev/src/keymap/keymaps/hewlett-packard
deleted file mode 100644 (file)
index 4461fa2..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-0x81 fn_esc
-0x89 battery # FnF8
-0x8A screenlock # FnF6
-0x8B camera
-0x8C media # music
-0x8E dvd
-0xB1 help
-0xB3 f23 # FIXME: Auto brightness
-0xD7 wlan
-0x92 brightnessdown # FnF7 (FnF9 on 6730b)
-0x97 brightnessup # FnF8 (FnF10 on 6730b)
-0xEE switchvideomode # FnF4
diff --git a/src/udev/src/keymap/keymaps/hewlett-packard-2510p_2530p b/src/udev/src/keymap/keymaps/hewlett-packard-2510p_2530p
deleted file mode 100644 (file)
index 41ad2e9..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-0xD8 f23 # touchpad off
-0xD9 f22 # touchpad on
diff --git a/src/udev/src/keymap/keymaps/hewlett-packard-compaq_elitebook b/src/udev/src/keymap/keymaps/hewlett-packard-compaq_elitebook
deleted file mode 100644 (file)
index 42007c5..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-0x88 presentation
-0xD9 help # I key (high keycode: "info")
diff --git a/src/udev/src/keymap/keymaps/hewlett-packard-pavilion b/src/udev/src/keymap/keymaps/hewlett-packard-pavilion
deleted file mode 100644 (file)
index 3d3cefc..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-0x88 media # FIXME: quick play
-0xD8 f23 # touchpad off
-0xD9 f22 # touchpad on
diff --git a/src/udev/src/keymap/keymaps/hewlett-packard-presario-2100 b/src/udev/src/keymap/keymaps/hewlett-packard-presario-2100
deleted file mode 100644 (file)
index 1df39dc..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-0xF0 help
-0xF1 screenlock
-0xF3 search
diff --git a/src/udev/src/keymap/keymaps/hewlett-packard-tablet b/src/udev/src/keymap/keymaps/hewlett-packard-tablet
deleted file mode 100644 (file)
index d19005a..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-0x82 prog2 # Funny Key
-0x83 prog1 # Q
-0x84 tab
-0x85 esc
-0x86 pageup
-0x87 pagedown
diff --git a/src/udev/src/keymap/keymaps/hewlett-packard-tx2 b/src/udev/src/keymap/keymaps/hewlett-packard-tx2
deleted file mode 100644 (file)
index 36a690f..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-0xC2 media
-0xD8 f23 # Toggle touchpad button on tx2 (OFF)
-0xD9 f22 # Toggle touchpad button on tx2 (ON)
diff --git a/src/udev/src/keymap/keymaps/ibm-thinkpad-usb-keyboard-trackpoint b/src/udev/src/keymap/keymaps/ibm-thinkpad-usb-keyboard-trackpoint
deleted file mode 100644 (file)
index 027e50b..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-0x900f0 screenlock
-0x900f1 wlan
-0x900f2 switchvideomode
-0x900f3 suspend
-0x900f4 brightnessup
-0x900f5 brightnessdown
-0x900f8 zoom
diff --git a/src/udev/src/keymap/keymaps/inventec-symphony_6.0_7.0 b/src/udev/src/keymap/keymaps/inventec-symphony_6.0_7.0
deleted file mode 100644 (file)
index 4a8b4ba..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-0xF3 prog2
-0xF4 prog1
diff --git a/src/udev/src/keymap/keymaps/lenovo-3000 b/src/udev/src/keymap/keymaps/lenovo-3000
deleted file mode 100644 (file)
index 5bd1656..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-0x8B switchvideomode # Fn+F7 video
-0x96 wlan # Fn+F5 wireless
-0x97 sleep # Fn+F4 suspend
-0x98 suspend # Fn+F12 hibernate
-0xB4 prog1 # Lenovo Care
diff --git a/src/udev/src/keymap/keymaps/lenovo-ideapad b/src/udev/src/keymap/keymaps/lenovo-ideapad
deleted file mode 100644 (file)
index fc33983..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-# Key codes observed on S10-3, assumed valid on other IdeaPad models
-0x81 rfkill             # does nothing in BIOS
-0x83 display_off        # BIOS toggles screen state
-0xB9 brightnessup       # does nothing in BIOS
-0xBA brightnessdown     # does nothing in BIOS
-0xF1 camera             # BIOS toggles camera power
-0xf2 f21                # touchpad toggle (key alternately emits f2 and f3)
-0xf3 f21
diff --git a/src/udev/src/keymap/keymaps/lenovo-thinkpad-usb-keyboard-trackpoint b/src/udev/src/keymap/keymaps/lenovo-thinkpad-usb-keyboard-trackpoint
deleted file mode 100644 (file)
index 47e8846..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-0x90012 screenlock # Fn+F2
-0x90013 battery # Fn+F3
-0x90014 wlan # Fn+F5
-0x90016 switchvideomode # Fn+F7
-0x90017 f21 # Fn+F8  touchpadtoggle
-0x90019 suspend # Fn+F12
-0x9001A brightnessup # Fn+Home
-0x9001B brightnessdown # Fn+End
-0x9001D zoom # Fn+Space
-0x90011 prog1 # Thinkvantage button
-
-0x90015 camera # Fn+F6 headset/camera VoIP key  ??
-0x90010 micmute # Microphone mute button
diff --git a/src/udev/src/keymap/keymaps/lenovo-thinkpad_x200_tablet b/src/udev/src/keymap/keymaps/lenovo-thinkpad_x200_tablet
deleted file mode 100644 (file)
index 31ea3b2..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-0x5D menu
-0x63 fn
-0x66 screenlock
-0x67 cyclewindows # bezel circular arrow
-0x68 setup # bezel setup / menu
-0x6c direction # rotate screen
diff --git a/src/udev/src/keymap/keymaps/lenovo-thinkpad_x6_tablet b/src/udev/src/keymap/keymaps/lenovo-thinkpad_x6_tablet
deleted file mode 100644 (file)
index 6fd16b5..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-0x6C f21 # rotate
-0x68 screenlock # screenlock
-0x6B esc # escape
-0x6D right # right on d-pad
-0x6E left # left on d-pad
-0x71 up # up on d-pad
-0x6F down # down on d-pad
-0x69 enter # enter on d-pad
diff --git a/src/udev/src/keymap/keymaps/lg-x110 b/src/udev/src/keymap/keymaps/lg-x110
deleted file mode 100644 (file)
index ba08cba..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-0xA0 mute # Fn-F9
-0xAE volumedown # Fn-Left
-0xAF search # Fn-F3
-0xB0 volumeup # Fn-Right
-0xB1 battery # Fn-F10 Info
-0xB3 suspend # Fn-F12
-0xDF sleep # Fn-F4
-# 0xE2 bluetooth # satellite dish2
-0xE4 f21 # Fn-F5   Touchpad disable
-0xF6 wlan # Fn-F6
-0xF7 reserved # brightnessdown # Fn-Down
-0xF8 reserved # brightnessup # Fn-Up
diff --git a/src/udev/src/keymap/keymaps/logitech-wave b/src/udev/src/keymap/keymaps/logitech-wave
deleted file mode 100644 (file)
index caa5d5d..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-0x9001C scale #expo
-0x9001F zoomout #zoom out
-0x90020 zoomin #zoom in
-0x9003D prog1 #gadget
-0x90005 camera #camera
-0x90018 media #media center
-0x90041 wordprocessor #fn+f1 (word)
-0x90042 spreadsheet #fn+f2 (excel)
-0x90043 calendar #fn+f3 (calendar)
-0x90044 prog2 #fn+f4 (program a)
-0x90045 prog3 #fn+f5 (program b)
-0x90046 prog4 #fn+f6 (program c)
-0x90048 messenger #fn+f8 (msn messenger)
-0x9002D find #fn+f10 (search www)
-0x9004B search #fn+f11 (search pc)
-0x9004C ejectclosecd #fn+f12 (eject)
diff --git a/src/udev/src/keymap/keymaps/logitech-wave-cordless b/src/udev/src/keymap/keymaps/logitech-wave-cordless
deleted file mode 100644 (file)
index a10dad5..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-0xD4 zoomin
-0xCC zoomout
-0xC0183 media
-0xC1005 camera
-0xC101F zoomout
-0xC1020 zoomin
-0xC1041 wordprocessor
-0xC1042 spreadsheet
-0xC1043 calendar
-0xC1044 prog2 #fn+f4 (program a)
-0xC1045 prog3 #fn+f5 (program b)
-0xC1046 prog4 #fn+f6 (program c)
-0xC1048 messenger
-0xC104A find #fn+f10 (search www)
-0xC104C ejectclosecd
diff --git a/src/udev/src/keymap/keymaps/logitech-wave-pro-cordless b/src/udev/src/keymap/keymaps/logitech-wave-pro-cordless
deleted file mode 100644 (file)
index e7aa022..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-0xC01B6 camera
-0xC0183 media
-0xC0184 wordprocessor
-0xC0186 spreadsheet
-0xC018E calendar
-0xC0223 homepage
-0xC01BC messenger
-0xC018A mail
-0xC0221 search
-0xC00B8 ejectcd
-0xC022D zoomin
-0xC022E zoomout
diff --git a/src/udev/src/keymap/keymaps/maxdata-pro_7000 b/src/udev/src/keymap/keymaps/maxdata-pro_7000
deleted file mode 100644 (file)
index c0e4f77..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-0x97 prog2
-0x9F prog1
-0xA0 mute # Fn-F5
-0x82 www
-0xEC email
-0xAE volumedown # Fn-Down
-0xB0 volumeup # Fn-Up
-0xDF suspend # Fn+F2
-0xF5 help
diff --git a/src/udev/src/keymap/keymaps/medion-fid2060 b/src/udev/src/keymap/keymaps/medion-fid2060
deleted file mode 100644 (file)
index 5a76c76..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-0x6B channeldown # Thottle Down
-0x6D channelup # Thottle Up
diff --git a/src/udev/src/keymap/keymaps/medionnb-a555 b/src/udev/src/keymap/keymaps/medionnb-a555
deleted file mode 100644 (file)
index c3b5dfa..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-0x63 www # N button
-0x66 prog1 # link 1 button
-0x67 email # envelope button
-0x69 prog2 # link 2 button
diff --git a/src/udev/src/keymap/keymaps/micro-star b/src/udev/src/keymap/keymaps/micro-star
deleted file mode 100644 (file)
index 4a43869..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-0xA0 mute # Fn-F9
-0xAE volumedown # Fn-F7
-0xB0 volumeup # Fn-F8
-0xB2 www # e button
-0xDF sleep # Fn-F12
-0xE2 bluetooth # satellite dish2
-0xE4 f21 # Fn-F3   Touchpad disable
-0xEC email # envelope button
-0xEE camera # Fn-F6 camera disable
-0xF6 wlan # satellite dish1
-0xF7 brightnessdown # Fn-F4
-0xF8 brightnessup # Fn-F5
-0xF9 search
diff --git a/src/udev/src/keymap/keymaps/module-asus-w3j b/src/udev/src/keymap/keymaps/module-asus-w3j
deleted file mode 100644 (file)
index 773e0b3..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-0x41 nextsong
-0x45 playpause
-0x43 stopcd
-0x40 previoussong
-0x4C ejectclosecd
-0x32 mute
-0x31 volumedown
-0x30 volumeup
-0x5D wlan
-0x7E bluetooth
-0x8A media # high keycode: "tv"
diff --git a/src/udev/src/keymap/keymaps/module-ibm b/src/udev/src/keymap/keymaps/module-ibm
deleted file mode 100644 (file)
index a92dfa2..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-0x01 battery # Fn+F2
-0x02 screenlock # Fn+F3
-0x03 sleep # Fn+F4
-0x04 wlan # Fn+F5
-0x06 switchvideomode # Fn+F7
-0x07 zoom # Fn+F8 screen expand
-0x08 f24 # Fn+F9 undock
-0x0B suspend # Fn+F12
-0x0F brightnessup # Fn+Home
-0x10 brightnessdown # Fn+End
-0x11 kbdillumtoggle # Fn+PgUp - ThinkLight
-0x13 zoom # Fn+Space
-0x14 volumeup
-0x15 volumedown
-0x16 mute
-0x17 prog1 # ThinkPad/ThinkVantage button  (high keycode: "vendor")
diff --git a/src/udev/src/keymap/keymaps/module-lenovo b/src/udev/src/keymap/keymaps/module-lenovo
deleted file mode 100644 (file)
index 8e38883..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-0x1 screenlock # Fn+F2
-0x2 battery # Fn+F3
-0x3 sleep # Fn+F4
-0x4 wlan # Fn+F5
-0x6 switchvideomode # Fn+F7
-0x7 f21 # Fn+F8 touchpadtoggle
-0x8 f24 # Fn+F9 undock
-0xB suspend # Fn+F12
-0xF brightnessup # Fn+Home
-0x10 brightnessdown # Fn+End
-0x11 kbdillumtoggle # Fn+PgUp - ThinkLight
-0x13 zoom # Fn+Space
-0x14 volumeup
-0x15 volumedown
-0x16 mute
-0x17 prog1 # ThinkPad/ThinkVantage button (high keycode: "vendor")
-0x1A micmute # Microphone mute
diff --git a/src/udev/src/keymap/keymaps/module-sony b/src/udev/src/keymap/keymaps/module-sony
deleted file mode 100644 (file)
index 7c00013..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-0x06 mute # Fn+F2
-0x07 volumedown # Fn+F3
-0x08 volumeup # Fn+F4
-0x09 brightnessdown # Fn+F5
-0x0A brightnessup # Fn+F6
-0x0B switchvideomode # Fn+F7
-0x0E zoom # Fn+F10
-0x10 suspend # Fn+F12
diff --git a/src/udev/src/keymap/keymaps/module-sony-old b/src/udev/src/keymap/keymaps/module-sony-old
deleted file mode 100644 (file)
index 596a342..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-0x06 battery
-0x07 mute
diff --git a/src/udev/src/keymap/keymaps/module-sony-vgn b/src/udev/src/keymap/keymaps/module-sony-vgn
deleted file mode 100644 (file)
index c8ba001..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-0x00 brightnessdown # Fn+F5
-0x10 brightnessup # Fn+F6
-0x11 switchvideomode # Fn+F7
-0x12 zoomout
-0x14 zoomin
-0x15 suspend # Fn+F12
-0x17 prog1
-0x20 media
diff --git a/src/udev/src/keymap/keymaps/olpc-xo b/src/udev/src/keymap/keymaps/olpc-xo
deleted file mode 100644 (file)
index 34434a1..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-0x59 fn
-0x81 fn_esc
-0xF9 camera
-0xF8 sound # Fn-CAMERA = Mic
-
-
-# Function key mappings, as per
-#    http://dev.laptop.org/ticket/10213#comment:20
-#
-# Unmodified F1-F8 produce F1-F8, so no remap necessary.
-# Unmodified F9-F12 control brightness and volume.
-0x43 brightnessdown
-0x44 brightnessup
-0x57 volumedown
-0x58 volumeup
-
-# fn-modified fkeys all produce the unmodified version of the key.
-0xBB f1
-0xBC f2
-0xBD f3
-0xBE f4
-0xBF f5
-0xC0 f6
-0xC1 f7
-0xC2 f8
-0xC3 f9
-0xC4 f10
-0xD7 f11
-0xD8 f12
-
-
-# Using F13-F21 for the .5 F keys right now.
-0xF7 f13
-0xF6 f14
-0xF5 f15
-0xF4 f16
-0xF3 f17
-0xF2 f18
-0xF1 f19
-0xF0 f20
-0xEF f21
-
-0xEE chat
-0xE4 chat # Just mapping Fn-Chat to Chat for now
-0xDD menu # Frame
-0xDA prog1 # Fn-Frame
-
-# The FN of some keys is other keys
-0xD3 delete
-0xD2 insert
-0xC9 pageup
-0xD1 pagedown
-0xC7 home
-0xCF end
-
-# Language key - don't ask what they are doing as KEY_HP
-0x73 hp
-0x7E hp
-
-0xDB leftmeta # left grab
-0xDC rightmeta # right grab
-0x85 rightmeta # Right grab releases on a different scancode
-0xD6 kbdillumtoggle # Fn-space
-0x69 switchvideomode # Brightness key
-
-# Game keys
-0x65 kp8 # up
-0x66 kp2 # down
-0x67 kp4 # left
-0x68 kp6 # right
-0xE5 kp9 # pgup
-0xE6 kp3 # pgdn
-0xE7 kp7 # home
-0xE8 kp1 # end
diff --git a/src/udev/src/keymap/keymaps/onkyo b/src/udev/src/keymap/keymaps/onkyo
deleted file mode 100644 (file)
index ee864ad..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-0xA0 mute # Fn+D
-0xAE volumedown # Fn+F
-0xB0 volumeup # Fn+G
-0xDF sleep # Fn+W
-0xE0 bluetooth # Fn+H
-0xE2 cyclewindows # Fn+Esc
-0xEE battery # Fn+Q
-0xF0 media # Fn+R
-0xF5 switchvideomode # Fn+E
-0xF6 camera # Fn+T
-0xF7 f21 # Fn+Y (touchpad toggle)
-0xF8 brightnessup # Fn+S
-0xF9 brightnessdown # Fn+A
-0xFB wlan # Fn+J
diff --git a/src/udev/src/keymap/keymaps/oqo-model2 b/src/udev/src/keymap/keymaps/oqo-model2
deleted file mode 100644 (file)
index b7f4851..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-0x8E wlan
-0xF0 switchvideomode
-0xF1 mute
-0xF2 volumedown
-0xF3 volumeup
diff --git a/src/udev/src/keymap/keymaps/samsung-90x3a b/src/udev/src/keymap/keymaps/samsung-90x3a
deleted file mode 100644 (file)
index 8b65eb6..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-0x96 kbdillumup         # Fn+F8 keyboard backlit up
-0x97 kbdillumdown       # Fn+F7 keyboard backlit down
-0xD5 wlan               # Fn+F12 wifi on/off
-0xCE prog1              # Fn+F1 performance mode
-0x8D prog2              # Fn+F6 battery life extender
diff --git a/src/udev/src/keymap/keymaps/samsung-other b/src/udev/src/keymap/keymaps/samsung-other
deleted file mode 100644 (file)
index 3ac0c2f..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-0x74 prog1 # User key
-0x75 www
-0x78 mail
-0x82 switchvideomode # Fn+F4 CRT/LCD (high keycode: "displaytoggle")
-0x83 battery # Fn+F2
-0x84 prog1 # Fn+F5 backlight on/off
-0x86 wlan # Fn+F9
-0x88 brightnessup # Fn-Up
-0x89 brightnessdown # Fn-Down
-0xB1 prog2 # Fn+F7 run Samsung Magic Doctor (keypressed event is generated twice)
-0xB3 prog3 # Fn+F8 switch power mode (battery/dynamic/performance)
-0xB4 wlan # Fn+F9 (X60P)
-0xF7 f22 # Fn+F10 Touchpad on
-0xF9 f23 # Fn+F10 Touchpad off
diff --git a/src/udev/src/keymap/keymaps/samsung-sq1us b/src/udev/src/keymap/keymaps/samsung-sq1us
deleted file mode 100644 (file)
index ea2141e..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-0xD4 menu
-0xD8 f1
-0xD9 f10
-0xD6 f3
-0xD7 f9
-0xE4 f5
-0xEE f11
diff --git a/src/udev/src/keymap/keymaps/samsung-sx20s b/src/udev/src/keymap/keymaps/samsung-sx20s
deleted file mode 100644 (file)
index 9d954ee..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-0x74 mute
-0x75 mute
-0x77 f22 # Touchpad on
-0x79 f23 # Touchpad off
diff --git a/src/udev/src/keymap/keymaps/toshiba-satellite_a100 b/src/udev/src/keymap/keymaps/toshiba-satellite_a100
deleted file mode 100644 (file)
index 22007be..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-0xA4 stopcd
-0xB2 www
diff --git a/src/udev/src/keymap/keymaps/toshiba-satellite_a110 b/src/udev/src/keymap/keymaps/toshiba-satellite_a110
deleted file mode 100644 (file)
index 1429409..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-0x92 stop
-0x93 www
-0x94 media
-0x9E f22 # Touchpad on
-0x9F f23 # Touchpad off
-0xB9 nextsong
-0xD9 brightnessup
-0xEE screenlock
-0xF4 previoussong
-0xF7 playpause
diff --git a/src/udev/src/keymap/keymaps/toshiba-satellite_m30x b/src/udev/src/keymap/keymaps/toshiba-satellite_m30x
deleted file mode 100644 (file)
index ae8e349..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-0xef brightnessdown
-0xd9 brightnessup
-0xee screenlock
-0x93 media
-0x9e f22 #touchpad_enable
-0x9f f23 #touchpad_disable
diff --git a/src/udev/src/keymap/keymaps/zepto-znote b/src/udev/src/keymap/keymaps/zepto-znote
deleted file mode 100644 (file)
index cf72fda..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-0x93 switchvideomode    # Fn+F3 Toggle Video Output
-0x95 brightnessdown     # Fn+F4 Brightness Down
-0x91 brightnessup       # Fn+F5 Brightness Up
-0xA5 f23                # Fn+F6 Disable Touchpad
-0xA6 f22                # Fn+F6 Enable Touchpad
-0xA7 bluetooth          # Fn+F10 Enable Bluetooth
-0XA9 bluetooth          # Fn+F10 Disable Bluetooth
-0xF1 wlan               # RF Switch Off
-0xF2 wlan               # RF Switch On
-0xF4 prog1              # P1 Button
-0xF3 prog2              # P2 Button
diff --git a/src/udev/src/libudev-device-private.c b/src/udev/src/libudev-device-private.c
deleted file mode 100644 (file)
index 13fdb8e..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.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.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/stat.h>
-
-#include "libudev.h"
-#include "libudev-private.h"
-
-static void udev_device_tag(struct udev_device *dev, const char *tag, bool add)
-{
-        const char *id;
-        struct udev *udev = udev_device_get_udev(dev);
-        char filename[UTIL_PATH_SIZE];
-
-        id = udev_device_get_id_filename(dev);
-        if (id == NULL)
-                return;
-        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/tags/", tag, "/", id, NULL);
-
-        if (add) {
-                int fd;
-
-                util_create_path(udev, filename);
-                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 (strcmp(tag, tag_old) == 0) {
-                                        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)
-{
-        bool has_info;
-        const char *id;
-        struct udev *udev = udev_device_get_udev(udev_device);
-        char filename[UTIL_PATH_SIZE];
-        char filename_tmp[UTIL_PATH_SIZE];
-        FILE *f;
-
-        id = udev_device_get_id_filename(udev_device);
-        if (id == NULL)
-                return -1;
-
-        has_info = device_has_info(udev_device);
-        util_strscpyl(filename, sizeof(filename), udev_get_run_path(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 */
-        util_strscpyl(filename_tmp, sizeof(filename_tmp), filename, ".tmp", NULL);
-        util_create_path(udev, filename_tmp);
-        f = fopen(filename_tmp, "we");
-        if (f == NULL) {
-                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) {
-                        size_t devlen = strlen(udev_get_dev_path(udev))+1;
-
-                        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)[devlen]);
-                        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", 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);
-        rename(filename_tmp, filename);
-        info(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;
-        struct udev *udev = udev_device_get_udev(udev_device);
-        char filename[UTIL_PATH_SIZE];
-
-        id = udev_device_get_id_filename(udev_device);
-        if (id == NULL)
-                return -1;
-        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/data/", id, NULL);
-        unlink(filename);
-        return 0;
-}
diff --git a/src/udev/src/libudev-device.c b/src/udev/src/libudev-device.c
deleted file mode 100644 (file)
index 10f28b8..0000000
+++ /dev/null
@@ -1,1744 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.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.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <stdbool.h>
-#include <errno.h>
-#include <string.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <net/if.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <linux/sockios.h>
-
-#include "libudev.h"
-#include "libudev-private.h"
-
-/**
- * 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 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;
-        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;
-        unsigned long long int 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.
- **/
-UDEV_EXPORT 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
- *
- * Returns: the device major/minor number.
- **/
-UDEV_EXPORT 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
- *
- * Returns: the driver string, or #NULL if there is no driver attached.
- **/
-UDEV_EXPORT 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
- **/
-UDEV_EXPORT 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;
-}
-
-static 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
- **/
-UDEV_EXPORT 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 (strncmp(udev_device->devpath, "/module/", 8) == 0) {
-                        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 (strncmp(udev_device->devpath, "/subsystem/", 11) == 0 ||
-                    strncmp(udev_device->devpath, "/class/", 7) == 0 ||
-                    strncmp(udev_device->devpath, "/bus/", 5) == 0) {
-                        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;
-}
-
-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;
-
-        util_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 (strncmp(property, "DEVPATH=", 8) == 0) {
-                char path[UTIL_PATH_SIZE];
-
-                util_strscpyl(path, sizeof(path), udev_get_sys_path(udev_device->udev), &property[8], NULL);
-                udev_device_set_syspath(udev_device, path);
-        } else if (strncmp(property, "SUBSYSTEM=", 10) == 0) {
-                udev_device_set_subsystem(udev_device, &property[10]);
-        } else if (strncmp(property, "DEVTYPE=", 8) == 0) {
-                udev_device_set_devtype(udev_device, &property[8]);
-        } else if (strncmp(property, "DEVNAME=", 8) == 0) {
-                udev_device_set_devnode(udev_device, &property[8]);
-        } else if (strncmp(property, "DEVLINKS=", 9) == 0) {
-                char devlinks[UTIL_PATH_SIZE];
-                char *slink;
-                char *next;
-
-                util_strscpy(devlinks, sizeof(devlinks), &property[9]);
-                slink = devlinks;
-                next = strchr(slink, ' ');
-                while (next != NULL) {
-                        next[0] = '\0';
-                        udev_device_add_devlink(udev_device, slink, 0);
-                        slink = &next[1];
-                        next = strchr(slink, ' ');
-                }
-                if (slink[0] != '\0')
-                        udev_device_add_devlink(udev_device, slink, 0);
-        } else if (strncmp(property, "TAGS=", 5) == 0) {
-                char tags[UTIL_PATH_SIZE];
-                char *next;
-
-                util_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 (strncmp(property, "USEC_INITIALIZED=", 19) == 0) {
-                udev_device_set_usec_initialized(udev_device, strtoull(&property[19], NULL, 10));
-        } else if (strncmp(property, "DRIVER=", 7) == 0) {
-                udev_device_set_driver(udev_device, &property[7]);
-        } else if (strncmp(property, "ACTION=", 7) == 0) {
-                udev_device_set_action(udev_device, &property[7]);
-        } else if (strncmp(property, "MAJOR=", 6) == 0) {
-                udev_device->maj = strtoull(&property[6], NULL, 10);
-        } else if (strncmp(property, "MINOR=", 6) == 0) {
-                udev_device->min = strtoull(&property[6], NULL, 10);
-        } else if (strncmp(property, "DEVPATH_OLD=", 12) == 0) {
-                udev_device_set_devpath_old(udev_device, &property[12]);
-        } else if (strncmp(property, "SEQNUM=", 7) == 0) {
-                udev_device_set_seqnum(udev_device, strtoull(&property[7], NULL, 10));
-        } else if (strncmp(property, "IFINDEX=", 8) == 0) {
-                udev_device_set_ifindex(udev_device, strtoull(&property[8], NULL, 10));
-        } else if (strncmp(property, "DEVMODE=", 8) == 0) {
-                udev_device_set_devnode_mode(udev_device, strtoul(&property[8], NULL, 8));
-        } 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
- *
- * Returns: the value of a device property, or #NULL if there is no such property.
- **/
-UDEV_EXPORT 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;
-                util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev_device->udev), "/data/", id, NULL);
-                dbfile = filename;
-        }
-
-        f = fopen(dbfile, "re");
-        if (f == NULL) {
-                info(udev_device->udev, "no db file to read %s: %m\n", dbfile);
-                return -1;
-        }
-        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':
-                        util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_device->udev), "/", val, NULL);
-                        udev_device_add_devlink(udev_device, filename, 0);
-                        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);
-
-        info(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;
-
-        util_strscpyl(filename, sizeof(filename), udev_device->syspath, "/uevent", NULL);
-        f = fopen(filename, "re");
-        if (f == NULL)
-                return -1;
-        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 (strncmp(line, "DEVTYPE=", 8) == 0) {
-                        udev_device_set_devtype(udev_device, &line[8]);
-                        continue;
-                }
-                if (strncmp(line, "IFINDEX=", 8) == 0) {
-                        udev_device_set_ifindex(udev_device, strtoull(&line[8], NULL, 10));
-                        continue;
-                }
-                if (strncmp(line, "DEVNAME=", 8) == 0) {
-                        udev_device_set_devnode(udev_device, &line[8]);
-                        continue;
-                }
-
-                if (strncmp(line, "MAJOR=", 6) == 0)
-                        maj = strtoull(&line[6], NULL, 10);
-                else if (strncmp(line, "MINOR=", 6) == 0)
-                        min = strtoull(&line[6], NULL, 10);
-                else if (strncmp(line, "DEVMODE=", 8) == 0)
-                        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 = calloc(1, sizeof(struct udev_device));
-        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));
-        dbg(udev_device->udev, "udev_device: %p created\n", udev_device);
-        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
- **/
-UDEV_EXPORT struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath)
-{
-        size_t len;
-        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 */
-        len = strlen(udev_get_sys_path(udev));
-        if (strncmp(syspath, udev_get_sys_path(udev), len) != 0) {
-                info(udev, "not in sys :%s\n", syspath);
-                return NULL;
-        }
-
-        /* path is not a root directory */
-        subdir = &syspath[len+1];
-        pos = strrchr(subdir, '/');
-        if (pos == NULL || pos[1] == '\0' || pos < &subdir[2]) {
-                dbg(udev, "not a subdir :%s\n", syspath);
-                return NULL;
-        }
-
-        /* resolve possible symlink to real path */
-        util_strscpy(path, sizeof(path), syspath);
-        util_resolve_sys_link(udev, path, sizeof(path));
-
-        if (strncmp(&path[len], "/devices/", 9) == 0) {
-                char file[UTIL_PATH_SIZE];
-
-                /* all "devices" require a "uevent" file */
-                util_strscpyl(file, sizeof(file), path, "/uevent", NULL);
-                if (stat(file, &statbuf) != 0) {
-                        dbg(udev, "not a device: %s\n", syspath);
-                        return NULL;
-                }
-        } else {
-                /* everything else just needs to be a directory */
-                if (stat(path, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) {
-                        dbg(udev, "directory not found: %s\n", syspath);
-                        return NULL;
-                }
-        }
-
-        udev_device = udev_device_new(udev);
-        if (udev_device == NULL)
-                return NULL;
-
-        udev_device_set_syspath(udev_device, path);
-        info(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
- **/
-UDEV_EXPORT 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}/<maj>:<min> link */
-        snprintf(path, sizeof(path), "%s/dev/%s/%u:%u",
-                 udev_get_sys_path(udev), type_str, major(devnum), minor(devnum));
-        return udev_device_new_from_syspath(udev, path);
-}
-
-struct udev_device *udev_device_new_from_id_filename(struct udev *udev, 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;
-                memset(&ifr, 0x00, 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 '+':
-                util_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
- **/
-UDEV_EXPORT struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname)
-{
-        char path_full[UTIL_PATH_SIZE];
-        char *path;
-        size_t l;
-        struct stat statbuf;
-
-        path = path_full;
-        l = util_strpcpyl(&path, sizeof(path_full), udev_get_sys_path(udev), NULL);
-
-        if (strcmp(subsystem, "subsystem") == 0) {
-                util_strscpyl(path, l, "/subsystem/", sysname, NULL);
-                if (stat(path_full, &statbuf) == 0)
-                        goto found;
-
-                util_strscpyl(path, l, "/bus/", sysname, NULL);
-                if (stat(path_full, &statbuf) == 0)
-                        goto found;
-
-                util_strscpyl(path, l, "/class/", sysname, NULL);
-                if (stat(path_full, &statbuf) == 0)
-                        goto found;
-                goto out;
-        }
-
-        if (strcmp(subsystem, "module") == 0) {
-                util_strscpyl(path, l, "/module/", sysname, NULL);
-                if (stat(path_full, &statbuf) == 0)
-                        goto found;
-                goto out;
-        }
-
-        if (strcmp(subsystem, "drivers") == 0) {
-                char subsys[UTIL_NAME_SIZE];
-                char *driver;
-
-                util_strscpy(subsys, sizeof(subsys), sysname);
-                driver = strchr(subsys, ':');
-                if (driver != NULL) {
-                        driver[0] = '\0';
-                        driver = &driver[1];
-
-                        util_strscpyl(path, l, "/subsystem/", subsys, "/drivers/", driver, NULL);
-                        if (stat(path_full, &statbuf) == 0)
-                                goto found;
-
-                        util_strscpyl(path, l, "/bus/", subsys, "/drivers/", driver, NULL);
-                        if (stat(path_full, &statbuf) == 0)
-                                goto found;
-                }
-                goto out;
-        }
-
-        util_strscpyl(path, l, "/subsystem/", subsystem, "/devices/", sysname, NULL);
-        if (stat(path_full, &statbuf) == 0)
-                goto found;
-
-        util_strscpyl(path, l, "/bus/", subsystem, "/devices/", sysname, NULL);
-        if (stat(path_full, &statbuf) == 0)
-                goto found;
-
-        util_strscpyl(path, l, "/class/", subsystem, "/", sysname, NULL);
-        if (stat(path_full, &statbuf) == 0)
-                goto found;
-out:
-        return NULL;
-found:
-        return udev_device_new_from_syspath(udev, path_full);
-}
-
-/**
- * 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
- **/
-UDEV_EXPORT 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) {
-                info(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;
-
-        util_strscpy(path, sizeof(path), udev_device->syspath);
-        subdir = &path[strlen(udev_get_sys_path(udev_device->udev))+1];
-        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.
- *
- * The returned the 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.
- **/
-UDEV_EXPORT 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);
-        }
-        if (udev_device->parent_device != NULL)
-                dbg(udev_device->udev, "returning existing parent %p\n", udev_device->parent_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.
- *
- * The returned the 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.
- **/
-UDEV_EXPORT 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 && strcmp(parent_subsystem, subsystem) == 0) {
-                        if (devtype == NULL)
-                                break;
-                        parent_devtype = udev_device_get_devtype(parent);
-                        if (parent_devtype != NULL && strcmp(parent_devtype, devtype) == 0)
-                                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
- **/
-UDEV_EXPORT 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
- **/
-UDEV_EXPORT 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.
- *
- **/
-UDEV_EXPORT void udev_device_unref(struct udev_device *udev_device)
-{
-        if (udev_device == NULL)
-                return;
-        udev_device->refcount--;
-        if (udev_device->refcount > 0)
-                return;
-        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);
-        dbg(udev_device->udev, "udev_device: %p released\n", udev_device);
-        free(udev_device);
-}
-
-/**
- * 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
- **/
-UDEV_EXPORT 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
- **/
-UDEV_EXPORT 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
- *
- * Returns: the sys name of the device device
- **/
-UDEV_EXPORT 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
- *
- * Returns: the trailing number of of the device name
- **/
-UDEV_EXPORT 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
- **/
-UDEV_EXPORT 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_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
- **/
-UDEV_EXPORT 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_next(),
- * which returns #NULL if no more entries exist. The property name
- * can be retrieved from the list entry by udev_list_get_name(),
- * the property value by udev_list_get_value().
- *
- * Returns: the first entry of the property list
- **/
-UDEV_EXPORT 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 = util_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 = util_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 = util_strpcpyl(&s, sizeof(tags), ":", NULL);
-                        udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device))
-                                l = util_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.
- **/
-UDEV_EXPORT 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.
- **/
-UDEV_EXPORT unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device)
-{
-        unsigned long long now;
-
-        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 = now_usec();
-        if (now == 0)
-                return 0;
-        return now - udev_device->usec_initialized;
-}
-
-unsigned long long 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, unsigned long long usec_initialized)
-{
-        char num[32];
-
-        udev_device->usec_initialized = usec_initialized;
-        snprintf(num, sizeof(num), "%llu", 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.
- **/
-UDEV_EXPORT 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) {
-                dbg(udev_device->udev, "got '%s' (%s) from cache\n",
-                    sysattr, udev_list_entry_get_value(list_entry));
-                return udev_list_entry_get_value(list_entry);
-        }
-
-        util_strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device), "/", sysattr, NULL);
-        if (lstat(path, &statbuf) != 0) {
-                dbg(udev_device->udev, "no attribute '%s', keep negative entry\n", path);
-                udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, NULL);
-                goto out;
-        }
-
-        if (S_ISLNK(statbuf.st_mode)) {
-                struct udev_device *dev;
-
-                /*
-                 * Some core links return only the last element of the target path,
-                 * these are just values, the paths should not be exposed.
-                 */
-                if (strcmp(sysattr, "driver") == 0 ||
-                    strcmp(sysattr, "subsystem") == 0 ||
-                    strcmp(sysattr, "module") == 0) {
-                        if (util_get_sys_core_link_value(udev_device->udev, sysattr,
-                                                         udev_device->syspath, value, sizeof(value)) < 0)
-                                return NULL;
-                        dbg(udev_device->udev, "cache '%s' with link value '%s'\n", sysattr, value);
-                        list_entry = udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, value);
-                        val = udev_list_entry_get_value(list_entry);
-                        goto out;
-                }
-
-                /* resolve link to a device and return its syspath */
-                util_strscpyl(path, sizeof(path), udev_device->syspath, "/", sysattr, NULL);
-                dev = udev_device_new_from_syspath(udev_device->udev, path);
-                if (dev != NULL) {
-                        list_entry = udev_list_entry_add(&udev_device->sysattr_value_list, sysattr,
-                                                         udev_device_get_syspath(dev));
-                        val = udev_list_entry_get_value(list_entry);
-                        udev_device_unref(dev);
-                }
-
-                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) {
-                dbg(udev_device->udev, "attribute '%s' can not be opened\n", path);
-                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');
-        dbg(udev_device->udev, "'%s' has attribute value '%s'\n", path, value);
-        list_entry = udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, value);
-        val = udev_list_entry_get_value(list_entry);
-out:
-        return val;
-}
-
-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 -1;
-        if (udev_device->sysattr_list_read)
-                return 0;
-
-        dir = opendir(udev_device_get_syspath(udev_device));
-        if (!dir) {
-                dbg(udev_device->udev, "sysfs dir '%s' can not be opened\n",
-                                udev_device_get_syspath(udev_device));
-                return -1;
-        }
-
-        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;
-
-                util_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);
-        dbg(udev_device->udev, "found %d sysattrs for '%s'\n", num, udev_device_get_syspath(udev_device));
-        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
- **/
-UDEV_EXPORT 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(udev_get_sys_path(udev_device->udev))];
-        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;
-}
-
-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, "%s/%s", udev_get_dev_path(udev_device->udev), 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, int unique)
-{
-        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;
-        if (unique)
-                udev_list_entry_set_num(list_entry, true);
-        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",
-                                     strcmp(udev_device_get_subsystem(udev_device), "block") == 0 ? '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.
- **/
-UDEV_EXPORT 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_next(),
- * which returns #NULL if no more entries exist. The tag string
- * can be retrieved from the list entry by udev_list_get_name().
- *
- * Returns: the first entry of the tag list
- **/
-UDEV_EXPORT 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_EXPORT 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 = util_strpcpyl(&s, l, key, "=", udev_list_entry_get_value(list_entry), NULL);
-                if (l == 0)
-                        return -EINVAL;
-                /* advance past the trailing '\0' that util_strpcpyl() guarantees */
-                s++;
-                l--;
-        }
-        udev_device->envp[i] = NULL;
-        udev_device->monitor_buf_len = s - udev_device->monitor_buf;
-        udev_device->envp_uptodate = true;
-        dbg(udev_device->udev, "filled envp/monitor buffer, %u properties, %zu bytes\n",
-            i, udev_device->monitor_buf_len);
-        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/udev/src/libudev-enumerate.c b/src/udev/src/libudev-enumerate.c
deleted file mode 100644 (file)
index 034d96f..0000000
+++ /dev/null
@@ -1,947 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.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.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <dirent.h>
-#include <fnmatch.h>
-#include <stdbool.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-
-#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
- *
- * Returns: an enumeration context
- **/
-UDEV_EXPORT struct udev_enumerate *udev_enumerate_new(struct udev *udev)
-{
-        struct udev_enumerate *udev_enumerate;
-
-        udev_enumerate = calloc(1, sizeof(struct udev_enumerate));
-        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
- **/
-UDEV_EXPORT 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.
- **/
-UDEV_EXPORT void udev_enumerate_unref(struct udev_enumerate *udev_enumerate)
-{
-        unsigned int i;
-
-        if (udev_enumerate == NULL)
-                return;
-        udev_enumerate->refcount--;
-        if (udev_enumerate->refcount > 0)
-                return;
-        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);
-}
-
-/**
- * udev_enumerate_get_udev:
- * @udev_enumerate: context
- *
- * Returns: the udev library context.
- */
-UDEV_EXPORT 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
-        };
-        size_t len;
-        int i;
-
-        len = strlen(udev_get_sys_path(udev));
-        for (i = 0; delay_device_list[i] != NULL; i++) {
-                if (strstr(&syspath[len], delay_device_list[i]) != NULL) {
-                        dbg(udev, "delaying: %s\n", syspath);
-                        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 (strncmp(c, "/controlC", 9) == 0)
-                        return c - syspath + 1;
-        }
-
-        return 0;
-}
-
-/**
- * udev_enumerate_get_list_entry:
- * @udev_enumerate: context
- *
- * Returns: the first entry of the sorted list of device paths.
- */
-UDEV_EXPORT 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;
-                unsigned int max;
-                struct syspath *prev = NULL, *move_later = NULL;
-                size_t move_later_prefix = 0;
-
-                udev_list_cleanup(&udev_enumerate->devices_list);
-                qsort(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) {
-                                move_later_prefix = devices_delay_later(udev_enumerate->udev, entry->syspath);
-
-                                if (move_later_prefix > 0) {
-                                        move_later = entry;
-                                        continue;
-                                }
-                        }
-
-                        if (move_later &&
-                            strncmp(entry->syspath, move_later->syspath, move_later_prefix) != 0) {
-
-                                udev_list_entry_add(&udev_enumerate->devices_list, move_later->syspath, NULL);
-                                move_later = NULL;
-                        }
-
-                        udev_list_entry_add(&udev_enumerate->devices_list, entry->syspath, NULL);
-                }
-
-                if (move_later)
-                        udev_list_entry_add(&udev_enumerate->devices_list, 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
- *
- * Returns: 0 on success, otherwise a negative error value.
- */
-UDEV_EXPORT 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
- *
- * Returns: 0 on success, otherwise a negative error value.
- */
-UDEV_EXPORT 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
- *
- * Returns: 0 on success, otherwise a negative error value.
- */
-UDEV_EXPORT 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
- *
- * Returns: 0 on success, otherwise a negative error value.
- */
-UDEV_EXPORT 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
- *
- * Returns: 0 on success, otherwise a negative error value.
- */
-UDEV_EXPORT 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
- *
- * Returns: 0 on success, otherwise a negative error value.
- */
-UDEV_EXPORT 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.
- */
-UDEV_EXPORT 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.
- */
-UDEV_EXPORT 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
- *
- * Returns: 0 on success, otherwise a negative error value.
- */
-UDEV_EXPORT 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)
-{
-        const char *parent;
-
-        if (udev_enumerate->parent_match == NULL)
-                return true;
-
-        parent = udev_device_get_devpath(udev_enumerate->parent_match);
-        return strncmp(parent, udev_device_get_devpath(dev), strlen(parent)) == 0;
-}
-
-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)
-{
-        struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
-        char path[UTIL_PATH_SIZE];
-        size_t l;
-        char *s;
-        DIR *dir;
-        struct dirent *dent;
-
-        s = path;
-        l = util_strpcpyl(&s, sizeof(path), udev_get_sys_path(udev), "/", basedir, NULL);
-        if (subdir1 != NULL)
-                l = util_strpcpyl(&s, l, "/", subdir1, NULL);
-        if (subdir2 != NULL)
-                util_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;
-
-                util_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;
-
-        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)
-{
-        struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
-
-        char path[UTIL_PATH_SIZE];
-        DIR *dir;
-        struct dirent *dent;
-
-        util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), "/", 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.
- */
-UDEV_EXPORT 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 *udev = udev_enumerate_get_udev(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];
-
-                util_strscpyl(path, sizeof(path), udev_get_run_path(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_id_filename(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;
-
-        dev = udev_device_new_from_syspath(enumerate->udev, path);
-        if (dev == NULL)
-                return -ENODEV;
-
-        if (!match_subsystem(enumerate, udev_device_get_subsystem(dev)))
-                return 0;
-        if (!match_sysname(enumerate, udev_device_get_sysname(dev)))
-                return 0;
-        if (!match_property(enumerate, dev))
-                return 0;
-        if (!match_sysattr(enumerate, dev))
-                return 0;
-
-        syspath_add(enumerate, udev_device_get_syspath(dev));
-        udev_device_unref(dev);
-        return 1;
-}
-
-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 udev *udev = udev_enumerate_get_udev(udev_enumerate);
-        char base[UTIL_PATH_SIZE];
-        struct stat statbuf;
-
-        util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/subsystem", NULL);
-        if (stat(base, &statbuf) == 0) {
-                /* we have /subsystem/, forget all the old stuff */
-                dbg(udev, "searching '/subsystem/*/devices/*' dir\n");
-                scan_dir(udev_enumerate, "subsystem", "devices", NULL);
-        } else {
-                dbg(udev, "searching '/bus/*/devices/*' dir\n");
-                scan_dir(udev_enumerate, "bus", "devices", NULL);
-                dbg(udev, "searching '/class/*' dir\n");
-                scan_dir(udev_enumerate, "class", NULL, NULL);
-        }
-        return 0;
-}
-
-/**
- * udev_enumerate_scan_devices:
- * @udev_enumerate: udev enumeration context
- *
- * Returns: 0 on success, otherwise a negative error value.
- **/
-UDEV_EXPORT 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
- *
- * Returns: 0 on success, otherwise a negative error value.
- **/
-UDEV_EXPORT int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate)
-{
-        struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
-        char base[UTIL_PATH_SIZE];
-        struct stat statbuf;
-        const char *subsysdir;
-
-        if (udev_enumerate == NULL)
-                return -EINVAL;
-
-        /* all kernel modules */
-        if (match_subsystem(udev_enumerate, "module")) {
-                dbg(udev, "searching 'modules/*' dir\n");
-                scan_dir_and_add_devices(udev_enumerate, "module", NULL, NULL);
-        }
-
-        util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/subsystem", NULL);
-        if (stat(base, &statbuf) == 0)
-                subsysdir = "subsystem";
-        else
-                subsysdir = "bus";
-
-        /* all subsystems (only buses support coldplug) */
-        if (match_subsystem(udev_enumerate, "subsystem")) {
-                dbg(udev, "searching '%s/*' dir\n", subsysdir);
-                scan_dir_and_add_devices(udev_enumerate, subsysdir, NULL, NULL);
-        }
-
-        /* all subsystem drivers */
-        if (match_subsystem(udev_enumerate, "drivers")) {
-                dbg(udev, "searching '%s/*/drivers/*' dir\n", subsysdir);
-                scan_dir(udev_enumerate, subsysdir, "drivers", "drivers");
-        }
-        return 0;
-}
diff --git a/src/udev/src/libudev-list.c b/src/udev/src/libudev-list.c
deleted file mode 100644 (file)
index 4bdef35..0000000
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.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.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-
-#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 struct udev_list_entry *list_node_to_entry(struct udev_list_node *node)
-{
-        char *list;
-
-        list = (char *)node;
-        list -= offsetof(struct udev_list_entry, node);
-        return (struct udev_list_entry *)list;
-}
-
-void udev_list_init(struct udev *udev, struct udev_list *list, bool unique)
-{
-        memset(list, 0x00, 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  */
-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 */
-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];
-
-                        dbg(list->udev, "'%s' is already in the list\n", name);
-                        free(entry->value);
-                        if (value == NULL) {
-                                entry->value = NULL;
-                                dbg(list->udev, "'%s' value unset\n", name);
-                                return entry;
-                        }
-                        entry->value = strdup(value);
-                        if (entry->value == NULL)
-                                return NULL;
-                        dbg(list->udev, "'%s' value replaced with '%s'\n", name, value);
-                        return entry;
-                }
-        }
-
-        /* add new name */
-        entry = calloc(1, sizeof(struct udev_list_entry));
-        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) {
-                        unsigned int add;
-
-                        add = list->entries_max;
-                        if (add < 1)
-                                add = 64;
-                        list->entries = realloc(list->entries, (list->entries_max + add) * sizeof(struct udev_list_entry *));
-                        if (list->entries == NULL) {
-                                free(entry->name);
-                                free(entry->value);
-                                return NULL;
-                        }
-                        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);
-        }
-
-        dbg(list->udev, "'%s=%s' added\n", entry->name, entry->value);
-        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
- *
- * Returns: the next entry from the list, #NULL is no more entries are found.
- */
-UDEV_EXPORT 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
- *
- * Returns: the entry where @name matched, #NULL if no matching entry is found.
- */
-UDEV_EXPORT 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
- *
- * Returns: the name string of this entry.
- */
-UDEV_EXPORT 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
- *
- * Returns: the value string of this entry.
- */
-UDEV_EXPORT 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/udev/src/libudev-monitor.c b/src/udev/src/libudev-monitor.c
deleted file mode 100644 (file)
index 77dc555..0000000
+++ /dev/null
@@ -1,874 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.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.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <dirent.h>
-#include <sys/poll.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <arpa/inet.h>
-#include <linux/netlink.h>
-#include <linux/filter.h>
-
-#include "libudev.h"
-#include "libudev-private.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;
-        struct sockaddr_nl snl;
-        struct sockaddr_nl snl_trusted_sender;
-        struct sockaddr_nl snl_destination;
-        struct sockaddr_un sun;
-        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 = calloc(1, sizeof(struct udev_monitor));
-        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;
-}
-
-/**
- * udev_monitor_new_from_socket:
- * @udev: udev library context
- * @socket_path: unix socket path
- *
- * This function should not be used in any new application. The
- * kernel's netlink socket multiplexes messages to all interested
- * clients. Creating custom sockets from udev to applications
- * should be avoided.
- *
- * Create a new udev monitor and connect to a specified socket. The
- * path to a socket either points to an existing socket file, or if
- * the socket path starts with a '@' character, an abstract namespace
- * socket will be used.
- *
- * A socket file will not be created. If it does not already exist,
- * it will fall-back and connect to an abstract namespace socket with
- * the given path. The permissions adjustment of a socket file, as
- * well as the later cleanup, needs to be done by the caller.
- *
- * 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
- **/
-UDEV_EXPORT struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path)
-{
-        struct udev_monitor *udev_monitor;
-        struct stat statbuf;
-
-        if (udev == NULL)
-                return NULL;
-        if (socket_path == NULL)
-                return NULL;
-        udev_monitor = udev_monitor_new(udev);
-        if (udev_monitor == NULL)
-                return NULL;
-
-        udev_monitor->sun.sun_family = AF_LOCAL;
-        if (socket_path[0] == '@') {
-                /* translate leading '@' to abstract namespace */
-                util_strscpy(udev_monitor->sun.sun_path, sizeof(udev_monitor->sun.sun_path), socket_path);
-                udev_monitor->sun.sun_path[0] = '\0';
-                udev_monitor->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(socket_path);
-        } else if (stat(socket_path, &statbuf) == 0 && S_ISSOCK(statbuf.st_mode)) {
-                /* existing socket file */
-                util_strscpy(udev_monitor->sun.sun_path, sizeof(udev_monitor->sun.sun_path), socket_path);
-                udev_monitor->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(socket_path);
-        } else {
-                /* no socket file, assume abstract namespace socket */
-                util_strscpy(&udev_monitor->sun.sun_path[1], sizeof(udev_monitor->sun.sun_path)-1, socket_path);
-                udev_monitor->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(socket_path)+1;
-        }
-        udev_monitor->sock = socket(AF_LOCAL, SOCK_DGRAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
-        if (udev_monitor->sock == -1) {
-                err(udev, "error getting socket: %m\n");
-                free(udev_monitor);
-                return NULL;
-        }
-
-        dbg(udev, "monitor %p created with '%s'\n", udev_monitor, socket_path);
-        return udev_monitor;
-}
-
-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 (strcmp(name, "udev") == 0)
-                group = UDEV_MONITOR_UDEV;
-        else if (strcmp(name, "kernel") == 0)
-                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) {
-                        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_family = AF_NETLINK;
-        udev_monitor->snl.nl_groups = group;
-
-        /* default destination for sending */
-        udev_monitor->snl_destination.nl_family = AF_NETLINK;
-        udev_monitor->snl_destination.nl_groups = UDEV_MONITOR_UDEV;
-
-        dbg(udev, "monitor %p created with NETLINK_KOBJECT_UEVENT (%u)\n", udev_monitor, group);
-        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
- **/
-UDEV_EXPORT 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.
- */
-UDEV_EXPORT 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;
-
-        memset(ins, 0x00, 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 >= ARRAY_SIZE(ins))
-                                return -1;
-                }
-
-                /* 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 */
-        memset(&filter, 0x00, sizeof(filter));
-        filter.len = i;
-        filter.filter = ins;
-        err = setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter));
-        return err;
-}
-
-int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender)
-{
-        udev_monitor->snl_trusted_sender.nl_pid = sender->snl.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.
- */
-UDEV_EXPORT int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor)
-{
-        int err = 0;
-        const int on = 1;
-
-        if (udev_monitor->sun.sun_family != 0) {
-                if (!udev_monitor->bound) {
-                        err = bind(udev_monitor->sock,
-                                   (struct sockaddr *)&udev_monitor->sun, udev_monitor->addrlen);
-                        if (err == 0)
-                                udev_monitor->bound = true;
-                }
-        } else if (udev_monitor->snl.nl_family != 0) {
-                udev_monitor_filter_update(udev_monitor);
-                if (!udev_monitor->bound) {
-                        err = bind(udev_monitor->sock,
-                                   (struct sockaddr *)&udev_monitor->snl, sizeof(struct sockaddr_nl));
-                        if (err == 0)
-                                udev_monitor->bound = true;
-                }
-                if (err == 0) {
-                        struct sockaddr_nl 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, (struct sockaddr *)&snl, &addrlen);
-                        if (err == 0)
-                                udev_monitor->snl.nl_pid = snl.nl_pid;
-                }
-        } else {
-                return -EINVAL;
-        }
-
-        if (err < 0) {
-                err(udev_monitor->udev, "bind failed: %m\n");
-                return err;
-        }
-
-        /* 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.
- */
-UDEV_EXPORT int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size)
-{
-        if (udev_monitor == NULL)
-                return -1;
-        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;
-}
-
-/**
- * udev_monitor_ref:
- * @udev_monitor: udev monitor
- *
- * Take a reference of a udev monitor.
- *
- * Returns: the passed udev monitor
- **/
-UDEV_EXPORT 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.
- *
- **/
-UDEV_EXPORT void udev_monitor_unref(struct udev_monitor *udev_monitor)
-{
-        if (udev_monitor == NULL)
-                return;
-        udev_monitor->refcount--;
-        if (udev_monitor->refcount > 0)
-                return;
-        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);
-        dbg(udev_monitor->udev, "monitor %p released\n", udev_monitor);
-        free(udev_monitor);
-}
-
-/**
- * udev_monitor_get_udev:
- * @udev_monitor: udev monitor
- *
- * Retrieve the udev library context the monitor was created with.
- *
- * Returns: the udev library context
- **/
-UDEV_EXPORT 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
- **/
-UDEV_EXPORT int udev_monitor_get_fd(struct udev_monitor *udev_monitor)
-{
-        if (udev_monitor == NULL)
-                return -1;
-        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 (strcmp(dsubsys, subsys) != 0)
-                        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 (strcmp(ddevtype, devtype) == 0)
-                        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 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
- **/
-UDEV_EXPORT 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;
-        struct sockaddr_nl snl;
-        struct ucred *cred;
-        char buf[8192];
-        ssize_t buflen;
-        ssize_t bufpos;
-        struct udev_monitor_netlink_header *nlh;
-
-retry:
-        if (udev_monitor == NULL)
-                return NULL;
-        iov.iov_base = &buf;
-        iov.iov_len = sizeof(buf);
-        memset (&smsg, 0x00, sizeof(struct msghdr));
-        smsg.msg_iov = &iov;
-        smsg.msg_iovlen = 1;
-        smsg.msg_control = cred_msg;
-        smsg.msg_controllen = sizeof(cred_msg);
-
-        if (udev_monitor->snl.nl_family != 0) {
-                smsg.msg_name = &snl;
-                smsg.msg_namelen = sizeof(snl);
-        }
-
-        buflen = recvmsg(udev_monitor->sock, &smsg, 0);
-        if (buflen < 0) {
-                if (errno != EINTR)
-                        info(udev_monitor->udev, "unable to receive message\n");
-                return NULL;
-        }
-
-        if (buflen < 32 || (size_t)buflen >= sizeof(buf)) {
-                info(udev_monitor->udev, "invalid message length\n");
-                return NULL;
-        }
-
-        if (udev_monitor->snl.nl_family != 0) {
-                if (snl.nl_groups == 0) {
-                        /* unicast message, check if we trust the sender */
-                        if (udev_monitor->snl_trusted_sender.nl_pid == 0 ||
-                            snl.nl_pid != udev_monitor->snl_trusted_sender.nl_pid) {
-                                info(udev_monitor->udev, "unicast netlink message ignored\n");
-                                return NULL;
-                        }
-                } else if (snl.nl_groups == UDEV_MONITOR_KERNEL) {
-                        if (snl.nl_pid > 0) {
-                                info(udev_monitor->udev, "multicast kernel netlink message from pid %d ignored\n",
-                                     snl.nl_pid);
-                                return NULL;
-                        }
-                }
-        }
-
-        cmsg = CMSG_FIRSTHDR(&smsg);
-        if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
-                info(udev_monitor->udev, "no sender credentials received, message ignored\n");
-                return NULL;
-        }
-
-        cred = (struct ucred *)CMSG_DATA(cmsg);
-        if (cred->uid != 0) {
-                info(udev_monitor->udev, "sender uid=%d, message ignored\n", cred->uid);
-                return NULL;
-        }
-
-        if (memcmp(buf, "libudev", 8) == 0) {
-                /* udev message needs proper version magic */
-                nlh = (struct udev_monitor_netlink_header *) buf;
-                if (nlh->magic != htonl(UDEV_MONITOR_MAGIC)) {
-                        err(udev_monitor->udev, "unrecognized message signature (%x != %x)\n",
-                            nlh->magic, htonl(UDEV_MONITOR_MAGIC));
-                        return NULL;
-                }
-                if (nlh->properties_off+32 > buflen)
-                        return NULL;
-                bufpos = nlh->properties_off;
-        } else {
-                /* kernel message with header */
-                bufpos = strlen(buf) + 1;
-                if ((size_t)bufpos < sizeof("a@/d") || bufpos >= buflen) {
-                        info(udev_monitor->udev, "invalid message length\n");
-                        return NULL;
-                }
-
-                /* check message header */
-                if (strstr(buf, "@/") == NULL) {
-                        info(udev_monitor->udev, "unrecognized message header\n");
-                        return NULL;
-                }
-        }
-
-        udev_device = udev_device_new(udev_monitor->udev);
-        if (udev_device == NULL)
-                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) {
-                info(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;
-
-        blen = udev_device_get_properties_monitor_buf(udev_device, &buf);
-        if (blen < 32)
-                return -EINVAL;
-
-        if (udev_monitor->sun.sun_family != 0) {
-                struct msghdr smsg;
-                struct iovec iov[2];
-                const char *action;
-                char header[2048];
-                char *s;
-
-                /* header <action>@<devpath> */
-                action = udev_device_get_action(udev_device);
-                if (action == NULL)
-                        return -EINVAL;
-                s = header;
-                if (util_strpcpyl(&s, sizeof(header), action, "@", udev_device_get_devpath(udev_device), NULL) == 0)
-                        return -EINVAL;
-                iov[0].iov_base = header;
-                iov[0].iov_len = (s - header)+1;
-
-                /* add properties list */
-                iov[1].iov_base = (char *)buf;
-                iov[1].iov_len = blen;
-
-                memset(&smsg, 0x00, sizeof(struct msghdr));
-                smsg.msg_iov = iov;
-                smsg.msg_iovlen = 2;
-                smsg.msg_name = &udev_monitor->sun;
-                smsg.msg_namelen = udev_monitor->addrlen;
-                count = sendmsg(udev_monitor->sock, &smsg, 0);
-                info(udev_monitor->udev, "passed %zi bytes to socket monitor %p\n", count, udev_monitor);
-                return count;
-        }
-
-        if (udev_monitor->snl.nl_family != 0) {
-                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;
-
-                /* add versioned header */
-                memset(&nlh, 0x00, 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;
-
-                memset(&smsg, 0x00, 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);
-                info(udev_monitor->udev, "passed %zi bytes to netlink monitor %p\n", count, udev_monitor);
-                return count;
-        }
-
-        return -EINVAL;
-}
-
-/**
- * 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.
- */
-UDEV_EXPORT 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.
- */
-UDEV_EXPORT 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.
- */
-UDEV_EXPORT 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/udev/src/libudev-private.h b/src/udev/src/libudev-private.h
deleted file mode 100644 (file)
index 5f5c64a..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.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.
- */
-
-#ifndef _LIBUDEV_PRIVATE_H_
-#define _LIBUDEV_PRIVATE_H_
-
-#include <syslog.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include "libudev.h"
-
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-#define READ_END                                0
-#define WRITE_END                                1
-
-static inline void __attribute__((always_inline, format(printf, 2, 3)))
-udev_log_null(struct udev *udev, const char *format, ...) {}
-
-#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)
-
-#ifdef ENABLE_LOGGING
-#  ifdef ENABLE_DEBUG
-#    define dbg(udev, arg...) udev_log_cond(udev, LOG_DEBUG, ## arg)
-#  else
-#    define dbg(udev, arg...) udev_log_null(udev, ## arg)
-#  endif
-#  define info(udev, arg...) udev_log_cond(udev, LOG_INFO, ## arg)
-#  define err(udev, arg...) udev_log_cond(udev, LOG_ERR, ## arg)
-#else
-#  define dbg(udev, arg...) udev_log_null(udev, ## arg)
-#  define info(udev, arg...) udev_log_null(udev, ## arg)
-#  define err(udev, arg...) udev_log_null(udev, ## arg)
-#endif
-
-#define UDEV_EXPORT __attribute__ ((visibility("default")))
-
-static inline void udev_log_init(const char *program_name)
-{
-        openlog(program_name, LOG_PID | LOG_CONS, LOG_DAEMON);
-}
-
-static inline void udev_log_close(void)
-{
-        closelog();
-}
-
-/* libudev.c */
-void udev_log(struct udev *udev,
-              int priority, const char *file, int line, const char *fn,
-              const char *format, ...)
-              __attribute__((format(printf, 6, 7)));
-int udev_get_rules_path(struct udev *udev, char **path[], unsigned long long *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);
-struct udev_device *udev_device_new_from_id_filename(struct udev *udev, char *id);
-mode_t udev_device_get_devnode_mode(struct udev_device *udev_device);
-int udev_device_set_syspath(struct udev_device *udev_device, const char *syspath);
-int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode);
-int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink, int unique);
-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);
-unsigned long long udev_device_get_usec_initialized(struct udev_device *udev_device);
-void udev_device_set_usec_initialized(struct udev_device *udev_device, unsigned long long 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);
-void udev_list_entry_insert_before(struct udev_list_entry *new, struct udev_list_entry *entry);
-void udev_list_entry_append(struct udev_list_entry *new, struct udev_list *list);
-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-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);
-size_t util_path_decode(char *s);
-void util_remove_trailing_chars(char *path, char c);
-size_t util_strpcpy(char **dest, size_t size, const char *src);
-size_t util_strpcpyl(char **dest, size_t size, const char *src, ...) __attribute__((sentinel));
-size_t util_strscpy(char *dest, size_t size, const char *src);
-size_t util_strscpyl(char *dest, size_t size, const char *src, ...) __attribute__((sentinel));
-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_create_path(struct udev *udev, const char *path);
-int util_create_path_selinux(struct udev *udev, const char *path);
-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);
-unsigned long long ts_usec(const struct timespec *ts);
-unsigned long long now_usec(void);
-
-/* libudev-selinux-private.c */
-#ifndef WITH_SELINUX
-static inline void udev_selinux_init(struct udev *udev) {}
-static inline void udev_selinux_exit(struct udev *udev) {}
-static inline void udev_selinux_lsetfilecon(struct udev *udev, const char *file, unsigned int mode) {}
-static inline void udev_selinux_setfscreatecon(struct udev *udev, const char *file, unsigned int mode) {}
-static inline void udev_selinux_setfscreateconat(struct udev *udev, int dfd, const char *file, unsigned int mode) {}
-static inline void udev_selinux_resetfscreatecon(struct udev *udev) {}
-#else
-void udev_selinux_init(struct udev *udev);
-void udev_selinux_exit(struct udev *udev);
-void udev_selinux_lsetfilecon(struct udev *udev, const char *file, unsigned int mode);
-void udev_selinux_setfscreatecon(struct udev *udev, const char *file, unsigned int mode);
-void udev_selinux_setfscreateconat(struct udev *udev, int dfd, const char *file, unsigned int mode);
-void udev_selinux_resetfscreatecon(struct udev *udev);
-#endif
-
-#endif
diff --git a/src/udev/src/libudev-queue-private.c b/src/udev/src/libudev-queue-private.c
deleted file mode 100644 (file)
index 7177195..0000000
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
- * Copyright (C) 2009 Alan Jenkins <alan-jenkins@tuffmail.co.uk>
- *
- * 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.
- */
-
-/*
- * 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <limits.h>
-#include <errno.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#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 = calloc(1, sizeof(struct udev_queue_export));
-        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)
-{
-        char filename[UTIL_PATH_SIZE];
-
-        if (udev_queue_export == NULL)
-                return;
-        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev_queue_export->udev), "/queue.tmp", NULL);
-        unlink(filename);
-        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev_queue_export->udev), "/queue.bin", NULL);
-        unlink(filename);
-}
-
-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[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) {
-                err(udev_queue_export->udev, "queue file overflow\n");
-                return NULL;
-        }
-        devpaths = calloc(1, 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:
-        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;
-        char filename[UTIL_PATH_SIZE];
-        char filename_tmp[UTIL_PATH_SIZE];
-        FILE *new_queue_file = NULL;
-        unsigned int i;
-
-        /* read old queue file */
-        if (udev_queue_export->queue_file != NULL) {
-                dbg(udev_queue_export->udev, "compacting queue file, freeing %d bytes\n",
-                                                udev_queue_export->waste_bytes);
-
-                devpaths = build_index(udev_queue_export);
-                if (devpaths != NULL)
-                        udev_queue_export->seqnum_max += devpaths->devpaths_first;
-        }
-        if (devpaths == NULL) {
-                dbg(udev_queue_export->udev, "creating empty queue file\n");
-                udev_queue_export->queued_count = 0;
-                udev_queue_export->seqnum_max = udev_queue_export->seqnum_min;
-        }
-
-        /* create new queue file */
-        util_strscpyl(filename_tmp, sizeof(filename_tmp), udev_get_run_path(udev_queue_export->udev), "/queue.tmp", NULL);
-        new_queue_file = fopen(filename_tmp, "w+");
-        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 */
-        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev_queue_export->udev), "/queue.bin", NULL);
-        if (rename(filename_tmp, filename) != 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:
-        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) {
-                dbg(udev_queue_export->udev, "can't record event: queue file not available\n");
-                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. */
-        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/udev/src/libudev-queue.c b/src/udev/src/libudev-queue.c
deleted file mode 100644 (file)
index 0e82cb6..0000000
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
- * Copyright (C) 2009 Alan Jenkins <alan-jenkins@tuffmail.co.uk>
- *
- * 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 <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <sys/stat.h>
-
-#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.
- **/
-UDEV_EXPORT struct udev_queue *udev_queue_new(struct udev *udev)
-{
-        struct udev_queue *udev_queue;
-
-        if (udev == NULL)
-                return NULL;
-
-        udev_queue = calloc(1, sizeof(struct udev_queue));
-        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.
- **/
-UDEV_EXPORT 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.
- **/
-UDEV_EXPORT void udev_queue_unref(struct udev_queue *udev_queue)
-{
-        if (udev_queue == NULL)
-                return;
-        udev_queue->refcount--;
-        if (udev_queue->refcount > 0)
-                return;
-        udev_list_cleanup(&udev_queue->queue_list);
-        free(udev_queue);
-}
-
-/**
- * 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.
- **/
-UDEV_EXPORT 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)
-{
-        char filename[UTIL_PATH_SIZE];
-        unsigned long long int seqnum;
-        int fd;
-        char buf[32];
-        ssize_t len;
-
-        util_strscpyl(filename, sizeof(filename), udev_get_sys_path(udev), "/kernel/uevent_seqnum", NULL);
-        fd = open(filename, 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
- *
- * Returns: the current kernel event sequence number.
- **/
-UDEV_EXPORT 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);
-        dbg(udev_queue->udev, "seqnum=%llu\n", seqnum);
-        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[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[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)
-{
-        char filename[UTIL_PATH_SIZE];
-        FILE *queue_file;
-
-        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev_queue->udev), "/queue.bin", NULL);
-        queue_file = fopen(filename, "re");
-        if (queue_file == NULL)
-                return NULL;
-
-        if (udev_queue_read_seqnum(queue_file, seqnum_start) < 0) {
-                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
- *
- * Returns: the last known udev event sequence number.
- **/
-UDEV_EXPORT 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
- *
- * Returns: a flag indicating if udev is active.
- **/
-UDEV_EXPORT 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
- *
- * Returns: a flag indicating if udev is currently handling events.
- **/
-UDEV_EXPORT 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) {
-                dbg(udev_queue->udev, "queue is not empty\n");
-                goto out;
-        }
-
-        seqnum_kernel = udev_queue_get_kernel_seqnum(udev_queue);
-        if (seqnum_udev < seqnum_kernel) {
-                dbg(udev_queue->udev, "queue is empty but kernel events still pending [%llu]<->[%llu]\n",
-                                      seqnum_kernel, seqnum_udev);
-                goto out;
-        }
-
-        dbg(udev_queue->udev, "queue is empty\n");
-        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
- *
- * Returns: a flag indicating if any of the sequence numbers in the given range is currently active.
- **/
-UDEV_EXPORT 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
- *
- * Returns: a flag indicating if the given sequence number is currently active.
- **/
-UDEV_EXPORT 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;
-
-        dbg(udev_queue->udev, "seqnum: %llu finished\n", seqnum);
-        return 1;
-}
-
-/**
- * udev_queue_get_queued_list_entry:
- * @udev_queue: udev queue context
- *
- * Returns: the first entry of the list of queued events.
- **/
-UDEV_EXPORT 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 = util_strpcpyl(&s, sizeof(syspath), udev_get_sys_path(udev_queue->udev), NULL);
-                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 (strcmp(seqnum_str, udev_list_entry_get_value(list_entry)) == 0) {
-                                        udev_list_entry_delete(list_entry);
-                                        break;
-                                }
-                        }
-                }
-        }
-        fclose(queue_file);
-
-        return udev_list_get_entry(&udev_queue->queue_list);
-}
-
-struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue);
-UDEV_EXPORT struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue)
-{
-        errno = ENOSYS;
-        return NULL;
-}
diff --git a/src/udev/src/libudev-selinux-private.c b/src/udev/src/libudev-selinux-private.c
deleted file mode 100644 (file)
index 0f2a617..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.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.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <selinux/selinux.h>
-
-#include "libudev.h"
-#include "libudev-private.h"
-
-static int selinux_enabled;
-security_context_t selinux_prev_scontext;
-
-void udev_selinux_init(struct udev *udev)
-{
-        /* record the present security context */
-        selinux_enabled = (is_selinux_enabled() > 0);
-        info(udev, "selinux=%i\n", selinux_enabled);
-        if (!selinux_enabled)
-                return;
-        matchpathcon_init_prefix(NULL, udev_get_dev_path(udev));
-        if (getfscreatecon(&selinux_prev_scontext) < 0) {
-                err(udev, "getfscreatecon failed\n");
-                selinux_prev_scontext = NULL;
-        }
-}
-
-void udev_selinux_exit(struct udev *udev)
-{
-        if (!selinux_enabled)
-                return;
-        freecon(selinux_prev_scontext);
-        selinux_prev_scontext = NULL;
-}
-
-void udev_selinux_lsetfilecon(struct udev *udev, const char *file, unsigned int mode)
-{
-        security_context_t scontext = NULL;
-
-        if (!selinux_enabled)
-                return;
-        if (matchpathcon(file, mode, &scontext) < 0) {
-                err(udev, "matchpathcon(%s) failed\n", file);
-                return;
-        }
-        if (lsetfilecon(file, scontext) < 0)
-                err(udev, "setfilecon %s failed: %m\n", file);
-        freecon(scontext);
-}
-
-void udev_selinux_setfscreatecon(struct udev *udev, const char *file, unsigned int mode)
-{
-        security_context_t scontext = NULL;
-
-        if (!selinux_enabled)
-                return;
-
-        if (matchpathcon(file, mode, &scontext) < 0) {
-                err(udev, "matchpathcon(%s) failed\n", file);
-                return;
-        }
-        if (setfscreatecon(scontext) < 0)
-                err(udev, "setfscreatecon %s failed: %m\n", file);
-        freecon(scontext);
-}
-
-void udev_selinux_resetfscreatecon(struct udev *udev)
-{
-        if (!selinux_enabled)
-                return;
-        if (setfscreatecon(selinux_prev_scontext) < 0)
-                err(udev, "setfscreatecon failed: %m\n");
-}
-
-void udev_selinux_setfscreateconat(struct udev *udev, int dfd, const char *file, unsigned int mode)
-{
-        char filename[UTIL_PATH_SIZE];
-
-        if (!selinux_enabled)
-                return;
-
-        /* resolve relative filename */
-        if (file[0] != '/') {
-                char procfd[UTIL_PATH_SIZE];
-                char target[UTIL_PATH_SIZE];
-                ssize_t len;
-
-                snprintf(procfd, sizeof(procfd), "/proc/%u/fd/%u", getpid(), dfd);
-                len = readlink(procfd, target, sizeof(target));
-                if (len <= 0 || len == sizeof(target))
-                        return;
-                target[len] = '\0';
-
-                util_strscpyl(filename, sizeof(filename), target, "/", file, NULL);
-                file = filename;
-        }
-        udev_selinux_setfscreatecon(udev, file, mode);
-}
diff --git a/src/udev/src/libudev-util-private.c b/src/udev/src/libudev-util-private.c
deleted file mode 100644 (file)
index 08f0ba2..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2003-2009 Kay Sievers <kay.sievers@vrfy.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.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <ctype.h>
-#include <pwd.h>
-#include <grp.h>
-#include <sys/param.h>
-
-#include "libudev.h"
-#include "libudev-private.h"
-
-static int create_path(struct udev *udev, const char *path, bool selinux)
-{
-        char p[UTIL_PATH_SIZE];
-        char *pos;
-        struct stat stats;
-        int err;
-
-        util_strscpy(p, sizeof(p), path);
-        pos = strrchr(p, '/');
-        if (pos == NULL)
-                return 0;
-        while (pos != p && pos[-1] == '/')
-                pos--;
-        if (pos == p)
-                return 0;
-        pos[0] = '\0';
-
-        dbg(udev, "stat '%s'\n", p);
-        if (stat(p, &stats) == 0) {
-                if ((stats.st_mode & S_IFMT) == S_IFDIR)
-                        return 0;
-                else
-                        return -ENOTDIR;
-        }
-
-        err = util_create_path(udev, p);
-        if (err != 0)
-                return err;
-
-        dbg(udev, "mkdir '%s'\n", p);
-        if (selinux)
-                udev_selinux_setfscreatecon(udev, p, S_IFDIR|0755);
-        err = mkdir(p, 0755);
-        if (err != 0) {
-                err = -errno;
-                if (err == -EEXIST && stat(p, &stats) == 0) {
-                        if ((stats.st_mode & S_IFMT) == S_IFDIR)
-                                err = 0;
-                        else
-                                err = -ENOTDIR;
-                }
-        }
-        if (selinux)
-                udev_selinux_resetfscreatecon(udev);
-        return err;
-}
-
-int util_create_path(struct udev *udev, const char *path)
-{
-        return create_path(udev, path, false);
-}
-
-int util_create_path_selinux(struct udev *udev, const char *path)
-{
-        return create_path(udev, path, true);
-}
-
-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++;
-        util_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;
-        size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
-        char buf[buflen];
-        struct passwd pwbuf;
-        struct passwd *pw;
-        uid_t uid;
-
-        if (strcmp(user, "root") == 0)
-                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)
-                err(udev, "specified user '%s' unknown\n", user);
-        else
-                err(udev, "error resolving user '%s': %m\n", user);
-        return 0;
-}
-
-gid_t util_lookup_group(struct udev *udev, const char *group)
-{
-        char *endptr;
-        size_t buflen = sysconf(_SC_GETGR_R_SIZE_MAX);
-        char *buf;
-        struct group grbuf;
-        struct group *gr;
-        gid_t gid = 0;
-
-        if (strcmp(group, "root") == 0)
-                return 0;
-        gid = strtoul(group, &endptr, 10);
-        if (endptr[0] == '\0')
-                return gid;
-        buf = NULL;
-        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) {
-                        err(udev, "specified group '%s' unknown\n", group);
-                } else {
-                        err(udev, "error resolving group '%s': %m\n", group);
-                }
-                break;
-        }
-        free(buf);
-        return gid;
-}
-
-/* handle "[<SUBSYSTEM>/<KERNEL>]<attribute>" 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;
-
-        util_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)
-                        util_strscpy(result, maxsize, val);
-                else
-                        result[0] = '\0';
-                info(udev, "value '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result);
-        } else {
-                size_t l;
-                char *s;
-
-                s = result;
-                l = util_strpcpyl(&s, maxsize, udev_device_get_syspath(dev), NULL);
-                if (attr != NULL)
-                        util_strpcpyl(&s, l, "/", attr, NULL);
-                info(udev, "path '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result);
-        }
-        udev_device_unref(dev);
-        return 0;
-}
diff --git a/src/udev/src/libudev-util.c b/src/udev/src/libudev-util.c
deleted file mode 100644 (file)
index 7e345f0..0000000
+++ /dev/null
@@ -1,570 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008-2011 Kay Sievers <kay.sievers@vrfy.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.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <dirent.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <time.h>
-#include <sys/stat.h>
-
-#include "libudev.h"
-#include "libudev-private.h"
-
-/**
- * SECTION:libudev-util
- * @short_description: utils
- */
-
-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;
-
-        util_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];
-        dbg(udev, "resolved link to: '%s'\n", pos);
-        return util_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';
-        dbg(udev, "path link '%s' points to '%s'\n", syspath, link_target);
-
-        for (back = 0; strncmp(&link_target[back * 3], "../", 3) == 0; back++)
-                ;
-        dbg(udev, "base '%s', tail '%s', back %i\n", syspath, &link_target[back * 3], back);
-        for (i = 0; i <= back; i++) {
-                base = strrchr(syspath, '/');
-                if (base == NULL)
-                        return -EINVAL;
-                base[0] = '\0';
-        }
-        if (base == NULL)
-                return -EINVAL;
-        dbg(udev, "after moving back '%s'\n", syspath);
-        util_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 (strncmp(priority, "err", 3) == 0)
-                return LOG_ERR;
-        if (strncmp(priority, "info", 4) == 0)
-                return LOG_INFO;
-        if (strncmp(priority, "debug", 5) == 0)
-                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;
-}
-
-size_t util_path_decode(char *s)
-{
-        size_t i, j;
-
-        for (i = 0, j = 0; s[i] != '\0'; j++) {
-                if (memcmp(&s[i], "\\x2f", 4) == 0) {
-                        s[j] = '/';
-                        i += 4;
-                } else if (memcmp(&s[i], "\\x5c", 4) == 0) {
-                        s[j] = '\\';
-                        i += 4;
-                } else {
-                        s[j] = s[i];
-                        i++;
-                }
-        }
-        s[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';
-}
-
-/*
- * Concatenates 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.
- */
-size_t util_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;
-                *dest[0] = '\0';
-        } else {
-                if (len > 0) {
-                        *dest = mempcpy(*dest, src, len);
-                        size -= len;
-                }
-                *dest[0] = '\0';
-        }
-        return size;
-}
-
-/* concatenates list of strings, moves dest forward */
-size_t util_strpcpyl(char **dest, size_t size, const char *src, ...)
-{
-        va_list va;
-
-        va_start(va, src);
-        do {
-                size = util_strpcpy(dest, size, src);
-                src = va_arg(va, char *);
-        } while (src != NULL);
-        va_end(va);
-
-        return size;
-}
-
-/* copies string */
-size_t util_strscpy(char *dest, size_t size, const char *src)
-{
-        char *s;
-
-        s = dest;
-        return util_strpcpy(&s, size, src);
-}
-
-/* concatenates list of strings */
-size_t util_strscpyl(char *dest, size_t size, const char *src, ...)
-{
-        va_list va;
-        char *s;
-
-        va_start(va, src);
-        s = dest;
-        do {
-                size = util_strpcpy(&s, size, src);
-                src = va_arg(va, char *);
-        } while (src != NULL);
-        va_end(va);
-
-        return size;
-}
-
-/* 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 */
-static 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;
-}
-
-/* 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;
-}
-
-/* check if unicode char has a valid numeric range */
-static int utf8_unichar_valid_range(int unichar)
-{
-        if (unichar > 0x10ffff)
-                return 0;
-        if ((unichar & 0xfffff800) == 0xd800)
-                return 0;
-        if ((unichar > 0xfdcf) && (unichar < 0xfdf0))
-                return 0;
-        if ((unichar & 0xffff) == 0xffff)
-                return 0;
-        return 1;
-}
-
-/* validate one encoded unicode char and return its length */
-static 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 (!utf8_unichar_valid_range(unichar))
-                return -1;
-
-        return len;
-}
-
-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;
-}
-
-static int is_whitelisted(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;
-}
-
-/* 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 (is_whitelisted(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.
- **/
-UDEV_EXPORT int udev_util_encode_string(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] == '\\' || !is_whitelisted(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;
-}
-
-/*
- * http://sites.google.com/site/murmurhash/
- *
- * All code is released to the public domain. For business purposes,
- * Murmurhash is under the MIT license.
- *
- */
-static unsigned int murmur_hash2(const char *key, int len, unsigned int seed)
-{
-        /*
-         *  'm' and 'r' are mixing constants generated offline.
-         *  They're not really 'magic', they just happen to work well.
-         */
-        const unsigned int m = 0x5bd1e995;
-        const int r = 24;
-
-        /* initialize the hash to a 'random' value */
-        unsigned int h = seed ^ len;
-
-        /* mix 4 bytes at a time into the hash */
-        const unsigned char * data = (const unsigned char *)key;
-
-        while(len >= 4) {
-                unsigned int k = *(unsigned int *)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;
-}
-
-unsigned int util_string_hash32(const char *str)
-{
-        return murmur_hash2(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;
-}
-
-#define USEC_PER_SEC  1000000ULL
-#define NSEC_PER_USEC 1000ULL
-unsigned long long ts_usec(const struct timespec *ts)
-{
-        return (unsigned long long) ts->tv_sec * USEC_PER_SEC +
-               (unsigned long long) ts->tv_nsec / NSEC_PER_USEC;
-}
-
-unsigned long long now_usec(void)
-{
-        struct timespec ts;
-
-        if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
-                return 0;
-        return ts_usec(&ts);
-}
diff --git a/src/udev/src/libudev.c b/src/udev/src/libudev.c
deleted file mode 100644 (file)
index d954dae..0000000
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.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.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <ctype.h>
-#include <time.h>
-
-#include "libudev.h"
-#include "libudev-private.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;
-        char *sys_path;
-        char *dev_path;
-        char *rules_path[4];
-        unsigned long long rules_path_ts[4];
-        int rules_path_count;
-        char *run_path;
-        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);
-}
-
-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
- **/
-UDEV_EXPORT 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.
- **/
-UDEV_EXPORT void udev_set_userdata(struct udev *udev, void *userdata)
-{
-        if (udev == NULL)
-                return;
-        udev->userdata = userdata;
-}
-
-static char *set_value(char **s, const char *v)
-{
-        free(*s);
-        *s = strdup(v);
-        util_remove_trailing_chars(*s, '/');
-        return *s;
-}
-
-/**
- * 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
- **/
-UDEV_EXPORT struct udev *udev_new(void)
-{
-        struct udev *udev;
-        const char *env;
-        char *config_file = NULL;
-        FILE *f;
-
-        udev = calloc(1, sizeof(struct udev));
-        if (udev == NULL)
-                return NULL;
-        udev->refcount = 1;
-        udev->log_fn = log_stderr;
-        udev->log_priority = LOG_ERR;
-        udev_list_init(udev, &udev->properties_list, true);
-
-        /* custom config file */
-        env = getenv("UDEV_CONFIG_FILE");
-        if (env != NULL) {
-                if (set_value(&config_file, env) == NULL)
-                        goto err;
-                udev_add_property(udev, "UDEV_CONFIG_FILE", config_file);
-        }
-
-        /* default config file */
-        if (config_file == NULL)
-                config_file = strdup(SYSCONFDIR "/udev/udev.conf");
-        if (config_file == NULL)
-                goto err;
-
-        f = fopen(config_file, "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) {
-                                err(udev, "missing <key>=<value> in '%s'[%i], skip line\n", config_file, 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]) {
-                                        err(udev, "inconsistent quoting in '%s'[%i], skip line\n", config_file, line_nr);
-                                        continue;
-                                }
-                                val[len-1] = '\0';
-                                val++;
-                        }
-
-                        if (strcmp(key, "udev_log") == 0) {
-                                udev_set_log_priority(udev, util_log_priority(val));
-                                continue;
-                        }
-                        if (strcmp(key, "udev_root") == 0) {
-                                set_value(&udev->dev_path, val);
-                                continue;
-                        }
-                        if (strcmp(key, "udev_run") == 0) {
-                                set_value(&udev->run_path, val);
-                                continue;
-                        }
-                        if (strcmp(key, "udev_sys") == 0) {
-                                set_value(&udev->sys_path, val);
-                                continue;
-                        }
-                        if (strcmp(key, "udev_rules") == 0) {
-                                set_value(&udev->rules_path[0], val);
-                                udev->rules_path_count = 1;
-                                continue;
-                        }
-                }
-                fclose(f);
-        }
-
-        /* environment overrides config */
-        env = getenv("UDEV_LOG");
-        if (env != NULL)
-                udev_set_log_priority(udev, util_log_priority(env));
-
-        /* set defaults */
-        if (udev->dev_path == NULL)
-                if (set_value(&udev->dev_path, "/dev") == NULL)
-                        goto err;
-
-        if (udev->sys_path == NULL)
-                if (set_value(&udev->sys_path, "/sys") == NULL)
-                        goto err;
-
-        if (udev->run_path == NULL)
-                if (set_value(&udev->run_path, "/run/udev") == NULL)
-                        goto err;
-
-        if (udev->rules_path[0] == NULL) {
-                /* /usr/lib/udev -- system rules */
-                udev->rules_path[0] = strdup(PKGLIBEXECDIR "/rules.d");
-                if (!udev->rules_path[0])
-                        goto err;
-
-                /* /run/udev -- runtime rules */
-                if (asprintf(&udev->rules_path[2], "%s/rules.d", udev->run_path) < 0)
-                        goto err;
-
-                /* /etc/udev -- local administration rules */
-                udev->rules_path[1] = strdup(SYSCONFDIR "/udev/rules.d");
-                if (!udev->rules_path[1])
-                        goto err;
-
-                udev->rules_path_count = 3;
-        }
-
-        dbg(udev, "context %p created\n", udev);
-        dbg(udev, "log_priority=%d\n", udev->log_priority);
-        dbg(udev, "config_file='%s'\n", config_file);
-        dbg(udev, "dev_path='%s'\n", udev->dev_path);
-        dbg(udev, "sys_path='%s'\n", udev->sys_path);
-        dbg(udev, "run_path='%s'\n", udev->run_path);
-        dbg(udev, "rules_path='%s':'%s':'%s'\n", udev->rules_path[0], udev->rules_path[1], udev->rules_path[2]);
-        free(config_file);
-        return udev;
-err:
-        free(config_file);
-        err(udev, "context creation failed\n");
-        udev_unref(udev);
-        return NULL;
-}
-
-/**
- * udev_ref:
- * @udev: udev library context
- *
- * Take a reference of the udev library context.
- *
- * Returns: the passed udev library context
- **/
-UDEV_EXPORT 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.
- *
- **/
-UDEV_EXPORT void udev_unref(struct udev *udev)
-{
-        if (udev == NULL)
-                return;
-        udev->refcount--;
-        if (udev->refcount > 0)
-                return;
-        udev_list_cleanup(&udev->properties_list);
-        free(udev->dev_path);
-        free(udev->sys_path);
-        free(udev->rules_path[0]);
-        free(udev->rules_path[1]);
-        free(udev->rules_path[2]);
-        free(udev->run_path);
-        dbg(udev, "context %p released\n", udev);
-        free(udev);
-}
-
-/**
- * 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.
- *
- **/
-UDEV_EXPORT 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;
-        info(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
- **/
-UDEV_EXPORT 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.
- **/
-UDEV_EXPORT 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);
-}
-
-int udev_get_rules_path(struct udev *udev, char **path[], unsigned long long *stamp_usec[])
-{
-        *path = udev->rules_path;
-        if (stamp_usec)
-                *stamp_usec = udev->rules_path_ts;
-        return udev->rules_path_count;
-}
-
-/**
- * udev_get_sys_path:
- * @udev: udev library context
- *
- * Retrieve the sysfs mount point. The default is "/sys". For
- * testing purposes, it can be overridden with udev_sys=
- * in the udev configuration file.
- *
- * Returns: the sys mount point
- **/
-UDEV_EXPORT const char *udev_get_sys_path(struct udev *udev)
-{
-        if (udev == NULL)
-                return NULL;
-        return udev->sys_path;
-}
-
-/**
- * udev_get_dev_path:
- * @udev: udev library context
- *
- * Retrieve the device directory path. The default value is "/dev",
- * the actual value may be overridden in the udev configuration
- * file.
- *
- * Returns: the device directory path
- **/
-UDEV_EXPORT const char *udev_get_dev_path(struct udev *udev)
-{
-        if (udev == NULL)
-                return NULL;
-        return udev->dev_path;
-}
-
-/**
- * udev_get_run_path:
- * @udev: udev library context
- *
- * Retrieve the udev runtime directory path. The default is "/run/udev".
- *
- * Returns: the runtime directory path
- **/
-UDEV_EXPORT const char *udev_get_run_path(struct udev *udev)
-{
-        if (udev == NULL)
-                return NULL;
-        return udev->run_path;
-}
-
-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/udev/src/libudev.h b/src/udev/src/libudev.h
deleted file mode 100644 (file)
index 10e098d..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008-2011 Kay Sievers <kay.sievers@vrfy.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.
- */
-
-#ifndef _LIBUDEV_H_
-#define _LIBUDEV_H_
-
-#include <stdarg.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#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);
-void 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);
-const char *udev_get_sys_path(struct udev *udev);
-const char *udev_get_dev_path(struct udev *udev);
-const char *udev_get_run_path(struct udev *udev);
-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);
-void 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_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_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);
-void 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);
-/* custom socket (use netlink and filters instead) */
-struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path);
-/* 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);
-void 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);
-void 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_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/udev/src/libudev.pc.in b/src/udev/src/libudev.pc.in
deleted file mode 100644 (file)
index c9a47fc..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-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 -lrt
-Libs.private:
-Cflags: -I${includedir}
diff --git a/src/udev/src/mtd_probe/75-probe_mtd.rules b/src/udev/src/mtd_probe/75-probe_mtd.rules
deleted file mode 100644 (file)
index c0e0839..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-# 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"
-KERNEL=="mtd*ro", ENV{MTD_FTL}=="smartmedia", IMPORT{builtin}="kmod load sm_ftl"
-
-LABEL="mtd_probe_end"
diff --git a/src/udev/src/mtd_probe/mtd_probe.c b/src/udev/src/mtd_probe/mtd_probe.c
deleted file mode 100644 (file)
index 1aa08d3..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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 <stdio.h>
-#include <sys/ioctl.h>
-#include <mtd/mtd-user.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-
-int main(int argc, char** argv)
-{
-        if (argc != 2) {
-                printf("usage: mtd_probe /dev/mtd[n]\n");
-                return 1;
-        }
-
-        int mtd_fd = open(argv[1], O_RDONLY);
-        if (mtd_fd == -1) {
-                perror("open");
-                exit(-1);
-        }
-
-        mtd_info_t mtd_info;
-        int 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/src/mtd_probe/mtd_probe.h b/src/udev/src/mtd_probe/mtd_probe.h
deleted file mode 100644 (file)
index 2a37ede..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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/mtd-user.h>
-
-/* 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/src/mtd_probe/probe_smartmedia.c b/src/udev/src/mtd_probe/probe_smartmedia.c
deleted file mode 100644 (file)
index b3cdefc..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * 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 <stdio.h>
-#include <stdlib.h>
-#include <mtd/mtd-user.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <stdlib.h>
-#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)
-{
-        char* cis_buffer = malloc(SM_SECTOR_SIZE);
-
-        if (!cis_buffer)
-                return;
-
-        if (info->type != MTD_NANDFLASH)
-                goto exit;
-
-        int sector_size = info->writesize;
-        int block_size = info->erasesize;
-        int size_in_megs = info->size / (1024 * 1024);
-        int spare_count;
-
-
-        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;
-        }
-
-
-        int offset;
-        int cis_found = 0;
-
-        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/src/rule_generator/75-cd-aliases-generator.rules b/src/udev/src/rule_generator/75-cd-aliases-generator.rules
deleted file mode 100644 (file)
index e6da010..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-# these rules generate rules for the /dev/{cdrom,dvd,...} symlinks
-
-# the "path" of usb/ieee1394 devices changes frequently, use "id"
-ACTION=="add", SUBSYSTEM=="block", SUBSYSTEMS=="usb|ieee1394", ENV{ID_CDROM}=="?*", ENV{GENERATED}!="?*", \
-  PROGRAM="write_cd_rules by-id", SYMLINK+="%c", GOTO="persistent_cd_end"
-
-ACTION=="add", SUBSYSTEM=="block", ENV{ID_CDROM}=="?*", ENV{GENERATED}!="?*", PROGRAM="write_cd_rules", SYMLINK+="%c"
-
-LABEL="persistent_cd_end"
diff --git a/src/udev/src/rule_generator/75-persistent-net-generator.rules b/src/udev/src/rule_generator/75-persistent-net-generator.rules
deleted file mode 100644 (file)
index 4f80573..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-# do not edit this file, it will be overwritten on update
-
-# these rules generate rules for persistent network device naming
-#
-# variables used to communicate:
-#   MATCHADDR             MAC address used for the match
-#   MATCHID               bus_id used for the match
-#   MATCHDRV              driver name used for the match
-#   MATCHIFTYPE           interface type match
-#   COMMENT               comment to add to the generated rule
-#   INTERFACE_NAME        requested name supplied by external tool
-#   INTERFACE_NEW         new interface name returned by rule writer
-
-ACTION!="add", GOTO="persistent_net_generator_end"
-SUBSYSTEM!="net", GOTO="persistent_net_generator_end"
-
-# ignore the interface if a name has already been set
-NAME=="?*", GOTO="persistent_net_generator_end"
-
-# device name whitelist
-KERNEL!="eth*|ath*|wlan*[0-9]|msh*|ra*|sta*|ctc*|lcs*|hsi*", GOTO="persistent_net_generator_end"
-
-# ignore Xen virtual interfaces
-SUBSYSTEMS=="xen", GOTO="persistent_net_generator_end"
-
-# read MAC address
-ENV{MATCHADDR}="$attr{address}"
-
-# match interface type
-ENV{MATCHIFTYPE}="$attr{type}"
-
-# ignore KVM virtual interfaces
-ENV{MATCHADDR}=="52:54:00:*", GOTO="persistent_net_generator_end"
-# ignore VMWare virtual interfaces
-ENV{MATCHADDR}=="00:0c:29:*|00:50:56:*", GOTO="persistent_net_generator_end"
-# ignore Hyper-V virtual interfaces
-ENV{MATCHADDR}=="00:15:5d:*", GOTO="persistent_net_generator_end"
-
-# These vendors are known to violate the local MAC address assignment scheme
-# Interlan, DEC (UNIBUS or QBUS), Apollo, Cisco, Racal-Datacom
-ENV{MATCHADDR}=="02:07:01:*", GOTO="globally_administered_whitelist"
-# 3Com
-ENV{MATCHADDR}=="02:60:60:*", GOTO="globally_administered_whitelist"
-# 3Com IBM PC; Imagen; Valid; Cisco; Apple
-ENV{MATCHADDR}=="02:60:8c:*", GOTO="globally_administered_whitelist"
-# Intel
-ENV{MATCHADDR}=="02:a0:c9:*", GOTO="globally_administered_whitelist"
-# Olivetti
-ENV{MATCHADDR}=="02:aa:3c:*", GOTO="globally_administered_whitelist"
-# CMC Masscomp; Silicon Graphics; Prime EXL
-ENV{MATCHADDR}=="02:cf:1f:*", GOTO="globally_administered_whitelist"
-# Prominet Corporation Gigabit Ethernet Switch
-ENV{MATCHADDR}=="02:e0:3b:*", GOTO="globally_administered_whitelist"
-# BTI (Bus-Tech, Inc.) IBM Mainframes
-ENV{MATCHADDR}=="02:e6:d3:*", GOTO="globally_administered_whitelist"
-# Realtek
-ENV{MATCHADDR}=="52:54:00:*", GOTO="globally_administered_whitelist"
-# Novell 2000
-ENV{MATCHADDR}=="52:54:4c:*", GOTO="globally_administered_whitelist"
-# Realtec
-ENV{MATCHADDR}=="52:54:ab:*", GOTO="globally_administered_whitelist"
-# Kingston Technologies
-ENV{MATCHADDR}=="e2:0c:0f:*", GOTO="globally_administered_whitelist"
-# Xensource
-ENV{MATCHADDR}=="00:16:3e:*", GOTO="globally_administered_whitelist"
-
-# match interface dev_id
-ATTR{dev_id}=="?*", ENV{MATCHDEVID}="$attr{dev_id}"
-
-# do not use "locally administered" MAC address
-ENV{MATCHADDR}=="?[2367abef]:*", ENV{MATCHADDR}=""
-
-# do not use empty address
-ENV{MATCHADDR}=="00:00:00:00:00:00", ENV{MATCHADDR}=""
-
-LABEL="globally_administered_whitelist"
-
-# build comment line for generated rule:
-SUBSYSTEMS=="pci", ENV{COMMENT}="PCI device $attr{vendor}:$attr{device} ($driver)"
-SUBSYSTEMS=="usb", ATTRS{idVendor}=="?*", ENV{COMMENT}="USB device 0x$attr{idVendor}:0x$attr{idProduct} ($driver)"
-SUBSYSTEMS=="pcmcia", ENV{COMMENT}="PCMCIA device $attr{card_id}:$attr{manf_id} ($driver)"
-SUBSYSTEMS=="ieee1394", ENV{COMMENT}="Firewire device $attr{host_id})"
-
-# ibmveth likes to use "locally administered" MAC addresses
-DRIVERS=="ibmveth", ENV{MATCHADDR}="$attr{address}", ENV{COMMENT}="ibmveth ($id)"
-
-# S/390 uses id matches only, do not use MAC address match
-SUBSYSTEMS=="ccwgroup", ENV{COMMENT}="S/390 $driver device at $id", ENV{MATCHID}="$id", ENV{MATCHDRV}="$driver", ENV{MATCHADDR}=""
-
-# see if we got enough data to create a rule
-ENV{MATCHADDR}=="", ENV{MATCHID}=="", ENV{INTERFACE_NAME}=="", GOTO="persistent_net_generator_end"
-
-# default comment
-ENV{COMMENT}=="", ENV{COMMENT}="net device ($attr{driver})"
-
-# write rule
-DRIVERS=="?*", IMPORT{program}="write_net_rules"
-
-# rename interface if needed
-ENV{INTERFACE_NEW}=="?*", NAME="$env{INTERFACE_NEW}"
-
-LABEL="persistent_net_generator_end"
diff --git a/src/udev/src/rule_generator/rule_generator.functions b/src/udev/src/rule_generator/rule_generator.functions
deleted file mode 100644 (file)
index 2eec1b6..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-# functions used by the udev rule generator
-
-# Copyright (C) 2006 Marco d'Itri <md@Linux.IT>
-
-# 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 <http://www.gnu.org/licenses/>.
-
-PATH='/usr/bin:/bin:/usr/sbin:/sbin'
-
-# Read a single line from file $1 in the $DEVPATH directory.
-# The function must not return an error even if the file does not exist.
-sysread() {
-        local file="$1"
-        [ -e "/sys$DEVPATH/$file" ] || return 0
-        local value
-        read value < "/sys$DEVPATH/$file" || return 0
-        echo "$value"
-}
-
-sysreadlink() {
-        local file="$1"
-        [ -e "/sys$DEVPATH/$file" ] || return 0
-        readlink -f /sys$DEVPATH/$file 2> /dev/null || true
-}
-
-# Return true if a directory is writeable.
-writeable() {
-        if ln -s test-link $1/.is-writeable 2> /dev/null; then
-                rm -f $1/.is-writeable
-                return 0
-        else
-                return 1
-        fi
-}
-
-# Create a lock file for the current rules file.
-lock_rules_file() {
-        RUNDIR=$(udevadm info --run)
-        [ -e "$RUNDIR" ] || return 0
-
-        RULES_LOCK="$RUNDIR/.lock-${RULES_FILE##*/}"
-
-        retry=30
-        while ! mkdir $RULES_LOCK 2> /dev/null; do
-                if [ $retry -eq 0 ]; then
-                         echo "Cannot lock $RULES_FILE!" >&2
-                         exit 2
-                fi
-                sleep 1
-                retry=$(($retry - 1))
-        done
-}
-
-unlock_rules_file() {
-        [ "$RULES_LOCK" ] || return 0
-        rmdir $RULES_LOCK || true
-}
-
-# Choose the real rules file if it is writeable or a temporary file if not.
-# Both files should be checked later when looking for existing rules.
-choose_rules_file() {
-        RUNDIR=$(udevadm info --run)
-        local tmp_rules_file="$RUNDIR/tmp-rules--${RULES_FILE##*/}"
-        [ -e "$RULES_FILE" -o -e "$tmp_rules_file" ] || PRINT_HEADER=1
-
-        if writeable ${RULES_FILE%/*}; then
-                RO_RULES_FILE='/dev/null'
-        else
-                RO_RULES_FILE=$RULES_FILE
-                RULES_FILE=$tmp_rules_file
-        fi
-}
-
-# Return the name of the first free device.
-raw_find_next_available() {
-        local links="$1"
-
-        local basename=${links%%[ 0-9]*}
-        local max=-1
-        for name in $links; do
-                local num=${name#$basename}
-                [ "$num" ] || num=0
-                [ $num -gt $max ] && max=$num
-        done
-
-        local max=$(($max + 1))
-        # "name0" actually is just "name"
-        [ $max -eq 0 ] && return
-        echo "$max"
-}
-
-# Find all rules matching a key (with action) and a pattern.
-find_all_rules() {
-        local key="$1"
-        local linkre="$2"
-        local match="$3"
-
-        local search='.*[[:space:],]'"$key"'"('"$linkre"')".*'
-        echo $(sed -n -r -e 's/^#.*//' -e "${match}s/${search}/\1/p" \
-                $RO_RULES_FILE \
-                $([ -e $RULES_FILE ] && echo $RULES_FILE) \
-                2>/dev/null)
-}
diff --git a/src/udev/src/rule_generator/write_cd_rules b/src/udev/src/rule_generator/write_cd_rules
deleted file mode 100644 (file)
index 645b9cd..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-#!/bin/sh -e
-
-# This script is run if an optical drive lacks a rule for persistent naming.
-#
-# It adds symlinks for optical drives based on the device class determined
-# by cdrom_id and used ID_PATH to identify the device.
-
-# (C) 2006 Marco d'Itri <md@Linux.IT>
-#
-# 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 <http://www.gnu.org/licenses/>.
-
-# debug, if UDEV_LOG=<debug>
-if [ -n "$UDEV_LOG" ]; then
-        if [ "$UDEV_LOG" -ge 7 ]; then
-                set -x
-        fi
-fi
-
-RULES_FILE="/etc/udev/rules.d/70-persistent-cd.rules"
-
-. /lib/udev/rule_generator.functions
-
-find_next_available() {
-        raw_find_next_available "$(find_all_rules 'SYMLINK\+=' "$1")"
-}
-
-write_rule() {
-        local match="$1"
-        local link="$2"
-        local comment="$3"
-
-        {
-        if [ "$PRINT_HEADER" ]; then
-                PRINT_HEADER=
-                echo "# This file was automatically generated by the $0"
-                echo "# program, run by the cd-aliases-generator.rules rules file."
-                echo "#"
-                echo "# You can modify it, as long as you keep each rule on a single"
-                echo "# line, and set the \$GENERATED variable."
-                echo ""
-        fi
-
-        [ "$comment" ] && echo "# $comment"
-        echo "$match, SYMLINK+=\"$link\", ENV{GENERATED}=\"1\""
-        } >> $RULES_FILE
-        SYMLINKS="$SYMLINKS $link"
-}
-
-if [ -z "$DEVPATH" ]; then
-        echo "Missing \$DEVPATH." >&2
-        exit 1
-fi
-if [ -z "$ID_CDROM" ]; then
-        echo "$DEVPATH is not a CD reader." >&2
-        exit 1
-fi
-
-if [ "$1" ]; then
-        METHOD="$1"
-else
-        METHOD='by-path'
-fi
-
-case "$METHOD" in
-        by-path)
-        if [ -z "$ID_PATH" ]; then
-                echo "$DEVPATH not supported by path_id. by-id may work." >&2
-                exit 1
-        fi
-        RULE="ENV{ID_PATH}==\"$ID_PATH\""
-        ;;
-
-        by-id)
-        if [ "$ID_SERIAL" ]; then
-                RULE="ENV{ID_SERIAL}==\"$ID_SERIAL\""
-        elif [ "$ID_MODEL" -a "$ID_REVISION" ]; then
-                RULE="ENV{ID_MODEL}==\"$ID_MODEL\", ENV{ID_REVISION}==\"$ID_REVISION\""
-        else
-                echo "$DEVPATH not supported by ata_id. by-path may work." >&2
-                exit 1
-        fi
-        ;;
-
-        *)
-        echo "Invalid argument (must be either by-path or by-id)." >&2
-        exit 1
-        ;;
-esac
-
-# Prevent concurrent processes from modifying the file at the same time.
-lock_rules_file
-
-# Check if the rules file is writeable.
-choose_rules_file
-
-link_num=$(find_next_available 'cdrom[0-9]*')
-
-match="SUBSYSTEM==\"block\", ENV{ID_CDROM}==\"?*\", $RULE"
-
-comment="$ID_MODEL ($ID_PATH)"
-
-        write_rule "$match" "cdrom$link_num" "$comment"
-[ "$ID_CDROM_CD_R" -o "$ID_CDROM_CD_RW" ] && \
-        write_rule "$match" "cdrw$link_num"
-[ "$ID_CDROM_DVD" ] && \
-        write_rule "$match" "dvd$link_num"
-[ "$ID_CDROM_DVD_R" -o "$ID_CDROM_DVD_RW" -o "$ID_CDROM_DVD_RAM" ] && \
-        write_rule "$match" "dvdrw$link_num"
-echo >> $RULES_FILE
-
-unlock_rules_file
-
-echo $SYMLINKS
-
-exit 0
diff --git a/src/udev/src/rule_generator/write_net_rules b/src/udev/src/rule_generator/write_net_rules
deleted file mode 100644 (file)
index bcea4b0..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-#!/bin/sh -e
-
-# This script is run to create persistent network device naming rules
-# based on properties of the device.
-# If the interface needs to be renamed, INTERFACE_NEW=<name> will be printed
-# on stdout to allow udev to IMPORT it.
-
-# variables used to communicate:
-#   MATCHADDR             MAC address used for the match
-#   MATCHID               bus_id used for the match
-#   MATCHDEVID            dev_id used for the match
-#   MATCHDRV              driver name used for the match
-#   MATCHIFTYPE           interface type match
-#   COMMENT               comment to add to the generated rule
-#   INTERFACE_NAME        requested name supplied by external tool
-#   INTERFACE_NEW         new interface name returned by rule writer
-
-# Copyright (C) 2006 Marco d'Itri <md@Linux.IT>
-# Copyright (C) 2007 Kay Sievers <kay.sievers@vrfy.org>
-#
-# 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 <http://www.gnu.org/licenses/>.
-
-# debug, if UDEV_LOG=<debug>
-if [ -n "$UDEV_LOG" ]; then
-        if [ "$UDEV_LOG" -ge 7 ]; then
-                set -x
-        fi
-fi
-
-RULES_FILE='/etc/udev/rules.d/70-persistent-net.rules'
-
-. /lib/udev/rule_generator.functions
-
-interface_name_taken() {
-        local value="$(find_all_rules 'NAME=' $INTERFACE)"
-        if [ "$value" ]; then
-                return 0
-        else
-                return 1
-        fi
-}
-
-find_next_available() {
-        raw_find_next_available "$(find_all_rules 'NAME=' "$1")"
-}
-
-write_rule() {
-        local match="$1"
-        local name="$2"
-        local comment="$3"
-
-        {
-        if [ "$PRINT_HEADER" ]; then
-                PRINT_HEADER=
-                echo "# This file was automatically generated by the $0"
-                echo "# program, run by the persistent-net-generator.rules rules file."
-                echo "#"
-                echo "# You can modify it, as long as you keep each rule on a single"
-                echo "# line, and change only the value of the NAME= key."
-        fi
-
-        echo ""
-        [ "$comment" ] && echo "# $comment"
-        echo "SUBSYSTEM==\"net\", ACTION==\"add\"$match, NAME=\"$name\""
-        } >> $RULES_FILE
-}
-
-if [ -z "$INTERFACE" ]; then
-        echo "missing \$INTERFACE" >&2
-        exit 1
-fi
-
-# Prevent concurrent processes from modifying the file at the same time.
-lock_rules_file
-
-# Check if the rules file is writeable.
-choose_rules_file
-
-# the DRIVERS key is needed to not match bridges and VLAN sub-interfaces
-if [ "$MATCHADDR" ]; then
-        match="$match, DRIVERS==\"?*\", ATTR{address}==\"$MATCHADDR\""
-fi
-
-if [ "$MATCHDRV" ]; then
-        match="$match, DRIVERS==\"$MATCHDRV\""
-fi
-
-if [ "$MATCHDEVID" ]; then
-        match="$match, ATTR{dev_id}==\"$MATCHDEVID\""
-fi
-
-if [ "$MATCHID" ]; then
-        match="$match, KERNELS==\"$MATCHID\""
-fi
-
-if [ "$MATCHIFTYPE" ]; then
-        match="$match, ATTR{type}==\"$MATCHIFTYPE\""
-fi
-
-if [ -z "$match" ]; then
-        echo "missing valid match" >&2
-        unlock_rules_file
-        exit 1
-fi
-
-basename=${INTERFACE%%[0-9]*}
-match="$match, KERNEL==\"$basename*\""
-
-if [ "$INTERFACE_NAME" ]; then
-        # external tools may request a custom name
-        COMMENT="$COMMENT (custom name provided by external tool)"
-        if [ "$INTERFACE_NAME" != "$INTERFACE" ]; then
-                INTERFACE=$INTERFACE_NAME;
-                echo "INTERFACE_NEW=$INTERFACE"
-        fi
-else
-        # if a rule using the current name already exists, find a new name
-        if interface_name_taken; then
-                INTERFACE="$basename$(find_next_available "$basename[0-9]*")"
-                # prevent INTERFACE from being "eth" instead of "eth0"
-                [ "$INTERFACE" = "${INTERFACE%%[ \[\]0-9]*}" ] && INTERFACE=${INTERFACE}0
-                echo "INTERFACE_NEW=$INTERFACE"
-        fi
-fi
-
-write_rule "$match" "$INTERFACE" "$COMMENT"
-
-unlock_rules_file
-
-exit 0
diff --git a/src/udev/src/scsi_id/.gitignore b/src/udev/src/scsi_id/.gitignore
deleted file mode 100644 (file)
index 6aebddd..0000000
+++ /dev/null
@@ -1 +0,0 @@
-scsi_id_version.h
diff --git a/src/udev/src/scsi_id/README b/src/udev/src/scsi_id/README
deleted file mode 100644 (file)
index 9cfe739..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-scsi_id - generate a SCSI unique identifier for a given SCSI device
-
-Please send questions, comments or patches to <patmans@us.ibm.com> or
-<linux-hotplug-devel@lists.sourceforge.net>.
diff --git a/src/udev/src/scsi_id/scsi.h b/src/udev/src/scsi_id/scsi.h
deleted file mode 100644 (file)
index c423cac..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * 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 <scsi/scsi.h>
-
-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 <scsi/scsi.h>) 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/src/scsi_id/scsi_id.8 b/src/udev/src/scsi_id/scsi_id.8
deleted file mode 100644 (file)
index 0d4dba9..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-.TH SCSI_ID 8 "December 2003" "" "Linux Administrator's Manual"
-.SH NAME
-scsi_id \- retrieve and generate a unique SCSI identifier
-.SH SYNOPSIS
-.BI scsi_id
-[\fIoptions\fP]
-.SH "DESCRIPTION"
-.B scsi_id
-queries a SCSI device via the SCSI INQUIRY vital product data (VPD) page 0x80 or
-0x83 and uses the resulting data to generate a value that is unique across
-all SCSI devices that properly support page 0x80 or page 0x83.
-
-If a result is generated it is sent to standard output, and the program
-exits with a zero value. If no identifier is output, the program exits
-with a non\-zero value.
-
-\fBscsi_id\fP is primarily for use by other utilities such as \fBudev\fP
-that require a unique SCSI identifier.
-
-By default all devices are assumed black listed, the \fB\-\-whitelisted\fP option must
-be specified on the command line or in the config file for any useful
-behaviour.
-
-SCSI commands are sent directly to the device via the SG_IO ioctl
-interface.
-
-In order to generate unique values for either page 0x80 or page 0x83, the
-serial numbers or world wide names are prefixed as follows.
-
-Identifiers based on page 0x80 are prefixed by the character 'S', the SCSI
-vendor, the SCSI product (model) and then the the serial number returned
-by page 0x80. For example:
-
-.sp
-.nf
-# /usr/lib/udev/scsi_id \-\-page=0x80 \-\-whitelisted \-\-device=/dev/sda
-SIBM     3542           1T05078453
-.fi
-.P
-
-Identifiers based on page 0x83 are prefixed by the identifier type
-followed by the page 0x83 identifier. For example, a device with a NAA
-(Name Address Authority) type of 3 (also in this case the page 0x83
-identifier starts with the NAA value of 6):
-
-.sp
-.nf
-# /usr/lib/udev/scsi_id \-\-page=0x83 \-\-whitelisted \-\-device=/dev/sda
-3600a0b80000b174b000000d63efc5c8c
-.fi
-.P
-
-.SH OPTIONS
-.TP
-.BI \-\-blacklisted
-The default behaviour \- treat the device as black listed, and do nothing
-unless a white listed device is found in the scsi_id config\-file.
-.TP
-.BI \-\-device=\| device\^
-Send SG_IO commands to \fBdevice\fP, such as \fB/dev/sdc\fP.
-.TP
-.BI \-\-config=\| config\-file
-Read configuration and black/white list entries from
-.B config\-file
-rather than the default
-.B /etc/scsi_id.config
-file.
-.TP
-.BI \-\-whitelisted
-Treat the device as white listed. The \fB\-\-whitelisted\fP option must be specified
-on the command line or in the scsi_id configuration file for
-.B scsi_id
-to generate any output.
-.TP
-.BI \-\-page=\| 0x80 | 0x83 | pre-spc3-83
-Use SCSI INQUIRY VPD page code 0x80, 0x83, or pre-spc3-83.
-.sp
-The default
-behaviour is to query the available VPD pages, and use page 0x83 if found,
-else page 0x80 if found, else nothing.
-.sp
-Page pre-spc3-83 should only be utilized for those scsi devices which
-are not compliant with the SPC-2 or SPC-3 format for page 83.  While this
-option is used for older model 4, 5, and 6 EMC Symmetrix devices, its
-use with SPC-2 or SPC-3 compliant devices will fallback to the page 83
-format supported by these devices.
-.TP
-.BI \-\-replace-whitespace
-Reformat the output : replace all whitespaces by underscores.
-.TP
-.BI \-\-export
-Export all data in KEY=<value> format used to import in other programs.
-.TP
-.BI \-\-verbose
-Generate verbose debugging output.
-.TP
-.BI \-\-version
-Display version number and exit.
-.RE
-
-.SH "FILES"
-.nf
-.ft B
-.ft
-.TP
-\fI/etc/scsi_id.config\fP
-Configuration of black/white list entries and per device options:
-# one config per line, short match strings match longer strings
-# vendor=string[,model=string],options=<per-device scsi_id command line options>
-vendor="ATA",options=-p 0x80
-.RE
-.fi
-.LP
-.SH "SEE ALSO"
-.BR udev (7)
-.SH AUTHORS
-Developed by Patrick Mansfield <patmans@us.ibm.com> based on SCSI ID
-source included in earlier linux 2.5 kernels, sg_utils source, and SCSI
-specifications.
diff --git a/src/udev/src/scsi_id/scsi_id.c b/src/udev/src/scsi_id/scsi_id.c
deleted file mode 100644 (file)
index 9bb0d7f..0000000
+++ /dev/null
@@ -1,657 +0,0 @@
-/*
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <string.h>
-#include <syslog.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <getopt.h>
-#include <sys/stat.h>
-
-#include "libudev.h"
-#include "libudev-private.h"
-#include "scsi_id.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' },
-        { "export", no_argument, NULL, 'x' },
-        { "help", no_argument, NULL, 'h' },
-        {}
-};
-
-static const char short_options[] = "d:f:ghip:uvVx";
-static const char dev_short_options[] = "bgp:";
-
-static int all_good;
-static int dev_specified;
-static char config_file[MAX_PATH_LEN] = SYSCONFDIR "/scsi_id.config";
-static enum page_code default_page_code;
-static int sg_version = 4;
-static int use_stderr;
-static int debug;
-static int reformat_serial;
-static int export;
-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];
-
-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;
-        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;
-                }
-        }
-        util_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 char *quote_string = "\"\n";
-        static char *comma_string = ",\n";
-        char *val;
-        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;
-        FILE *fd;
-        char *buf;
-        char *str1;
-        char *vendor_in, *model_in, *options_in; /* read in from file */
-        int lineno;
-        int c;
-        int retval = 0;
-
-        dbg(udev, "vendor='%s'; model='%s'\n", vendor, model);
-        fd = fopen(config_file, "r");
-        if (fd == NULL) {
-                dbg(udev, "can't open %s\n", config_file);
-                if (errno == ENOENT) {
-                        return 1;
-                } else {
-                        err(udev, "can't open %s: %s\n", config_file, strerror(errno));
-                        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) {
-                fclose(fd);
-                err(udev, "can't allocate memory\n");
-                return -1;
-        }
-
-        *newargv = NULL;
-        lineno = 0;
-        while (1) {
-                vendor_in = model_in = options_in = NULL;
-
-                buf = fgets(buffer, MAX_BUFFER_LEN, fd);
-                if (buf == NULL)
-                        break;
-                lineno++;
-                if (buf[strlen(buffer) - 1] != '\n') {
-                        err(udev, "Config file line %d too long\n", lineno);
-                        break;
-                }
-
-                while (isspace(*buf))
-                        buf++;
-
-                /* blank or all whitespace line */
-                if (*buf == '\0')
-                        continue;
-
-                /* comment line */
-                if (*buf == '#')
-                        continue;
-
-                dbg(udev, "lineno %d: '%s'\n", lineno, buf);
-                str1 = strsep(&buf, "=");
-                if (str1 && strcasecmp(str1, "VENDOR") == 0) {
-                        str1 = get_value(&buf);
-                        if (!str1) {
-                                retval = -1;
-                                break;
-                        }
-                        vendor_in = str1;
-
-                        str1 = strsep(&buf, "=");
-                        if (str1 && strcasecmp(str1, "MODEL") == 0) {
-                                str1 = get_value(&buf);
-                                if (!str1) {
-                                        retval = -1;
-                                        break;
-                                }
-                                model_in = str1;
-                                str1 = strsep(&buf, "=");
-                        }
-                }
-
-                if (str1 && strcasecmp(str1, "OPTIONS") == 0) {
-                        str1 = get_value(&buf);
-                        if (!str1) {
-                                retval = -1;
-                                break;
-                        }
-                        options_in = str1;
-                }
-                dbg(udev, "config file line %d:\n"
-                        " vendor '%s'; model '%s'; options '%s'\n",
-                        lineno, vendor_in, model_in, options_in);
-                /*
-                 * Only allow: [vendor=foo[,model=bar]]options=stuff
-                 */
-                if (!options_in || (!vendor_in && model_in)) {
-                        err(udev, "Error parsing config file line %d '%s'\n", lineno, buffer);
-                        retval = -1;
-                        break;
-                }
-                if (vendor == NULL) {
-                        if (vendor_in == NULL) {
-                                dbg(udev, "matched global option\n");
-                                break;
-                        }
-                } else if ((vendor_in && strncmp(vendor, vendor_in,
-                                                 strlen(vendor_in)) == 0) &&
-                           (!model_in || (strncmp(model, model_in,
-                                                  strlen(model_in)) == 0))) {
-                                /*
-                                 * Matched vendor and optionally model.
-                                 *
-                                 * Note: a short vendor_in or model_in can
-                                 * give a partial match (that is FOO
-                                 * matches FOOBAR).
-                                 */
-                                dbg(udev, "matched vendor/model\n");
-                                break;
-                } else {
-                        dbg(udev, "no match\n");
-                }
-        }
-
-        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) {
-                                err(udev, "can't allocate memory\n");
-                                retval = -1;
-                        } 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);
-        fclose(fd);
-        return retval;
-}
-
-static int set_options(struct udev *udev,
-                       int argc, char **argv, const char *short_opts,
-                       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 (1) {
-                option = getopt_long(argc, argv, short_opts, options, NULL);
-                if (option == -1)
-                        break;
-
-                if (optarg)
-                        dbg(udev, "option '%c' arg '%s'\n", option, optarg);
-                else
-                        dbg(udev, "option '%c'\n", option);
-
-                switch (option) {
-                case 'b':
-                        all_good = 0;
-                        break;
-
-                case 'd':
-                        dev_specified = 1;
-                        util_strscpy(maj_min_dev, MAX_PATH_LEN, optarg);
-                        break;
-
-                case 'e':
-                        use_stderr = 1;
-                        break;
-
-                case 'f':
-                        util_strscpy(config_file, MAX_PATH_LEN, optarg);
-                        break;
-
-                case 'g':
-                        all_good = 1;
-                        break;
-
-                case 'h':
-                        printf("Usage: scsi_id OPTIONS <device>\n"
-                               "  --device=                     device node for SG_IO commands\n"
-                               "  --config=                     location of config file\n"
-                               "  --page=0x80|0x83|pre-spc3-83  SCSI page (0x80, 0x83, pre-spc3-83)\n"
-                               "  --sg-version=3|4              use SGv3 or SGv4\n"
-                               "  --blacklisted                 threat device as blacklisted\n"
-                               "  --whitelisted                 threat device as whitelisted\n"
-                               "  --replace-whitespace          replace all whitespaces by underscores\n"
-                               "  --verbose                     verbose logging\n"
-                               "  --version                     print version\n"
-                               "  --export                      print values as environment keys\n"
-                               "  --help                        print this help text\n\n");
-                        exit(0);
-
-                case 'p':
-                        if (strcmp(optarg, "0x80") == 0) {
-                                default_page_code = PAGE_80;
-                        } else if (strcmp(optarg, "0x83") == 0) {
-                                default_page_code = PAGE_83;
-                        } else if (strcmp(optarg, "pre-spc3-83") == 0) {
-                                default_page_code = PAGE_83_PRE_SPC3;
-                        } else {
-                                err(udev, "Unknown page code '%s'\n", optarg);
-                                return -1;
-                        }
-                        break;
-
-                case 's':
-                        sg_version = atoi(optarg);
-                        if (sg_version < 3 || sg_version > 4) {
-                                err(udev, "Unknown SG version '%s'\n", optarg);
-                                return -1;
-                        }
-                        break;
-
-                case 'u':
-                        reformat_serial = 1;
-                        break;
-
-                case 'x':
-                        export = 1;
-                        break;
-
-                case 'v':
-                        debug++;
-                        break;
-
-                case 'V':
-                        printf("%s\n", VERSION);
-                        exit(0);
-                        break;
-
-                default:
-                        exit(1);
-                }
-        }
-        if (optind < argc && !dev_specified) {
-                dev_specified = 1;
-                util_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, dev_short_options, options, NULL);
-                if (option == -1)
-                        break;
-
-                if (optarg)
-                        dbg(udev, "option '%c' arg '%s'\n", option, optarg);
-                else
-                        dbg(udev, "option '%c'\n", option);
-
-                switch (option) {
-                case 'b':
-                        *good_bad = 0;
-                        break;
-
-                case 'g':
-                        *good_bad = 1;
-                        break;
-
-                case 'p':
-                        if (strcmp(optarg, "0x80") == 0) {
-                                *page_code = PAGE_80;
-                        } else if (strcmp(optarg, "0x83") == 0) {
-                                *page_code = PAGE_83;
-                        } else if (strcmp(optarg, "pre-spc3-83") == 0) {
-                                *page_code = PAGE_83_PRE_SPC3;
-                        } else {
-                                err(udev, "Unknown page code '%s'\n", optarg);
-                                retval = -1;
-                        }
-                        break;
-
-                default:
-                        err(udev, "Unknown or bad option '%c' (0x%x)\n", 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;
-
-        memset(&dev_scsi, 0x00, sizeof(struct scsi_id_device));
-
-        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);
-        dbg(udev, "per dev options: good %d; page code 0x%x\n", 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)
-{
-        struct udev *udev;
-        int retval = 0;
-        char maj_min_dev[MAX_PATH_LEN];
-        int newargc;
-        char **newargv;
-
-        udev = udev_new();
-        if (udev == NULL)
-                goto exit;
-
-        udev_log_init("scsi_id");
-        udev_set_log_fn(udev, log_fn);
-
-        /*
-         * Get config file options.
-         */
-        newargv = NULL;
-        retval = get_file_options(udev, NULL, NULL, &newargc, &newargv);
-        if (retval < 0) {
-                retval = 1;
-                goto exit;
-        }
-        if (newargv && (retval == 0)) {
-                if (set_options(udev, newargc, newargv, short_options, maj_min_dev) < 0) {
-                        retval = 2;
-                        goto exit;
-                }
-                free(newargv);
-        }
-
-        /*
-         * Get command line options (overriding any config file settings).
-         */
-        if (set_options(udev, argc, argv, short_options, maj_min_dev) < 0)
-                exit(1);
-
-        if (!dev_specified) {
-                err(udev, "no device specified\n");
-                retval = 1;
-                goto exit;
-        }
-
-        retval = scsi_id(udev, maj_min_dev);
-
-exit:
-        udev_unref(udev);
-        udev_log_close();
-        return retval;
-}
diff --git a/src/udev/src/scsi_id/scsi_id.h b/src/udev/src/scsi_id/scsi_id.h
deleted file mode 100644 (file)
index 828a983..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#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];
-};
-
-extern int scsi_std_inquiry(struct udev *udev, struct scsi_id_device *dev_scsi, const char *devname);
-extern 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/src/scsi_id/scsi_serial.c b/src/udev/src/scsi_id/scsi_serial.c
deleted file mode 100644 (file)
index f1d63f4..0000000
+++ /dev/null
@@ -1,990 +0,0 @@
-/*
- * Copyright (C) IBM Corp. 2003
- *
- * Author: Patrick Mansfield<patmans@us.ibm.com>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <syslog.h>
-#include <time.h>
-#include <inttypes.h>
-#include <scsi/scsi.h>
-#include <scsi/sg.h>
-#include <linux/types.h>
-#include <linux/bsg.h>
-
-#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.
-         */
-
-        dbg(udev, "got check condition\n");
-
-        if (sb_len < 1) {
-                info(udev, "%s: sense buffer empty\n", 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) {
-                        info(udev, "%s: sense buffer too small %d bytes, %d bytes too short\n",
-                            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?
-                                 */
-                                info(udev, "%s: sense result too" " small %d bytes\n",
-                                    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 {
-                        info(udev, "%s: invalid sense code 0x%x\n",
-                            dev_scsi->kernel, code);
-                        return -1;
-                }
-                info(udev, "%s: sense key 0x%x ASC 0x%x ASCQ 0x%x\n",
-                    dev_scsi->kernel, sense_key, asc, ascq);
-        } else {
-                if (sb_len < 4) {
-                        info(udev, "%s: sense buffer too small %d bytes, %d bytes too short\n",
-                            dev_scsi->kernel, sb_len, 4 - sb_len);
-                        return -1;
-                }
-
-                if (sense_buffer[0] < 15)
-                        info(udev, "%s: old sense key: 0x%x\n", dev_scsi->kernel, sense_buffer[0] & 0x0f);
-                else
-                        info(udev, "%s: sense = %2x %2x\n",
-                            dev_scsi->kernel, sense_buffer[0], sense_buffer[2]);
-                info(udev, "%s: non-extended sense class %d code 0x%0x\n",
-                    dev_scsi->kernel, sense_class, code);
-
-        }
-
-#ifdef DUMP_SENSE
-        for (i = 0, j = 0; (i < s) && (j < 254); i++) {
-                dbg(udev, "i %d, j %d\n", i, j);
-                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';
-        info(udev, "%s: sense dump:\n", dev_scsi->kernel);
-        info(udev, "%s: %s\n", 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.
-                 */
-                info(udev, "%s: called with no error\n", __FUNCTION__);
-                return -1;
-        }
-
-        info(udev, "%s: sg_io failed status 0x%x 0x%x 0x%x 0x%x\n",
-            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.
-                 */
-                info(udev, "%s: called with no error\n", __FUNCTION__);
-                return -1;
-        }
-
-        info(udev, "%s: sg_io failed status 0x%x 0x%x 0x%x\n",
-            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) {
-                info(udev, "buflen %d too long\n", buflen);
-                return -1;
-        }
-
-resend:
-        dbg(udev, "%s evpd %d, page 0x%x\n", dev_scsi->kernel, evpd, page);
-
-        if (dev_scsi->use_sg == 4) {
-                memset(&io_v4, 0, 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 {
-                memset(&io_hdr, 0, 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;
-                }
-                info(udev, "%s: ioctl failed: %s\n", dev_scsi->kernel, strerror(errno));
-                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) {
-                        dbg(udev, "%s: Retrying ...\n", dev_scsi->kernel);
-                        goto resend;
-                }
-                retval = -1;
-        }
-
-error:
-        if (retval < 0)
-                info(udev, "%s: Unable to get INQUIRY vpd %d page 0x%x.\n",
-                    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;
-
-        memset(buffer, 0, len);
-        retval = scsi_inquiry(udev, dev_scsi, fd, 1, 0x0, buffer, len);
-        if (retval < 0)
-                return 1;
-
-        if (buffer[1] != 0) {
-                info(udev, "%s: page 0 not available.\n", dev_scsi->kernel);
-                return 1;
-        }
-        if (buffer[3] > len) {
-                info(udev, "%s: page 0 buffer too long %d\n", 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 (!strncmp((char *)&buffer[VENDOR_LENGTH], dev_scsi->vendor, VENDOR_LENGTH)) {
-                        info(udev, "%s: invalid page0 data\n", 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)) {
-                info(udev, "%s: expected length %d, got length %d\n",
-                     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) {
-                info(udev, "%s: length %d too short - need %d\n",
-                    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) {
-                        dbg(udev, "prepend failed\n");
-                        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;
-
-        dbg(udev, "using pre-spc3-83 for %s\n", dev_scsi->kernel);
-        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);
-
-        memset(page_83, 0, 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) {
-                info(udev, "%s: Invalid page 0x83\n", 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);
-                        dbg(udev, "%s id desc %d/%d/%d\n", dev_scsi->kernel,
-                                id_search_list[id_ind].id_type,
-                                id_search_list[id_ind].naa_type,
-                                id_search_list[id_ind].code_set);
-                        if (!retval) {
-                                dbg(udev, "  used\n");
-                                return retval;
-                        } else if (retval < 0) {
-                                dbg(udev, "  failed\n");
-                                return retval;
-                        } else {
-                                dbg(udev, "  not used\n");
-                        }
-                }
-        }
-        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];
-
-        memset(page_83, 0, 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) {
-                info(udev, "%s: Invalid page 0x83\n", 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++;
-        }
-        dbg(udev, "using pre-spc3-83 for %s\n", dev_scsi->kernel);
-        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];
-
-        memset(buf, 0, 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) {
-                info(udev, "%s: Invalid page 0x80\n", dev_scsi->kernel);
-                return 1;
-        }
-
-        len = 1 + VENDOR_LENGTH + MODEL_LENGTH + buf[3];
-        if (max_len < len) {
-                info(udev, "%s: length %d too short - need %d\n",
-                     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;
-                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;
-
-        dbg(udev, "opening %s\n", devname);
-        fd = open(devname, O_RDONLY | O_NONBLOCK);
-        if (fd < 0) {
-                info(udev, "scsi_id: cannot open %s: %s\n",
-                     devname, strerror(errno));
-                return 1;
-        }
-
-        if (fstat(fd, &statbuf) < 0) {
-                info(udev, "scsi_id: cannot stat %s: %s\n",
-                     devname, strerror(errno));
-                err = 2;
-                goto out;
-        }
-        sprintf(dev_scsi->kernel,"%d:%d", major(statbuf.st_rdev),
-                minor(statbuf.st_rdev));
-
-        memset(buf, 0, 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;
-
-        memset(dev_scsi->serial, 0, len);
-        dbg(udev, "opening %s\n", devname);
-        srand((unsigned int)getpid());
-        for (cnt = 20; cnt > 0; cnt--) {
-                struct timespec duration;
-
-                fd = open(devname, O_RDONLY | O_NONBLOCK);
-                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) {
-                info(udev, "%s: unsupported page code 0x%d\n", dev_scsi->kernel, page_code);
-                return 1;
-        }
-
-        /*
-         * 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;
-        }
-
-        dbg(udev, "%s: Checking page0\n", dev_scsi->kernel);
-
-        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/src/sd-daemon.c b/src/udev/src/sd-daemon.c
deleted file mode 100644 (file)
index 763e079..0000000
+++ /dev/null
@@ -1,530 +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 <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#ifdef __BIONIC__
-#include <linux/fcntl.h>
-#else
-#include <sys/fcntl.h>
-#endif
-#include <netinet/in.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <limits.h>
-
-#if defined(__linux__)
-#include <mqueue.h>
-#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/udev/src/sd-daemon.h b/src/udev/src/sd-daemon.h
deleted file mode 100644 (file)
index fe51159..0000000
+++ /dev/null
@@ -1,282 +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 <sys/types.h>
-#include <inttypes.h>
-
-#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/systemd/plain/src/systemd/sd-daemon.h
-  http://cgit.freedesktop.org/systemd/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"
-
-     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.
-
-  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/udev/src/test-libudev.c b/src/udev/src/test-libudev.c
deleted file mode 100644 (file)
index 6161fb3..0000000
+++ /dev/null
@@ -1,501 +0,0 @@
-/*
- * test-libudev
- *
- * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.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.
- */
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <getopt.h>
-#include <syslog.h>
-#include <fcntl.h>
-#include <sys/epoll.h>
-
-#include "libudev.h"
-
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[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)
-{
-        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);
-        udev_device_unref(device);
-        return 0;
-}
-
-static int test_device_parents(struct udev *udev, const char *syspath)
-{
-        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);
-        udev_device_unref(device);
-
-        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;
-        }
-
-        memset(&ep_udev, 0, 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;
-        }
-
-        memset(&ep_stdin, 0, 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 ? "<all>" : subsystem);
-        udev_enumerate = udev_enumerate_new(udev);
-        if (udev_enumerate == NULL)
-                return -1;
-        udev_enumerate_add_match_subsystem(udev_enumerate, subsystem);
-        udev_enumerate_scan_devices(udev_enumerate);
-        test_enumerate_print_list(udev_enumerate);
-        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;
-}
-
-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];
-        const char *str;
-
-        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;
-                }
-        }
-
-        str = udev_get_sys_path(udev);
-        printf("sys_path: '%s'\n", str);
-        str = udev_get_dev_path(udev);
-        printf("dev_path: '%s'\n", str);
-
-        /* add sys path if needed */
-        if (strncmp(syspath, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0) {
-                snprintf(path, sizeof(path), "%s%s", udev_get_sys_path(udev), 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_monitor(udev);
-out:
-        udev_unref(udev);
-        return 0;
-}
diff --git a/src/udev/src/test-udev.c b/src/udev/src/test-udev.c
deleted file mode 100644 (file)
index c9712e9..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2003-2004 Greg Kroah-Hartman <greg@kroah.com>
- * Copyright (C) 2004-2008 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <errno.h>
-#include <unistd.h>
-#include <syslog.h>
-#include <grp.h>
-#include <sys/signalfd.h>
-
-#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) {}
-
-int main(int argc, char *argv[])
-{
-        struct udev *udev;
-        struct udev_event *event = NULL;
-        struct udev_device *dev = NULL;
-        struct udev_rules *rules = NULL;
-        char syspath[UTIL_PATH_SIZE];
-        const char *devpath;
-        const char *action;
-        sigset_t mask, sigmask_orig;
-        int err = -EINVAL;
-
-        udev = udev_new();
-        if (udev == NULL)
-                exit(1);
-        info(udev, "version %s\n", VERSION);
-        udev_selinux_init(udev);
-
-        sigprocmask(SIG_SETMASK, NULL, &sigmask_orig);
-
-        action = argv[1];
-        if (action == NULL) {
-                err(udev, "action missing\n");
-                goto out;
-        }
-
-        devpath = argv[2];
-        if (devpath == NULL) {
-                err(udev, "devpath missing\n");
-                goto out;
-        }
-
-        rules = udev_rules_new(udev, 1);
-
-        util_strscpyl(syspath, sizeof(syspath), udev_get_sys_path(udev), devpath, NULL);
-        dev = udev_device_new_from_syspath(udev, syspath);
-        if (dev == NULL) {
-                info(udev, "unknown device '%s'\n", 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;
-
-                if (strcmp(udev_device_get_subsystem(dev), "block") == 0)
-                        mode |= S_IFBLK;
-                else
-                        mode |= S_IFCHR;
-
-                if (strcmp(action, "remove") != 0) {
-                        util_create_path(udev, udev_device_get_devnode(dev));
-                        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);
-        udev_event_unref(event);
-        udev_device_unref(dev);
-        udev_rules_unref(rules);
-        udev_selinux_exit(udev);
-        udev_unref(udev);
-        if (err != 0)
-                return 1;
-        return 0;
-}
diff --git a/src/udev/src/udev-builtin-blkid.c b/src/udev/src/udev-builtin-blkid.c
deleted file mode 100644 (file)
index e57f03e..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * probe disks for filesystems and partitions
- *
- * Copyright (C) 2011 Kay Sievers <kay.sievers@vrfy.org>
- * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <sys/stat.h>
-#include <blkid/blkid.h>
-
-#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 (!strcmp(name, "TYPE")) {
-                udev_builtin_add_property(dev, test, "ID_FS_TYPE", value);
-
-        } else if (!strcmp(name, "USAGE")) {
-                udev_builtin_add_property(dev, test, "ID_FS_USAGE", value);
-
-        } else if (!strcmp(name, "VERSION")) {
-                udev_builtin_add_property(dev, test, "ID_FS_VERSION", value);
-
-        } else if (!strcmp(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 (!strcmp(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 (!strcmp(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 (!strcmp(name, "PTTYPE")) {
-                udev_builtin_add_property(dev, test, "ID_PART_TABLE_TYPE", value);
-
-        } else if (!strcmp(name, "PART_ENTRY_NAME")) {
-                blkid_encode_string(value, s, sizeof(s));
-                udev_builtin_add_property(dev, test, "ID_PART_ENTRY_NAME", s);
-
-        } else if (!strcmp(name, "PART_ENTRY_TYPE")) {
-                blkid_encode_string(value, s, sizeof(s));
-                udev_builtin_add_property(dev, test, "ID_PART_ENTRY_TYPE", s);
-
-        } else if (!strncmp(name, "PART_ENTRY_", 11)) {
-                util_strscpyl(s, sizeof(s), "ID_", name, NULL);
-                udev_builtin_add_property(dev, test, s, value);
-        }
-}
-
-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)
-{
-        struct udev *udev = udev_device_get_udev(dev);
-        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) {
-                err = -ENOMEM;
-                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;
-
-        info(udev, "probe %s %sraid offset=%llu\n",
-             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/src/udev-builtin-firmware.c b/src/udev/src/udev-builtin-firmware.c
deleted file mode 100644 (file)
index d212c64..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * firmware - Kernel firmware loader
- *
- * Copyright (C) 2009 Piter Punk <piterpunk@slackware.com>
- * Copyright (C) 2009-2011 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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 <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <getopt.h>
-#include <errno.h>
-#include <stdbool.h>
-#include <sys/utsname.h>
-#include <sys/stat.h>
-
-#include "udev.h"
-
-static bool set_loading(struct udev *udev, char *loadpath, const char *state)
-{
-        FILE *ldfile;
-
-        ldfile = fopen(loadpath, "we");
-        if (ldfile == NULL) {
-                err(udev, "error: can not open '%s'\n", 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) {
-                err(udev,"No memory available to load firmware file");
-                return false;
-        }
-
-        info(udev, "writing '%s' (%zi) to '%s'\n", 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;
-}
-
-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 fwencpath[UTIL_PATH_SIZE];
-        char misspath[UTIL_PATH_SIZE];
-        char loadpath[UTIL_PATH_SIZE];
-        char datapath[UTIL_PATH_SIZE];
-        char fwpath[UTIL_PATH_SIZE];
-        const char *firmware;
-        FILE *fwfile;
-        struct utsname kernel;
-        struct stat statbuf;
-        unsigned int i;
-        int rc = EXIT_SUCCESS;
-
-        firmware = udev_device_get_property_value(dev, "FIRMWARE");
-        if (firmware == NULL) {
-                err(udev, "firmware parameter missing\n\n");
-                rc = EXIT_FAILURE;
-                goto exit;
-        }
-
-        /* lookup firmware file */
-        uname(&kernel);
-        for (i = 0; i < ARRAY_SIZE(searchpath); i++) {
-                util_strscpyl(fwpath, sizeof(fwpath), searchpath[i], kernel.release, "/", firmware, NULL);
-                dbg(udev, "trying %s\n", fwpath);
-                fwfile = fopen(fwpath, "re");
-                if (fwfile != NULL)
-                        break;
-
-                util_strscpyl(fwpath, sizeof(fwpath), searchpath[i], firmware, NULL);
-                dbg(udev, "trying %s\n", fwpath);
-                fwfile = fopen(fwpath, "re");
-                if (fwfile != NULL)
-                        break;
-        }
-
-        util_path_encode(firmware, fwencpath, sizeof(fwencpath));
-        util_strscpyl(misspath, sizeof(misspath), udev_get_run_path(udev), "/firmware-missing/", fwencpath, NULL);
-        util_strscpyl(loadpath, sizeof(loadpath), udev_device_get_syspath(dev), "/loading", NULL);
-
-        if (fwfile == NULL) {
-                int err;
-
-                /* This link indicates the missing firmware file and the associated device */
-                info(udev, "did not find firmware file '%s'\n", firmware);
-                do {
-                        err = util_create_path(udev, misspath);
-                        if (err != 0 && err != -ENOENT)
-                                break;
-                        err = symlink(udev_device_get_devpath(dev), misspath);
-                        if (err != 0)
-                                err = -errno;
-                } while (err == -ENOENT);
-                rc = EXIT_FAILURE;
-                set_loading(udev, loadpath, "-1");
-                goto exit;
-        }
-
-        if (stat(fwpath, &statbuf) < 0 || statbuf.st_size == 0) {
-                rc = EXIT_FAILURE;
-                goto exit;
-        }
-        if (unlink(misspath) == 0)
-                util_delete_path(udev, misspath);
-
-        if (!set_loading(udev, loadpath, "1"))
-                goto exit;
-
-        util_strscpyl(datapath, sizeof(datapath), udev_device_get_syspath(dev), "/data", NULL);
-        if (!copy_firmware(udev, fwpath, datapath, statbuf.st_size)) {
-                err(udev, "error sending firmware '%s' to device\n", 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/src/udev-builtin-hwdb.c b/src/udev/src/udev-builtin-hwdb.c
deleted file mode 100644 (file)
index aa996f3..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * usb-db, pci-db - lookup vendor/product database
- *
- * Copyright (C) 2009 Lennart Poettering <lennart@poettering.net>
- * Copyright (C) 2011 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <inttypes.h>
-#include <ctype.h>
-#include <stdlib.h>
-
-#include "udev.h"
-
-static int get_id_attr(
-        struct udev_device *parent,
-        const char *name,
-        uint16_t *value) {
-
-        const char *t;
-        unsigned u;
-
-        if (!(t = udev_device_get_sysattr_value(parent, name))) {
-                fprintf(stderr, "%s lacks %s.\n", udev_device_get_syspath(parent), name);
-                return -1;
-        }
-
-        if (!strncmp(t, "0x", 2))
-                t += 2;
-
-        if (sscanf(t, "%04x", &u) != 1 || u > 0xFFFFU) {
-                fprintf(stderr, "Failed to parse %s on %s.\n", name, udev_device_get_syspath(parent));
-                return -1;
-        }
-
-        *value = (uint16_t) u;
-        return 0;
-}
-
-static int get_vid_pid(
-        struct udev_device *parent,
-        const char *vendor_attr,
-        const char *product_attr,
-        uint16_t *vid,
-        uint16_t *pid) {
-
-        if (get_id_attr(parent, vendor_attr, vid) < 0)
-                return -1;
-        else if (*vid <= 0) {
-                fprintf(stderr, "Invalid vendor id.\n");
-                return -1;
-        }
-
-        if (get_id_attr(parent, product_attr, pid) < 0)
-                return -1;
-
-        return 0;
-}
-
-static void rstrip(char *n) {
-        size_t i;
-
-        for (i = strlen(n); i > 0 && isspace(n[i-1]); i--)
-                n[i-1] = 0;
-}
-
-#define HEXCHARS "0123456789abcdefABCDEF"
-#define WHITESPACE " \t\n\r"
-static int lookup_vid_pid(const char *database,
-                          uint16_t vid, uint16_t pid,
-                          char **vendor, char **product)
-{
-
-        FILE *f;
-        int ret = -1;
-        int found_vendor = 0;
-        char *line = NULL;
-
-        *vendor = *product = NULL;
-
-        if (!(f = fopen(database, "rme"))) {
-                fprintf(stderr, "Failed to open database file '%s': %s\n", database, strerror(errno));
-                return -1;
-        }
-
-        for (;;) {
-                size_t n;
-
-                if (getline(&line, &n, f) < 0)
-                        break;
-
-                rstrip(line);
-
-                if (line[0] == '#' || line[0] == 0)
-                        continue;
-
-                if (strspn(line, HEXCHARS) == 4) {
-                        unsigned u;
-
-                        if (found_vendor)
-                                break;
-
-                        if (sscanf(line, "%04x", &u) == 1 && u == vid) {
-                                char *t;
-
-                                t = line+4;
-                                t += strspn(t, WHITESPACE);
-
-                                if (!(*vendor = strdup(t))) {
-                                        fprintf(stderr, "Out of memory.\n");
-                                        goto finish;
-                                }
-
-                                found_vendor = 1;
-                        }
-
-                        continue;
-                }
-
-                if (found_vendor && line[0] == '\t' && strspn(line+1, HEXCHARS) == 4) {
-                        unsigned u;
-
-                        if (sscanf(line+1, "%04x", &u) == 1 && u == pid) {
-                                char *t;
-
-                                t = line+5;
-                                t += strspn(t, WHITESPACE);
-
-                                if (!(*product = strdup(t))) {
-                                        fprintf(stderr, "Out of memory.\n");
-                                        goto finish;
-                                }
-
-                                break;
-                        }
-                }
-        }
-
-        ret = 0;
-
-finish:
-        free(line);
-        fclose(f);
-
-        if (ret < 0) {
-                free(*product);
-                free(*vendor);
-
-                *product = *vendor = NULL;
-        }
-
-        return ret;
-}
-
-static struct udev_device *find_device(struct udev_device *dev, const char *subsys, const char *devtype)
-{
-        const char *str;
-
-        str = udev_device_get_subsystem(dev);
-        if (str == NULL)
-                goto try_parent;
-        if (strcmp(str, subsys) != 0)
-                goto try_parent;
-
-        if (devtype != NULL) {
-                str = udev_device_get_devtype(dev);
-                if (str == NULL)
-                        goto try_parent;
-                if (strcmp(str, devtype) != 0)
-                        goto try_parent;
-        }
-        return dev;
-try_parent:
-        return udev_device_get_parent_with_subsystem_devtype(dev, subsys, devtype);
-}
-
-
-static int builtin_db(struct udev_device *dev, bool test,
-                      const char *database,
-                      const char *vendor_attr, const char *product_attr,
-                      const char *subsys, const char *devtype)
-{
-        struct udev_device *parent;
-        uint16_t vid = 0, pid = 0;
-        char *vendor = NULL, *product = NULL;
-
-        parent = find_device(dev, subsys, devtype);
-        if (!parent) {
-                fprintf(stderr, "Failed to find device.\n");
-                goto finish;
-        }
-
-        if (get_vid_pid(parent, vendor_attr, product_attr, &vid, &pid) < 0)
-                goto finish;
-
-        if (lookup_vid_pid(database, vid, pid, &vendor, &product) < 0)
-                goto finish;
-
-        if (vendor)
-                udev_builtin_add_property(dev, test, "ID_VENDOR_FROM_DATABASE", vendor);
-        if (product)
-                udev_builtin_add_property(dev, test, "ID_MODEL_FROM_DATABASE", product);
-
-finish:
-        free(vendor);
-        free(product);
-        return 0;
-}
-
-static int builtin_usb_db(struct udev_device *dev, int argc, char *argv[], bool test)
-{
-        return builtin_db(dev, test, USB_DATABASE, "idVendor", "idProduct", "usb", "usb_device");
-}
-
-static int builtin_pci_db(struct udev_device *dev, int argc, char *argv[], bool test)
-{
-        return builtin_db(dev, test, PCI_DATABASE, "vendor", "device", "pci", NULL);
-}
-
-const struct udev_builtin udev_builtin_usb_db = {
-        .name = "usb-db",
-        .cmd = builtin_usb_db,
-        .help = "USB vendor/product database",
-        .run_once = true,
-};
-
-const struct udev_builtin udev_builtin_pci_db = {
-        .name = "pci-db",
-        .cmd = builtin_pci_db,
-        .help = "PCI vendor/product database",
-        .run_once = true,
-};
diff --git a/src/udev/src/udev-builtin-input_id.c b/src/udev/src/udev-builtin-input_id.c
deleted file mode 100644 (file)
index a062ef7..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * compose persistent device path
- *
- * Copyright (C) 2009 Martin Pitt <martin.pitt@ubuntu.com>
- * Portions Copyright (C) 2004 David Zeuthen, <david@fubar.dk>
- * Copyright (C) 2011 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <linux/limits.h>
-#include <linux/input.h>
-
-#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(x))
-#define LONG(x) ((x)/BITS_PER_LONG)
-#define test_bit(bit, array)    ((array[LONG(bit)] >> 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)
-{
-        struct udev *udev = udev_device_get_udev(dev);
-        char text[4096];
-        unsigned i;
-        char* word;
-        unsigned long val;
-
-        snprintf(text, sizeof(text), "%s", udev_device_get_sysattr_value(pdev, attr));
-        info(udev, "%s raw kernel attribute: %s\n", attr, text);
-
-        memset (bitmask, 0, 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
-                        info(udev, "ignoring %s block %lX which is larger than maximum size\n", attr, val);
-                *word = '\0';
-                ++i;
-        }
-        val = strtoul (text, NULL, 16);
-        if (i < bitmask_size / sizeof(unsigned long))
-                bitmask[i] = val;
-        else
-                info(udev, "ignoring %s block %lX which is larger than maximum size\n", 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));
-                info(udev, "%s decoded bit map:\n", 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)
-                        info(udev, text, i * BITS_PER_LONG, bitmask[i]);
-        }
-}
-
-/* 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)
-{
-        struct udev *udev = udev_device_get_udev(dev);
-        unsigned i;
-        unsigned long found;
-        unsigned long mask;
-
-        /* do we have any KEY_* capability? */
-        if (!test_bit (EV_KEY, bitmask_ev)) {
-                info(udev, "test_key: no EV_KEY capability\n");
-                return;
-        }
-
-        /* only consider KEY_* here, not BTN_* */
-        found = 0;
-        for (i = 0; i < BTN_MISC/BITS_PER_LONG; ++i) {
-                found |= bitmask_key[i];
-                info(udev, "test_key: checking bit block %lu for any keys; found=%i\n", 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)) {
-                                info(udev, "test_key: Found key %x in high block\n", 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/src/udev-builtin-kmod.c b/src/udev/src/udev-builtin-kmod.c
deleted file mode 100644 (file)
index 57e813f..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * load kernel modules
- *
- * Copyright (C) 2011 Kay Sievers <kay.sievers@vrfy.org>
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <libkmod.h>
-
-#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)
-                info(udev, "no module matches '%s'\n", 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)
-                        info(udev, "module '%s' is blacklisted\n", kmod_module_get_name(mod));
-                else if (err == 0)
-                        info(udev, "inserted '%s'\n", kmod_module_get_name(mod));
-                else
-                        info(udev, "failed to insert '%s'\n", kmod_module_get_name(mod));
-
-                kmod_module_unref(mod);
-        }
-
-        kmod_module_unref_list(list);
-        return err;
-}
-
-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);
-}
-
-/* needs to re-instantiate the context after a reload */
-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) {
-                ctx = kmod_new(NULL, NULL);
-                if (!ctx)
-                        return -ENOMEM;
-
-                info(udev, "load module index\n");
-                kmod_set_log_fn(ctx, udev_kmod_log, udev);
-                kmod_load_resources(ctx);
-        }
-
-        if (argc < 3 || strcmp(argv[1], "load")) {
-                err(udev, "expect: %s load <module>\n", argv[0]);
-                return EXIT_FAILURE;
-        }
-
-        for (i = 2; argv[i]; i++) {
-                info(udev, "execute '%s' '%s'\n", argv[1], argv[i]);
-                load_module(udev, argv[i]);
-        }
-
-        return EXIT_SUCCESS;
-}
-
-/* called at udev startup */
-static int builtin_kmod_init(struct udev *udev)
-{
-        if (ctx)
-                return 0;
-
-        ctx = kmod_new(NULL, NULL);
-        if (!ctx)
-                return -ENOMEM;
-
-        info(udev, "load module index\n");
-        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)
-{
-        info(udev, "unload module index\n");
-        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)
-{
-        info(udev, "validate module index\n");
-        if (kmod_validate_resources(ctx) != KMOD_RESOURCES_OK)
-                return true;
-        return false;
-}
-
-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/src/udev-builtin-path_id.c b/src/udev/src/udev-builtin-path_id.c
deleted file mode 100644 (file)
index a8559d2..0000000
+++ /dev/null
@@ -1,498 +0,0 @@
-/*
- * compose persistent device path
- *
- * Copyright (C) 2009-2011 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <string.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <dirent.h>
-#include <getopt.h>
-
-#include "udev.h"
-
-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-%d", lun);
-        /* handle all other lun addressing methods by using a variant of the original lun format */
-        return path_prepend(path, "lun-0x%04x%04x00000000", (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 || strcmp(subsystem, subsys) != 0)
-                        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 (strncmp(udev_device_get_sysname(transportdev), "session", 7) == 0)
-                        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 */
-        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 (strncmp(dent->d_name, "host", 4) != 0)
-                        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(struct udev_device *parent, char **path)
-{
-        const char *devtype;
-        const char *name;
-        const char *id;
-
-        devtype = udev_device_get_devtype(parent);
-        if (devtype == NULL || strcmp(devtype, "scsi_device") != 0)
-                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;
-        }
-
-        /* lousy 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 creates duplicated link
-         * names as the fake SCSI host adapters are all separated, they are all
-         * re-based as host == 0. ATA should just stop faking two duplicated
-         * hierarchies for a single topology and leave the SCSI stuff alone;
-         * until that happens, there are no by-path/ links for ATA devices behind
-         * an ATA transport class.
-         */
-        if (strstr(name, "/ata") != NULL) {
-                parent = NULL;
-                goto out;
-        }
-
-        parent = handle_scsi_default(parent, path);
-out:
-        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 (strncmp(name, "nst", 3) == 0 && strchr("lma", name[3]) != NULL)
-                path_prepend(path, "nst%c", name[3]);
-        else if (strncmp(name, "st", 2) == 0 && 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 (strcmp(devtype, "usb_interface") != 0 && strcmp(devtype, "usb_device") != 0)
-                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_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;
-
-        /* 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 (strcmp(subsys, "scsi_tape") == 0) {
-                        handle_scsi_tape(parent, &path);
-                } else if (strcmp(subsys, "scsi") == 0) {
-                        parent = handle_scsi(parent, &path);
-                } else if (strcmp(subsys, "usb") == 0) {
-                        parent = handle_usb(parent, &path);
-                } else if (strcmp(subsys, "serio") == 0) {
-                        path_prepend(&path, "serio-%s", udev_device_get_sysnum(parent));
-                        parent = skip_subsystem(parent, "serio");
-                } else if (strcmp(subsys, "pci") == 0) {
-                        path_prepend(&path, "pci-%s", udev_device_get_sysname(parent));
-                        parent = skip_subsystem(parent, "pci");
-                } else if (strcmp(subsys, "platform") == 0) {
-                        path_prepend(&path, "platform-%s", udev_device_get_sysname(parent));
-                        parent = skip_subsystem(parent, "platform");
-                } else if (strcmp(subsys, "acpi") == 0) {
-                        path_prepend(&path, "acpi-%s", udev_device_get_sysname(parent));
-                        parent = skip_subsystem(parent, "acpi");
-                } else if (strcmp(subsys, "xen") == 0) {
-                        path_prepend(&path, "xen-%s", udev_device_get_sysname(parent));
-                        parent = skip_subsystem(parent, "xen");
-                } else if (strcmp(subsys, "virtio") == 0) {
-                        path_prepend(&path, "virtio-pci-%s", udev_device_get_sysname(parent));
-                        parent = skip_subsystem(parent, "virtio");
-                }
-
-                parent = udev_device_get_parent(parent);
-        }
-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/src/udev-builtin-usb_id.c b/src/udev/src/udev-builtin-usb_id.c
deleted file mode 100644 (file)
index 85828e3..0000000
+++ /dev/null
@@ -1,482 +0,0 @@
-/*
- * USB device properties and persistent device path
- *
- * Copyright (c) 2005 SUSE Linux Products GmbH, Germany
- *   Author: Hannes Reinecke <hare@suse.de>
- *
- * Copyright (C) 2005-2011 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <string.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <errno.h>
-
-#include "udev.h"
-
-static void set_usb_iftype(char *to, int if_class_num, size_t len)
-{
-        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;
-        char *type = "generic";
-
-        type_num = strtoul(from, &eptr, 0);
-        if (eptr != from) {
-                switch (type_num) {
-                case 2:
-                        type = "atapi";
-                        break;
-                case 3:
-                        type = "tape";
-                        break;
-                case 4: /* UFI */
-                case 5: /* SFF-8070i */
-                        type = "floppy";
-                        break;
-                case 1: /* RBC devices */
-                        type = "rbc";
-                        break;
-                case 6: /* Transparent SPC-2 devices */
-                        type = "scsi";
-                        break;
-                default:
-                        break;
-                }
-        }
-        util_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;
-        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;
-                }
-        }
-        util_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)
-{
-        char *filename = NULL;
-        int fd;
-        ssize_t size;
-        unsigned char buf[18 + 65535];
-        unsigned int pos, strpos;
-        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));
-        int err = 0;
-
-        if (asprintf(&filename, "%s/descriptors", udev_device_get_syspath(dev)) < 0) {
-                err = -1;
-                goto out;
-        }
-        fd = open(filename, O_RDONLY|O_CLOEXEC);
-        if (fd < 0) {
-                fprintf(stderr, "error opening USB device 'descriptors' file\n");
-                err = -1;
-                goto out;
-        }
-        size = read(fd, buf, sizeof(buf));
-        close(fd);
-        if (size < 18 || size == sizeof(buf)) {
-                err = -1;
-                goto out;
-        }
-
-        pos = 0;
-        strpos = 0;
-        ifs_str[0] = '\0';
-        while (pos < sizeof(buf) && 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';
-        }
-out:
-        free(filename);
-        return err;
-}
-
-/*
- * 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 *udev = udev_device_get_udev(dev);
-        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';
-
-        dbg(udev, "syspath %s\n", udev_device_get_syspath(dev));
-
-        /* shortcut, if we are called directly for a "usb_device" type */
-        if (udev_device_get_devtype(dev) != NULL && strcmp(udev_device_get_devtype(dev), "usb_device") == 0) {
-                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) {
-                info(udev, "unable to access usb_interface device of '%s'\n",
-                     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) {
-                info(udev, "%s: cannot get bInterfaceClass attribute\n",
-                     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);
-        }
-
-        info(udev, "%s: if_class %d protocol %d\n",
-             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) {
-                info(udev, "unable to find parent 'usb' device of '%s'\n",
-                     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) {
-                        info(udev, "unable to find parent 'scsi' device of '%s'\n",
-                             udev_device_get_syspath(dev));
-                        goto fallback;
-                }
-                if (sscanf(udev_device_get_sysname(dev_scsi), "%d:%d:%d:%d", &host, &bus, &target, &lun) != 4) {
-                        info(udev, "invalid scsi device '%s'\n", 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) {
-                        info(udev, "%s: cannot get SCSI vendor attribute\n",
-                             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) {
-                        info(udev, "%s: cannot get SCSI model attribute\n",
-                             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) {
-                        info(udev, "%s: cannot get SCSI type attribute\n",
-                             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) {
-                        info(udev, "%s: cannot get SCSI revision attribute\n",
-                             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) {
-                        info(udev, "No USB vendor information available\n");
-                        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) {
-                        dbg(udev, "No USB model information available\n");
-                        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) {
-                        util_replace_whitespace(usb_serial, serial_str, sizeof(serial_str)-1);
-                        util_replace_chars(serial_str, NULL);
-                }
-        }
-
-        s = serial;
-        l = util_strpcpyl(&s, sizeof(serial), vendor_str, "_", model_str, NULL);
-        if (serial_str[0] != '\0')
-                l = util_strpcpyl(&s, l, "_", serial_str, NULL);
-
-        if (instance_str[0] != '\0')
-                util_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/src/udev-builtin.c b/src/udev/src/udev-builtin.c
deleted file mode 100644 (file)
index 5bc5fa6..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2007-2009 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <errno.h>
-#include <getopt.h>
-
-#include "udev.h"
-
-static const struct udev_builtin *builtins[] = {
-        [UDEV_BUILTIN_BLKID] = &udev_builtin_blkid,
-        [UDEV_BUILTIN_FIRMWARE] = &udev_builtin_firmware,
-        [UDEV_BUILTIN_INPUT_ID] = &udev_builtin_input_id,
-        [UDEV_BUILTIN_KMOD] = &udev_builtin_kmod,
-        [UDEV_BUILTIN_PATH_ID] = &udev_builtin_path_id,
-        [UDEV_BUILTIN_PCI_DB] = &udev_builtin_pci_db,
-        [UDEV_BUILTIN_USB_DB] = &udev_builtin_usb_db,
-        [UDEV_BUILTIN_USB_ID] = &udev_builtin_usb_id,
-};
-
-int udev_builtin_init(struct udev *udev)
-{
-        unsigned int i;
-        int err;
-
-        for (i = 0; i < ARRAY_SIZE(builtins); i++) {
-                if (builtins[i]->init) {
-                        err = builtins[i]->init(udev);
-                        if (err < 0)
-                                break;
-                }
-        }
-        return err;
-}
-
-void udev_builtin_exit(struct udev *udev)
-{
-        unsigned int i;
-
-        for (i = 0; i < ARRAY_SIZE(builtins); i++)
-                if (builtins[i]->exit)
-                        builtins[i]->exit(udev);
-}
-
-bool udev_builtin_validate(struct udev *udev)
-{
-        unsigned int i;
-        bool change = false;
-
-        for (i = 0; i < ARRAY_SIZE(builtins); i++)
-                if (builtins[i]->validate)
-                        if (builtins[i]->validate(udev))
-                                change = true;
-        return change;
-}
-
-void udev_builtin_list(struct udev *udev)
-{
-        unsigned int i;
-
-        for (i = 0; i < ARRAY_SIZE(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;
-
-        util_strscpy(name, sizeof(name), command);
-        pos = strchr(name, ' ');
-        if (pos)
-                pos[0] = '\0';
-        for (i = 0; i < ARRAY_SIZE(builtins); i++)
-                if (strcmp(builtins[i]->name, name) == 0)
-                        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];
-
-        optind = 0;
-        util_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);
-
-        info(udev_device_get_udev(dev), "%s=%s\n", key, val);
-        if (test)
-                printf("%s=%s\n", key, val);
-        return 0;
-}
diff --git a/src/udev/src/udev-control.socket b/src/udev/src/udev-control.socket
deleted file mode 100644 (file)
index f80f774..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-[Unit]
-Description=udev Control Socket
-DefaultDependencies=no
-ConditionCapability=CAP_MKNOD
-
-[Socket]
-Service=udev.service
-ListenSequentialPacket=/run/udev/control
-SocketMode=0600
-PassCredentials=yes
diff --git a/src/udev/src/udev-ctrl.c b/src/udev/src/udev-ctrl.c
deleted file mode 100644 (file)
index 5556f1a..0000000
+++ /dev/null
@@ -1,494 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.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.
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/poll.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-
-#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;
-
-        uctrl = calloc(1, sizeof(struct udev_ctrl));
-        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) {
-                        err(udev, "error getting socket: %m\n");
-                        udev_ctrl_unref(uctrl);
-                        return NULL;
-                }
-        } else {
-                uctrl->bound = true;
-                uctrl->sock = fd;
-        }
-
-        uctrl->saddr.sun_family = AF_LOCAL;
-        util_strscpyl(uctrl->saddr.sun_path, sizeof(uctrl->saddr.sun_path),
-                      udev_get_run_path(udev), "/control", NULL);
-        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;
-                        err(uctrl->udev, "bind failed: %m\n");
-                        return err;
-                }
-
-                err = listen(uctrl->sock, 0);
-                if (err < 0) {
-                        err = -errno;
-                        err(uctrl->udev, "listen failed: %m\n");
-                        return err;
-                }
-
-                uctrl->bound = true;
-                uctrl->cleanup_socket = true;
-        }
-        return 0;
-}
-
-struct udev *udev_ctrl_get_udev(struct udev_ctrl *uctrl)
-{
-        return uctrl->udev;
-}
-
-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;
-        socklen_t slen;
-        const int on = 1;
-
-        conn = calloc(1, sizeof(struct udev_ctrl_connection));
-        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)
-                        err(uctrl->udev, "unable to receive ctrl connection: %m\n");
-                goto err;
-        }
-
-        /* check peer credential of connection */
-        slen = sizeof(ucred);
-        if (getsockopt(conn->sock, SOL_SOCKET, SO_PEERCRED, &ucred, &slen) < 0) {
-                err(uctrl->udev, "unable to receive credentials of ctrl connection: %m\n");
-                goto err;
-        }
-        if (ucred.uid > 0) {
-                err(uctrl->udev, "sender uid=%i, message ignored\n", 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;
-
-        memset(&ctrl_msg_wire, 0x00, 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)
-                util_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 *udev = conn->uctrl->udev;
-        struct udev_ctrl_msg *uctrl_msg;
-        ssize_t size;
-        struct msghdr smsg;
-        struct cmsghdr *cmsg;
-        struct iovec iov;
-        struct ucred *cred;
-        char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
-
-        uctrl_msg = calloc(1, sizeof(struct udev_ctrl_msg));
-        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) {
-                        err(udev, "timeout waiting for ctrl message\n");
-                        goto err;
-                } else {
-                        if (!(pfd[0].revents & POLLIN)) {
-                                err(udev, "ctrl connection error: %m\n");
-                                goto err;
-                        }
-                }
-
-                break;
-        }
-
-        iov.iov_base = &uctrl_msg->ctrl_msg_wire;
-        iov.iov_len = sizeof(struct udev_ctrl_msg_wire);
-        memset(&smsg, 0x00, sizeof(struct msghdr));
-        smsg.msg_iov = &iov;
-        smsg.msg_iovlen = 1;
-        smsg.msg_control = cred_msg;
-        smsg.msg_controllen = sizeof(cred_msg);
-        size = recvmsg(conn->sock, &smsg, 0);
-        if (size <  0) {
-                err(udev, "unable to receive ctrl message: %m\n");
-                goto err;
-        }
-        cmsg = CMSG_FIRSTHDR(&smsg);
-        cred = (struct ucred *) CMSG_DATA(cmsg);
-
-        if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
-                err(udev, "no sender credentials received, message ignored\n");
-                goto err;
-        }
-
-        if (cred->uid != 0) {
-                err(udev, "sender uid=%i, message ignored\n", cred->uid);
-                goto err;
-        }
-
-        if (uctrl_msg->ctrl_msg_wire.magic != UDEV_CTRL_MAGIC) {
-                err(udev, "message magic 0x%08x doesn't match, ignore it\n", uctrl_msg->ctrl_msg_wire.magic);
-                goto err;
-        }
-
-        dbg(udev, "created ctrl_msg %p (%i)\n", uctrl_msg, uctrl_msg->ctrl_msg_wire.type);
-        return uctrl_msg;
-err:
-        udev_ctrl_msg_unref(uctrl_msg);
-        return NULL;
-}
-
-struct udev_ctrl_msg *udev_ctrl_msg_ref(struct udev_ctrl_msg *ctrl_msg)
-{
-        if (ctrl_msg == NULL)
-                return NULL;
-        ctrl_msg->refcount++;
-        return ctrl_msg;
-}
-
-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;
-        dbg(ctrl_msg->conn->uctrl->udev, "release ctrl_msg %p\n", 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/src/udev-event.c b/src/udev/src/udev-event.c
deleted file mode 100644 (file)
index 45dd77b..0000000
+++ /dev/null
@@ -1,1011 +0,0 @@
-/*
- * Copyright (C) 2003-2010 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <ctype.h>
-#include <string.h>
-#include <time.h>
-#include <net/if.h>
-#include <sys/ioctl.h>
-#include <sys/prctl.h>
-#include <sys/poll.h>
-#include <sys/epoll.h>
-#include <sys/wait.h>
-#include <sys/socket.h>
-#include <sys/signalfd.h>
-#include <linux/sockios.h>
-
-#include "udev.h"
-
-struct udev_event *udev_event_new(struct udev_device *dev)
-{
-        struct udev *udev = udev_device_get_udev(dev);
-        struct udev_event *event;
-
-        event = calloc(1, sizeof(struct udev_event));
-        if (event == NULL)
-                return NULL;
-        event->dev = dev;
-        event->udev = udev;
-        udev_list_init(udev, &event->run_list, false);
-        event->fd_signal = -1;
-        event->birth_usec = now_usec();
-        event->timeout_usec = 30 * 1000 * 1000;
-        dbg(event->udev, "allocated event %p\n", event);
-        return event;
-}
-
-void udev_event_unref(struct udev_event *event)
-{
-        if (event == NULL)
-                return;
-        udev_list_cleanup(&event->run_list);
-        free(event->program_result);
-        free(event->name);
-        dbg(event->udev, "free event %p\n", event);
-        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 {
-                char *name;
-                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 < ARRAY_SIZE(map); i++) {
-                                        if (strncmp(&from[1], map[i].name, strlen(map[i].name)) == 0) {
-                                                type = map[i].type;
-                                                from += strlen(map[i].name)+1;
-                                                dbg(event->udev, "will substitute format name '%s'\n", map[i].name);
-                                                goto subst;
-                                        }
-                                }
-                        } else if (from[0] == '%') {
-                                /* substitute format char */
-                                unsigned int i;
-
-                                if (from[1] == '%') {
-                                        from++;
-                                        goto copy;
-                                }
-
-                                for (i = 0; i < ARRAY_SIZE(map); i++) {
-                                        if (from[1] == map[i].fmt) {
-                                                type = map[i].type;
-                                                from += 2;
-                                                dbg(event->udev, "will substitute format char '%c'\n", map[i].fmt);
-                                                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') {
-                                        err(event->udev, "missing closing brace for format '%s'\n", 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 = util_strpcpy(&s, l, udev_device_get_devpath(dev));
-                        dbg(event->udev, "substitute devpath '%s'\n", udev_device_get_devpath(dev));
-                        break;
-                case SUBST_KERNEL:
-                        l = util_strpcpy(&s, l, udev_device_get_sysname(dev));
-                        dbg(event->udev, "substitute kernel name '%s'\n", udev_device_get_sysname(dev));
-                        break;
-                case SUBST_KERNEL_NUMBER:
-                        if (udev_device_get_sysnum(dev) == NULL)
-                                break;
-                        l = util_strpcpy(&s, l, udev_device_get_sysnum(dev));
-                        dbg(event->udev, "substitute kernel number '%s'\n", udev_device_get_sysnum(dev));
-                        break;
-                case SUBST_ID:
-                        if (event->dev_parent == NULL)
-                                break;
-                        l = util_strpcpy(&s, l, udev_device_get_sysname(event->dev_parent));
-                        dbg(event->udev, "substitute id '%s'\n", 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 = util_strpcpy(&s, l, driver);
-                        dbg(event->udev, "substitute driver '%s'\n", driver);
-                        break;
-                }
-                case SUBST_MAJOR: {
-                        char num[UTIL_PATH_SIZE];
-
-                        sprintf(num, "%d", major(udev_device_get_devnum(dev)));
-                        l = util_strpcpy(&s, l, num);
-                        dbg(event->udev, "substitute major number '%s'\n", num);
-                        break;
-                }
-                case SUBST_MINOR: {
-                        char num[UTIL_PATH_SIZE];
-
-                        sprintf(num, "%d", minor(udev_device_get_devnum(dev)));
-                        l = util_strpcpy(&s, l, num);
-                        dbg(event->udev, "substitute minor number '%s'\n", 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;
-
-                                dbg(event->udev, "request part #%d of result string\n", i);
-                                util_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) {
-                                        err(event->udev, "requested part of result string not found\n");
-                                        break;
-                                }
-                                util_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 = util_strpcpy(&s, l, tmp);
-                                dbg(event->udev, "substitute part of result string '%s'\n", tmp);
-                        } else {
-                                l = util_strpcpy(&s, l, event->program_result);
-                                dbg(event->udev, "substitute result string '%s'\n", event->program_result);
-                        }
-                        break;
-                }
-                case SUBST_ATTR: {
-                        const char *value = NULL;
-                        char vbuf[UTIL_NAME_SIZE];
-                        size_t len;
-                        int count;
-
-                        if (attr == NULL) {
-                                err(event->udev, "missing file parameter for attr\n");
-                                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)
-                                util_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)
-                                info(event->udev, "%i character(s) replaced\n" , count);
-                        l = util_strpcpy(&s, l, vbuf);
-                        dbg(event->udev, "substitute sysfs value '%s'\n", 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) {
-                                size_t devlen = strlen(udev_get_dev_path(event->udev))+1;
-
-                                l = util_strpcpy(&s, l, &devnode[devlen]);
-                                dbg(event->udev, "found parent '%s', got node name '%s'\n",
-                                    udev_device_get_syspath(dev_parent), &devnode[devlen]);
-                        }
-                        break;
-                }
-                case SUBST_DEVNODE:
-                        if (udev_device_get_devnode(dev) != NULL)
-                                l = util_strpcpy(&s, l, udev_device_get_devnode(dev));
-                        break;
-                case SUBST_NAME: {
-                        if (event->name != NULL) {
-                                l = util_strpcpy(&s, l, event->name);
-                                dbg(event->udev, "substitute custom node name '%s'\n", event->name);
-                        } else if (udev_device_get_devnode(dev) != NULL) {
-                                size_t devlen = strlen(udev_get_dev_path(event->udev))+1;
-
-                                l = util_strpcpy(&s, l, &udev_device_get_devnode(dev)[devlen]);
-                                dbg(event->udev, "substitute node name'%s'\n", &udev_device_get_devnode(dev)[devlen]);
-                        } else {
-                                l = util_strpcpy(&s, l, udev_device_get_sysname(dev));
-                                dbg(event->udev, "substitute device name'%s'\n", udev_device_get_sysname(dev));
-                        }
-                        break;
-                }
-                case SUBST_LINKS: {
-                        size_t devlen = strlen(udev_get_dev_path(event->udev))+1;
-                        struct udev_list_entry *list_entry;
-
-                        list_entry = udev_device_get_devlinks_list_entry(dev);
-                        if (list_entry == NULL)
-                                break;
-                        l = util_strpcpy(&s, l, &udev_list_entry_get_name(list_entry)[devlen]);
-                        udev_list_entry_foreach(list_entry, udev_list_entry_get_next(list_entry))
-                                l = util_strpcpyl(&s, l, " ", &udev_list_entry_get_name(list_entry)[devlen], NULL);
-                        break;
-                }
-                case SUBST_ROOT:
-                        l = util_strpcpy(&s, l, udev_get_dev_path(event->udev));
-                        dbg(event->udev, "substitute udev_root '%s'\n", udev_get_dev_path(event->udev));
-                        break;
-                case SUBST_SYS:
-                        l = util_strpcpy(&s, l, udev_get_sys_path(event->udev));
-                        dbg(event->udev, "substitute sys_path '%s'\n", udev_get_sys_path(event->udev));
-                        break;
-                case SUBST_ENV:
-                        if (attr == NULL) {
-                                dbg(event->udev, "missing attribute\n");
-                                break;
-                        } else {
-                                const char *value;
-
-                                value = udev_device_get_property_value(event->dev, attr);
-                                if (value == NULL)
-                                        break;
-                                dbg(event->udev, "substitute env '%s=%s'\n", attr, value);
-                                l = util_strpcpy(&s, l, value);
-                                break;
-                        }
-                default:
-                        err(event->udev, "unknown substitution type=%i\n", type);
-                        break;
-                }
-        }
-
-out:
-        s[0] = '\0';
-        dbg(event->udev, "'%s' -> '%s' (%zu)\n", src, dest, l);
-        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)
-{
-        struct udev *udev = event->udev;
-        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 {
-                err(udev, "open /dev/null failed: %m\n");
-        }
-
-        /* 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;
-        err(udev, "failed to execute '%s' '%s': %m\n", 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)
-{
-        struct udev *udev = event->udev;
-        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) {
-                err(udev, "error creating epoll fd: %m\n");
-                goto out;
-        }
-
-        if (fd_stdout >= 0) {
-                memset(&ep_outpipe, 0, 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) {
-                        err(udev, "fail to add fd to epoll: %m\n");
-                        goto out;
-                }
-        }
-
-        if (fd_stderr >= 0) {
-                memset(&ep_errpipe, 0, 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) {
-                        err(udev, "fail to add fd to epoll: %m\n");
-                        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) {
-                        unsigned long long age_usec;
-
-                        age_usec = now_usec() - event->birth_usec;
-                        if (age_usec >= event->timeout_usec) {
-                                err(udev, "timeout '%s'\n", cmd);
-                                goto out;
-                        }
-                        timeout = ((event->timeout_usec - age_usec) / 1000) + 1000;
-                } else {
-                        timeout = -1;
-                }
-
-                fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), timeout);
-                if (fdcount < 0) {
-                        if (errno == EINTR)
-                                continue;
-                        err(udev, "failed to poll: %m\n");
-                        goto out;
-                }
-                if (fdcount == 0) {
-                        err(udev, "timeout '%s'\n", 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 {
-                                                err(udev, "'%s' ressize %zd too short\n", 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')
-                                                        info(udev, "'%s'(%s) '%s'\n", cmd, *fd == fd_stdout ? "out" : "err" , line);
-                                        }
-                                }
-                        } else if (ev[i].events & EPOLLHUP) {
-                                if (epoll_ctl(fd_ep, EPOLL_CTL_DEL, *fd, NULL) < 0) {
-                                        err(udev, "failed to remove fd from epoll: %m\n");
-                                        goto out;
-                                }
-                                *fd = -1;
-                        }
-                }
-        }
-
-        /* return the child's stdout string */
-        if (result != NULL) {
-                result[respos] = '\0';
-                dbg(udev, "result='%s'\n", result);
-        }
-out:
-        if (fd_ep >= 0)
-                close(fd_ep);
-}
-
-static int spawn_wait(struct udev_event *event, const char *cmd, pid_t pid)
-{
-        struct udev *udev = event->udev;
-        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) {
-                        unsigned long long age_usec;
-
-                        age_usec = now_usec() - 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;
-                        err(udev, "failed to poll: %m\n");
-                        goto out;
-                }
-                if (fdcount == 0) {
-                        err(udev, "timeout: killing '%s' [%u]\n", 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)) {
-                                        info(udev, "'%s' [%u] exit with return code %i\n", cmd, pid, WEXITSTATUS(status));
-                                        if (WEXITSTATUS(status) != 0)
-                                                err = -1;
-                                } else if (WIFSIGNALED(status)) {
-                                        err(udev, "'%s' [%u] terminated by signal %i (%s)\n", cmd, pid, WTERMSIG(status), strsignal(WTERMSIG(status)));
-                                        err = -1;
-                                } else if (WIFSTOPPED(status)) {
-                                        err(udev, "'%s' [%u] stopped\n", cmd, pid);
-                                        err = -1;
-                                } else if (WIFCONTINUED(status)) {
-                                        err(udev, "'%s' [%u] continued\n", cmd, pid);
-                                        err = -1;
-                                } else {
-                                        err(udev, "'%s' [%u] exit with status 0x%04x\n", 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++;
-                }
-                dbg(udev, "argv[%i] '%s'\n", i, argv[i]);
-                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;
-
-        util_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;
-                        err(udev, "pipe failed: %m\n");
-                        goto out;
-                }
-        }
-        if (udev_get_log_priority(udev) >= LOG_INFO) {
-                if (pipe2(errpipe, O_NONBLOCK) != 0) {
-                        err = -errno;
-                        err(udev, "pipe failed: %m\n");
-                        goto out;
-                }
-        }
-
-        /* allow programs in /usr/lib/udev/ to be called without the path */
-        if (argv[0][0] != '/') {
-                util_strscpyl(program, sizeof(program), PKGLIBEXECDIR "/", 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;
-                }
-
-                info(udev, "starting '%s'\n", cmd);
-
-                err = spawn_exec(event, cmd, argv, envp, sigmask,
-                                 outpipe[WRITE_END], errpipe[WRITE_END]);
-
-                _exit(2 );
-        case -1:
-                err(udev, "fork of '%s' failed: %m\n", 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 void rename_netif_kernel_log(struct ifreq ifr)
-{
-        int klog;
-        FILE *f;
-
-        klog = open("/dev/kmsg", O_WRONLY);
-        if (klog < 0)
-                return;
-
-        f = fdopen(klog, "w");
-        if (f == NULL) {
-                close(klog);
-                return;
-        }
-
-        fprintf(f, "<30>udevd[%u]: renamed network interface %s to %s\n",
-                getpid(), ifr.ifr_name, ifr.ifr_newname);
-        fclose(f);
-}
-
-static int rename_netif(struct udev_event *event)
-{
-        struct udev_device *dev = event->dev;
-        int sk;
-        struct ifreq ifr;
-        int loop;
-        int err;
-
-        info(event->udev, "changing net interface name from '%s' to '%s'\n",
-             udev_device_get_sysname(dev), event->name);
-
-        sk = socket(PF_INET, SOCK_DGRAM, 0);
-        if (sk < 0) {
-                err = -errno;
-                err(event->udev, "error opening socket: %m\n");
-                return err;
-        }
-
-        memset(&ifr, 0x00, sizeof(struct ifreq));
-        util_strscpy(ifr.ifr_name, IFNAMSIZ, udev_device_get_sysname(dev));
-        util_strscpy(ifr.ifr_newname, IFNAMSIZ, event->name);
-        err = ioctl(sk, SIOCSIFNAME, &ifr);
-        if (err == 0) {
-                rename_netif_kernel_log(ifr);
-                goto out;
-        }
-
-        /* keep trying if the destination interface name already exists */
-        err = -errno;
-        if (err != -EEXIST)
-                goto out;
-
-        /* free our own name, another process may wait for us */
-        snprintf(ifr.ifr_newname, IFNAMSIZ, "rename%u", udev_device_get_ifindex(dev));
-        err = ioctl(sk, SIOCSIFNAME, &ifr);
-        if (err < 0) {
-                err = -errno;
-                goto out;
-        }
-
-        /* log temporary name */
-        rename_netif_kernel_log(ifr);
-
-        /* wait a maximum of 90 seconds for our target to become available */
-        util_strscpy(ifr.ifr_name, IFNAMSIZ, ifr.ifr_newname);
-        util_strscpy(ifr.ifr_newname, IFNAMSIZ, event->name);
-        loop = 90 * 20;
-        while (loop--) {
-                const struct timespec duration = { 0, 1000 * 1000 * 1000 / 20 };
-
-                dbg(event->udev, "wait for netif '%s' to become free, loop=%i\n",
-                    event->name, (90 * 20) - loop);
-                nanosleep(&duration, NULL);
-
-                err = ioctl(sk, SIOCSIFNAME, &ifr);
-                if (err == 0) {
-                        rename_netif_kernel_log(ifr);
-                        break;
-                }
-                err = -errno;
-                if (err != -EEXIST)
-                        break;
-        }
-
-out:
-        if (err < 0)
-                err(event->udev, "error changing net interface name %s to %s: %m\n", ifr.ifr_name, ifr.ifr_newname);
-        close(sk);
-        return err;
-}
-
-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 (strcmp(udev_device_get_action(dev), "remove") == 0) {
-                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_from_syspath(event->udev, udev_device_get_syspath(dev));
-                if (event->dev_db != NULL) {
-                        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 && strcmp(udev_device_get_action(dev), "add") == 0 &&
-                    event->name != NULL && strcmp(event->name, udev_device_get_sysname(dev)) != 0) {
-                        char syspath[UTIL_PATH_SIZE];
-                        char *pos;
-
-                        err = rename_netif(event);
-                        if (err == 0) {
-                                info(event->udev, "renamed netif to '%s'\n", 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 */
-                                util_strscpy(syspath, sizeof(syspath), udev_device_get_syspath(dev));
-                                pos = strrchr(syspath, '/');
-                                if (pos != NULL) {
-                                        pos++;
-                                        util_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));
-                                        info(event->udev, "changed devpath to '%s'\n", udev_device_get_devpath(dev));
-                                }
-                        }
-                }
-
-                if (major(udev_device_get_devnum(dev)) > 0) {
-                        /* 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->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;
-                                }
-                        }
-
-                        udev_node_add(dev, event->mode, event->uid, event->gid);
-                }
-
-                /* 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_usec());
-
-                /* (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;
-        }
-out:
-        return err;
-}
-
-int udev_event_execute_run(struct udev_event *event, const sigset_t *sigmask)
-{
-        struct udev_list_entry *list_entry;
-        int err = 0;
-
-        dbg(event->udev, "executing run list\n");
-        udev_list_entry_foreach(list_entry, udev_list_get_entry(&event->run_list)) {
-                const char *cmd = udev_list_entry_get_name(list_entry);
-
-                if (strncmp(cmd, "socket:", strlen("socket:")) == 0) {
-                        struct udev_monitor *monitor;
-
-                        monitor = udev_monitor_new_from_socket(event->udev, &cmd[strlen("socket:")]);
-                        if (monitor == NULL)
-                                continue;
-                        udev_monitor_send_device(monitor, NULL, event->dev);
-                        udev_monitor_unref(monitor);
-                } else {
-                        char program[UTIL_PATH_SIZE];
-                        char **envp;
-
-                        if (event->exec_delay > 0) {
-                                info(event->udev, "delay execution of '%s'\n", program);
-                                sleep(event->exec_delay);
-                        }
-
-                        udev_event_apply_format(event, cmd, program, sizeof(program));
-                        envp = udev_device_get_properties_envp(event->dev);
-                        if (udev_event_spawn(event, program, envp, sigmask, NULL, 0) < 0) {
-                                if (udev_list_entry_get_num(list_entry))
-                                        err = -1;
-                        }
-                }
-        }
-        return err;
-}
diff --git a/src/udev/src/udev-kernel.socket b/src/udev/src/udev-kernel.socket
deleted file mode 100644 (file)
index 23fa9d5..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-[Unit]
-Description=udev Kernel Socket
-DefaultDependencies=no
-ConditionCapability=CAP_MKNOD
-
-[Socket]
-Service=udev.service
-ReceiveBuffer=134217728
-ListenNetlink=kobject-uevent 1
-PassCredentials=yes
diff --git a/src/udev/src/udev-node.c b/src/udev/src/udev-node.c
deleted file mode 100644 (file)
index 7a01a47..0000000
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * Copyright (C) 2003-2010 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <grp.h>
-#include <dirent.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include "udev.h"
-
-#define TMP_FILE_EXT                ".udev-tmp"
-
-static int node_symlink(struct udev *udev, 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 + sizeof(TMP_FILE_EXT)];
-        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 = util_strpcpy(&s, l, "../");
-                i++;
-        }
-        l = util_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)) {
-                        struct stat stats2;
-
-                        info(udev, "found existing node instead of symlink '%s'\n", slink);
-                        if (lstat(node, &stats2) == 0) {
-                                if ((stats.st_mode & S_IFMT) == (stats2.st_mode & S_IFMT) &&
-                                    stats.st_rdev == stats2.st_rdev && stats.st_ino != stats2.st_ino) {
-                                        info(udev, "replace device node '%s' with symlink to our node '%s'\n",
-                                             slink, node);
-                                } else {
-                                        err(udev, "device node '%s' already exists, "
-                                            "link to '%s' will not overwrite it\n",
-                                            slink, node);
-                                        goto exit;
-                                }
-                        }
-                } else if (S_ISLNK(stats.st_mode)) {
-                        char buf[UTIL_PATH_SIZE];
-                        int len;
-
-                        dbg(udev, "found existing symlink '%s'\n", slink);
-                        len = readlink(slink, buf, sizeof(buf));
-                        if (len > 0 && len < (int)sizeof(buf)) {
-                                buf[len] = '\0';
-                                if (strcmp(target, buf) == 0) {
-                                        info(udev, "preserve already existing symlink '%s' to '%s'\n",
-                                             slink, target);
-                                        udev_selinux_lsetfilecon(udev, slink, S_IFLNK);
-                                        utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW);
-                                        goto exit;
-                                }
-                        }
-                }
-        } else {
-                info(udev, "creating symlink '%s' to '%s'\n", slink, target);
-                do {
-                        err = util_create_path_selinux(udev, slink);
-                        if (err != 0 && err != -ENOENT)
-                                break;
-                        udev_selinux_setfscreatecon(udev, slink, S_IFLNK);
-                        err = symlink(target, slink);
-                        if (err != 0)
-                                err = -errno;
-                        udev_selinux_resetfscreatecon(udev);
-                } while (err == -ENOENT);
-                if (err == 0)
-                        goto exit;
-        }
-
-        info(udev, "atomically replace '%s'\n", slink);
-        util_strscpyl(slink_tmp, sizeof(slink_tmp), slink, TMP_FILE_EXT, NULL);
-        unlink(slink_tmp);
-        do {
-                err = util_create_path_selinux(udev, slink_tmp);
-                if (err != 0 && err != -ENOENT)
-                        break;
-                udev_selinux_setfscreatecon(udev, slink_tmp, S_IFLNK);
-                err = symlink(target, slink_tmp);
-                if (err != 0)
-                        err = -errno;
-                udev_selinux_resetfscreatecon(udev);
-        } while (err == -ENOENT);
-        if (err != 0) {
-                err(udev, "symlink '%s' '%s' failed: %m\n", target, slink_tmp);
-                goto exit;
-        }
-        err = rename(slink_tmp, slink);
-        if (err != 0) {
-                err(udev, "rename '%s' '%s' failed: %m\n", 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);
-                util_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;
-
-                info(udev, "found '%s' claiming '%s'\n", dent->d_name, stackdir);
-
-                /* did we find ourself? */
-                if (strcmp(dent->d_name, udev_device_get_id_filename(dev)) == 0)
-                        continue;
-
-                dev_db = udev_device_new_from_id_filename(udev, dent->d_name);
-                if (dev_db != NULL) {
-                        const char *devnode;
-
-                        devnode = udev_device_get_devnode(dev_db);
-                        if (devnode != NULL) {
-                                dbg(udev, "compare priority of '%s'(%i) > '%s'(%i)\n", target, priority,
-                                    udev_device_get_devnode(dev_db), udev_device_get_devlink_priority(dev_db));
-                                if (target == NULL || udev_device_get_devlink_priority(dev_db) > priority) {
-                                        info(udev, "'%s' claims priority %i for '%s'\n",
-                                             udev_device_get_syspath(dev_db), udev_device_get_devlink_priority(dev_db), stackdir);
-                                        priority = udev_device_get_devlink_priority(dev_db);
-                                        util_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];
-
-        dbg(udev, "update symlink '%s' of '%s'\n", slink, udev_device_get_syspath(dev));
-
-        util_path_encode(&slink[strlen(udev_get_dev_path(udev))+1], name_enc, sizeof(name_enc));
-        util_strscpyl(dirname, sizeof(dirname), udev_get_run_path(udev), "/links/", name_enc, NULL);
-        util_strscpyl(filename, sizeof(filename), dirname, "/", udev_device_get_id_filename(dev), NULL);
-
-        if (!add) {
-                dbg(udev, "removing index: '%s'\n", filename);
-                if (unlink(filename) == 0)
-                        rmdir(dirname);
-        }
-
-        target = link_find_prioritized(dev, add, dirname, buf, sizeof(buf));
-        if (target == NULL) {
-                info(udev, "no reference left, remove '%s'\n", slink);
-                if (unlink(slink) == 0)
-                        util_delete_path(udev, slink);
-        } else {
-                info(udev, "creating link '%s' to '%s'\n", slink, target);
-                node_symlink(udev, target, slink);
-        }
-
-        if (add) {
-                int err;
-
-                dbg(udev, "creating index: '%s'\n", filename);
-                do {
-                        int fd;
-
-                        err = util_create_path(udev, filename);
-                        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 *udev = udev_device_get_udev(dev);
-        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 (strcmp(name, name_current) == 0) {
-                                found = 1;
-                                break;
-                        }
-                }
-                if (found)
-                        continue;
-
-                info(udev, "update old name, '%s' no longer belonging to '%s'\n",
-                     name, udev_device_get_devpath(dev));
-                link_update(dev, name, 0);
-        }
-}
-
-static int node_fixup(struct udev_device *dev, mode_t mode, uid_t uid, gid_t gid)
-{
-        struct udev *udev = udev_device_get_udev(dev);
-        const char *devnode = udev_device_get_devnode(dev);
-        dev_t devnum = udev_device_get_devnum(dev);
-        struct stat stats;
-        int err = 0;
-
-        if (strcmp(udev_device_get_subsystem(dev), "block") == 0)
-                mode |= S_IFBLK;
-        else
-                mode |= S_IFCHR;
-
-        if (lstat(devnode, &stats) != 0) {
-                err = -errno;
-                info(udev, "can not stat() node '%s' (%m)\n", devnode);
-                goto out;
-        }
-
-        if (((stats.st_mode & S_IFMT) != (mode & S_IFMT)) || (stats.st_rdev != devnum)) {
-                err = -EEXIST;
-                info(udev, "found node '%s' with non-matching devnum %s, skip handling\n",
-                     udev_device_get_devnode(dev), udev_device_get_id_filename(dev));
-                goto out;
-        }
-
-        if ((stats.st_mode & 0777) != (mode & 0777) || stats.st_uid != uid || stats.st_gid != gid) {
-                info(udev, "set permissions %s, %#o, uid=%u, gid=%u\n", devnode, mode, uid, gid);
-                chmod(devnode, mode);
-                chown(devnode, uid, gid);
-        } else {
-                info(udev, "preserve permissions %s, %#o, uid=%u, gid=%u\n", devnode, mode, uid, gid);
-        }
-
-        /*
-         * Set initial selinux file context only on add events.
-         * We set the proper context on bootup (triger) or for newly
-         * added devices, but we don't change it later, in case
-         * something else has set a custom context in the meantime.
-         */
-        if (strcmp(udev_device_get_action(dev), "add") == 0)
-                udev_selinux_lsetfilecon(udev, devnode, mode);
-
-        /* 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, mode_t mode, uid_t uid, gid_t gid)
-{
-        struct udev *udev = udev_device_get_udev(dev);
-        char filename[UTIL_PATH_SIZE];
-        struct udev_list_entry *list_entry;
-        int err = 0;
-
-        info(udev, "handling device node '%s', devnum=%s, mode=%#o, uid=%d, gid=%d\n",
-             udev_device_get_devnode(dev), udev_device_get_id_filename(dev), mode, uid, gid);
-
-        if (node_fixup(dev, mode, uid, gid) < 0)
-                return;
-
-        /* always add /dev/{block,char}/$major:$minor */
-        snprintf(filename, sizeof(filename), "%s/%s/%u:%u",
-                 udev_get_dev_path(udev),
-                 strcmp(udev_device_get_subsystem(dev), "block") == 0 ? "block" : "char",
-                 major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev)));
-        node_symlink(udev, 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)) {
-                if (udev_list_entry_get_num(list_entry))
-                        /* simple unmanaged link name */
-                        node_symlink(udev, udev_device_get_devnode(dev), udev_list_entry_get_name(list_entry));
-                else
-                        link_update(dev, udev_list_entry_get_name(list_entry), 1);
-        }
-}
-
-void udev_node_remove(struct udev_device *dev)
-{
-        struct udev *udev = udev_device_get_udev(dev);
-        struct udev_list_entry *list_entry;
-        const char *devnode;
-        struct stat stats;
-        struct udev_device *dev_check;
-        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), 0);
-
-        /* remove /dev/{block,char}/$major:$minor */
-        snprintf(filename, sizeof(filename), "%s/%s/%u:%u",
-                 udev_get_dev_path(udev),
-                 strcmp(udev_device_get_subsystem(dev), "block") == 0 ? "block" : "char",
-                 major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev)));
-        unlink(filename);
-}
diff --git a/src/udev/src/udev-rules.c b/src/udev/src/udev-rules.c
deleted file mode 100644 (file)
index 8a85eae..0000000
+++ /dev/null
@@ -1,2767 +0,0 @@
-/*
- * Copyright (C) 2003-2010 Kay Sievers <kay.sievers@vrfy.org>
- * Copyright (C) 2008 Alan Jenkins <alan-jenkins@tuffmail.co.uk>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stddef.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <string.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <errno.h>
-#include <dirent.h>
-#include <fnmatch.h>
-#include <time.h>
-
-#include "udev.h"
-
-#define PREALLOC_TOKEN          2048
-#define PREALLOC_STRBUF         32 * 1024
-#define PREALLOC_TRIE           256
-
-struct uid_gid {
-        unsigned int name_off;
-        union {
-                uid_t uid;
-                gid_t gid;
-        };
-};
-
-struct trie_node {
-        /* this node's first child */
-        unsigned int child_idx;
-        /* the next child of our parent node's child list */
-        unsigned int next_child_idx;
-        /* this node's last child (shortcut for append) */
-        unsigned int last_child_idx;
-        unsigned int value_off;
-        unsigned short value_len;
-        unsigned char key;
-};
-
-struct udev_rules {
-        struct udev *udev;
-        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 to a single string buffer */
-        char *buf;
-        size_t buf_cur;
-        size_t buf_max;
-        unsigned int buf_count;
-
-        /* during rule parsing, strings are indexed to find duplicates */
-        struct trie_node *trie_nodes;
-        unsigned int trie_nodes_cur;
-        unsigned int trie_nodes_max;
-
-        /* 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;
-};
-
-/* 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_STATIC_NODE,               /* val */
-        TK_A_ENV,                       /* val, attr */
-        TK_A_TAG,                       /* val */
-        TK_A_NAME,                      /* val */
-        TK_A_DEVLINK,                   /* val */
-        TK_A_ATTR,                      /* val, attr */
-        TK_A_RUN,                       /* 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;
-                                int devlink_unique;
-                                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 ENABLE_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_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] =                    "A RUN",
-                [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 = &rules->buf[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);
-
-                        dbg(rules->udev, "* RULE %s:%u, token: %u, count: %u, label: '%s'\n",
-                            &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:
-                dbg(rules->udev, "%s %s '%s'(%s)\n",
-                    token_str(type), operation_str(op), value, string_glob_str(glob));
-                break;
-        case TK_M_IMPORT_BUILTIN:
-                dbg(rules->udev, "%s %i '%s'\n", 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:
-                dbg(rules->udev, "%s %s '%s' '%s'(%s)\n",
-                    token_str(type), operation_str(op), attr, value, string_glob_str(glob));
-                break;
-        case TK_M_TAG:
-        case TK_A_TAG:
-                dbg(rules->udev, "%s %s '%s'\n", 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:
-                dbg(rules->udev, "%s\n", token_str(type));
-                break;
-        case TK_M_TEST:
-                dbg(rules->udev, "%s %s '%s'(%s) %#o\n",
-                    token_str(type), operation_str(op), value, string_glob_str(glob), token->key.mode);
-                break;
-        case TK_A_INOTIFY_WATCH:
-                dbg(rules->udev, "%s %u\n", token_str(type), token->key.watch);
-                break;
-        case TK_A_DEVLINK_PRIO:
-                dbg(rules->udev, "%s %u\n", token_str(type), token->key.devlink_prio);
-                break;
-        case TK_A_OWNER_ID:
-                dbg(rules->udev, "%s %s %u\n", token_str(type), operation_str(op), token->key.uid);
-                break;
-        case TK_A_GROUP_ID:
-                dbg(rules->udev, "%s %s %u\n", token_str(type), operation_str(op), token->key.gid);
-                break;
-        case TK_A_MODE_ID:
-                dbg(rules->udev, "%s %s %#o\n", token_str(type), operation_str(op), token->key.mode);
-                break;
-        case TK_A_STATIC_NODE:
-                dbg(rules->udev, "%s '%s'\n", token_str(type), value);
-                break;
-        case TK_M_EVENT_TIMEOUT:
-                dbg(rules->udev, "%s %u\n", token_str(type), token->key.event_timeout);
-                break;
-        case TK_A_GOTO:
-                dbg(rules->udev, "%s '%s' %u\n", token_str(type), value, token->key.rule_goto);
-                break;
-        case TK_END:
-                dbg(rules->udev, "* %s\n", token_str(type));
-                break;
-        case TK_M_PARENTS_MIN:
-        case TK_M_PARENTS_MAX:
-        case TK_M_MAX:
-        case TK_UNSET:
-                dbg(rules->udev, "unknown type %u\n", type);
-                break;
-        }
-}
-
-static void dump_rules(struct udev_rules *rules)
-{
-        unsigned int i;
-
-        dbg(rules->udev, "dumping %u (%zu bytes) tokens, %u (%zu bytes) strings\n",
-            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 const char *operation_str(enum operation_type type) { return NULL; }
-static inline const char *token_str(enum token_type type) { return NULL; }
-static inline void dump_token(struct udev_rules *rules, struct token *token) {}
-static inline void dump_rules(struct udev_rules *rules) {}
-#endif /* ENABLE_DEBUG */
-
-static int add_new_string(struct udev_rules *rules, const char *str, size_t bytes)
-{
-        int off;
-
-        /* grow buffer if needed */
-        if (rules->buf_cur + bytes+1 >= rules->buf_max) {
-                char *buf;
-                unsigned int add;
-
-                /* double the buffer size */
-                add = rules->buf_max;
-                if (add < bytes * 8)
-                        add = bytes * 8;
-
-                buf = realloc(rules->buf, rules->buf_max + add);
-                if (buf == NULL)
-                        return -1;
-                dbg(rules->udev, "extend buffer from %zu to %zu\n", rules->buf_max, rules->buf_max + add);
-                rules->buf = buf;
-                rules->buf_max += add;
-        }
-        off = rules->buf_cur;
-        memcpy(&rules->buf[rules->buf_cur], str, bytes);
-        rules->buf_cur += bytes;
-        rules->buf_count++;
-        return off;
-}
-
-static int add_string(struct udev_rules *rules, const char *str)
-{
-        unsigned int node_idx;
-        struct trie_node *new_node;
-        unsigned int new_node_idx;
-        unsigned char key;
-        unsigned short len;
-        unsigned int depth;
-        unsigned int off;
-        struct trie_node *parent;
-
-        /* walk trie, start from last character of str to find matching tails */
-        len = strlen(str);
-        key = str[len-1];
-        node_idx = 0;
-        for (depth = 0; depth <= len; depth++) {
-                struct trie_node *node;
-                unsigned int child_idx;
-
-                node = &rules->trie_nodes[node_idx];
-                off = node->value_off + node->value_len - len;
-
-                /* match against current node */
-                if (depth == len || (node->value_len >= len && memcmp(&rules->buf[off], str, len) == 0))
-                        return off;
-
-                /* lookup child node */
-                key = str[len - 1 - depth];
-                child_idx = node->child_idx;
-                while (child_idx > 0) {
-                        struct trie_node *child;
-
-                        child = &rules->trie_nodes[child_idx];
-                        if (child->key == key)
-                                break;
-                        child_idx = child->next_child_idx;
-                }
-                if (child_idx == 0)
-                        break;
-                node_idx = child_idx;
-        }
-
-        /* string not found, add it */
-        off = add_new_string(rules, str, len + 1);
-
-        /* grow trie nodes if needed */
-        if (rules->trie_nodes_cur >= rules->trie_nodes_max) {
-                struct trie_node *nodes;
-                unsigned int add;
-
-                /* double the buffer size */
-                add = rules->trie_nodes_max;
-                if (add < 8)
-                        add = 8;
-
-                nodes = realloc(rules->trie_nodes, (rules->trie_nodes_max + add) * sizeof(struct trie_node));
-                if (nodes == NULL)
-                        return -1;
-                dbg(rules->udev, "extend trie nodes from %u to %u\n",
-                    rules->trie_nodes_max, rules->trie_nodes_max + add);
-                rules->trie_nodes = nodes;
-                rules->trie_nodes_max += add;
-        }
-
-        /* get a new node */
-        new_node_idx = rules->trie_nodes_cur;
-        rules->trie_nodes_cur++;
-        new_node = &rules->trie_nodes[new_node_idx];
-        memset(new_node, 0x00, sizeof(struct trie_node));
-        new_node->value_off = off;
-        new_node->value_len = len;
-        new_node->key = key;
-
-        /* join the parent's child list */
-        parent = &rules->trie_nodes[node_idx];
-        if (parent->child_idx == 0) {
-                parent->child_idx = new_node_idx;
-        } else {
-                struct trie_node *last_child;
-
-                last_child = &rules->trie_nodes[parent->last_child_idx];
-                last_child->next_child_idx = new_node_idx;
-        }
-        parent->last_child_idx = new_node_idx;
-        return off;
-}
-
-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;
-                dbg(rules->udev, "extend tokens from %u to %u\n", rules->token_max, rules->token_max + add);
-                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 (strcmp(&rules->buf[off], owner) == 0) {
-                        uid = rules->uids[i].uid;
-                        dbg(rules->udev, "return existing %u for '%s'\n", uid, owner);
-                        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;
-                dbg(rules->udev, "extend uids from %u to %u\n", rules->uids_max, rules->uids_max + add);
-                rules->uids = uids;
-                rules->uids_max += add;
-        }
-        rules->uids[rules->uids_cur].uid = uid;
-        off = 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 (strcmp(&rules->buf[off], group) == 0) {
-                        gid = rules->gids[i].gid;
-                        dbg(rules->udev, "return existing %u for '%s'\n", gid, group);
-                        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;
-                dbg(rules->udev, "extend gids from %u to %u\n", rules->gids_max, rules->gids_max + add);
-                rules->gids = gids;
-                rules->gids_max += add;
-        }
-        rules->gids[rules->gids_cur].gid = gid;
-        off = 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)
-{
-        struct udev *udev = udev_device_get_udev(dev);
-        char *key;
-        char *val;
-        size_t len;
-
-        /* 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]) {
-                        info(udev, "inconsistent quoting: '%s', skip\n", line);
-                        return -1;
-                }
-                val[len-1] = '\0';
-                val++;
-        }
-
-        dbg(udev, "adding '%s'='%s'\n", key, val);
-
-        /* handle device, renamed by external tool, returning new path */
-        if (strcmp(key, "DEVPATH") == 0) {
-                char syspath[UTIL_PATH_SIZE];
-
-                info(udev, "updating devpath from '%s' to '%s'\n",
-                     udev_device_get_devpath(dev), val);
-                util_strscpyl(syspath, sizeof(syspath), udev_get_sys_path(udev), val, NULL);
-                udev_device_set_syspath(dev, syspath);
-        } else {
-                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;
-}
-
-static int import_file_into_properties(struct udev_device *dev, const char *filename)
-{
-        FILE *f;
-        char line[UTIL_LINE_SIZE];
-
-        f = fopen(filename, "r");
-        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 *udev = udev_device_get_udev(dev);
-        struct udev_device *dev_parent;
-        struct udev_list_entry *list_entry;
-
-        dev_parent = udev_device_get_parent(dev);
-        if (dev_parent == NULL)
-                return -1;
-
-        dbg(udev, "found parent '%s', get the node name\n", udev_device_get_syspath(dev_parent));
-        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;
-
-                        dbg(udev, "import key '%s=%s'\n", key, 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;
-}
-
-#define WAIT_LOOP_PER_SECOND                50
-static int wait_for_file(struct udev_device *dev, const char *file, int timeout)
-{
-        struct udev *udev = udev_device_get_udev(dev);
-        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] != '/') {
-                util_strscpyl(devicepath, sizeof(devicepath),
-                              udev_get_sys_path(udev), udev_device_get_devpath(dev), NULL);
-                util_strscpyl(filepath, sizeof(filepath), devicepath, "/", file, NULL);
-                file = filepath;
-        }
-
-        dbg(udev, "will wait %i sec for '%s'\n", timeout, file);
-        while (--loop) {
-                const struct timespec duration = { 0, 1000 * 1000 * 1000 / WAIT_LOOP_PER_SECOND };
-
-                /* lookup file */
-                if (stat(file, &stats) == 0) {
-                        info(udev, "file '%s' appeared after %i loops\n", 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) {
-                        info(udev, "device disappeared while waiting for '%s'\n", file);
-                        return -2;
-                }
-                info(udev, "wait for '%s' for %i mseconds\n", file, 1000 / WAIT_LOOP_PER_SECOND);
-                nanosleep(&duration, NULL);
-        }
-        info(udev, "waiting for '%s' failed\n", 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;
-
-                util_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;
-                                util_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++;
-        dbg(udev, "%s '%s'-'%s'\n", operation_str(*op), *key, *value);
-
-        /* move line to next key */
-        *line = temp;
-        return 0;
-}
-
-/* extract possible KEY{attr} */
-static 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) {
-                        err(udev, "missing closing brace for format\n");
-                        return NULL;
-                }
-                pos[0] = '\0';
-                dbg(udev, "attribute='%s'\n", attr);
-                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;
-
-        memset(token, 0x00, 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_NAME:
-        case TK_A_GOTO:
-        case TK_M_TAG:
-        case TK_A_TAG:
-                token->key.value_off = add_string(rule_tmp->rules, value);
-                break;
-        case TK_M_IMPORT_BUILTIN:
-                token->key.value_off = 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:
-                attr = data;
-                token->key.value_off = add_string(rule_tmp->rules, value);
-                token->key.attr_off = add_string(rule_tmp->rules, attr);
-                break;
-        case TK_A_DEVLINK:
-                token->key.value_off = add_string(rule_tmp->rules, value);
-                token->key.devlink_unique = *(int *)data;
-                break;
-        case TK_M_TEST:
-                token->key.value_off = 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:
-                token->key.value_off = 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_A_STATIC_NODE:
-                token->key.value_off = add_string(rule_tmp->rules, value);
-                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:
-                err(rule_tmp->rules->udev, "wrong type %u\n", 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 = (strchr(value, '*') != NULL || strchr(value, '?') != NULL || strchr(value, '[') != NULL);
-                if (has_split && has_glob) {
-                        glob = GL_SPLIT_GLOB;
-                } else if (has_split) {
-                        glob = GL_SPLIT;
-                } else if (has_glob) {
-                        if (strcmp(value, "?*") == 0)
-                                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/attribut 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 >= ARRAY_SIZE(rule_tmp->token)) {
-                err(rule_tmp->rules->udev, "temporary rule array too small\n");
-                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;
-        char *attr;
-        struct rule_tmp rule_tmp;
-
-        memset(&rule_tmp, 0x00, sizeof(struct rule_tmp));
-        rule_tmp.rules = rules;
-        rule_tmp.rule.type = TK_RULE;
-        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)
-                        break;
-
-                if (strcmp(key, "ACTION") == 0) {
-                        if (op > OP_MATCH_MAX) {
-                                err(rules->udev, "invalid ACTION operation\n");
-                                goto invalid;
-                        }
-                        rule_add_key(&rule_tmp, TK_M_ACTION, op, value, NULL);
-                        continue;
-                }
-
-                if (strcmp(key, "DEVPATH") == 0) {
-                        if (op > OP_MATCH_MAX) {
-                                err(rules->udev, "invalid DEVPATH operation\n");
-                                goto invalid;
-                        }
-                        rule_add_key(&rule_tmp, TK_M_DEVPATH, op, value, NULL);
-                        continue;
-                }
-
-                if (strcmp(key, "KERNEL") == 0) {
-                        if (op > OP_MATCH_MAX) {
-                                err(rules->udev, "invalid KERNEL operation\n");
-                                goto invalid;
-                        }
-                        rule_add_key(&rule_tmp, TK_M_KERNEL, op, value, NULL);
-                        continue;
-                }
-
-                if (strcmp(key, "SUBSYSTEM") == 0) {
-                        if (op > OP_MATCH_MAX) {
-                                err(rules->udev, "invalid SUBSYSTEM operation\n");
-                                goto invalid;
-                        }
-                        /* bus, class, subsystem events should all be the same */
-                        if (strcmp(value, "subsystem") == 0 ||
-                            strcmp(value, "bus") == 0 ||
-                            strcmp(value, "class") == 0) {
-                                if (strcmp(value, "bus") == 0 || strcmp(value, "class") == 0)
-                                        err(rules->udev, "'%s' must be specified as 'subsystem' \n"
-                                            "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 (strcmp(key, "DRIVER") == 0) {
-                        if (op > OP_MATCH_MAX) {
-                                err(rules->udev, "invalid DRIVER operation\n");
-                                goto invalid;
-                        }
-                        rule_add_key(&rule_tmp, TK_M_DRIVER, op, value, NULL);
-                        continue;
-                }
-
-                if (strncmp(key, "ATTR{", sizeof("ATTR{")-1) == 0) {
-                        attr = get_key_attribute(rules->udev, key + sizeof("ATTR")-1);
-                        if (attr == NULL) {
-                                err(rules->udev, "error parsing ATTR attribute\n");
-                                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 (strcmp(key, "KERNELS") == 0) {
-                        if (op > OP_MATCH_MAX) {
-                                err(rules->udev, "invalid KERNELS operation\n");
-                                goto invalid;
-                        }
-                        rule_add_key(&rule_tmp, TK_M_KERNELS, op, value, NULL);
-                        continue;
-                }
-
-                if (strcmp(key, "SUBSYSTEMS") == 0) {
-                        if (op > OP_MATCH_MAX) {
-                                err(rules->udev, "invalid SUBSYSTEMS operation\n");
-                                goto invalid;
-                        }
-                        rule_add_key(&rule_tmp, TK_M_SUBSYSTEMS, op, value, NULL);
-                        continue;
-                }
-
-                if (strcmp(key, "DRIVERS") == 0) {
-                        if (op > OP_MATCH_MAX) {
-                                err(rules->udev, "invalid DRIVERS operation\n");
-                                goto invalid;
-                        }
-                        rule_add_key(&rule_tmp, TK_M_DRIVERS, op, value, NULL);
-                        continue;
-                }
-
-                if (strncmp(key, "ATTRS{", sizeof("ATTRS{")-1) == 0) {
-                        if (op > OP_MATCH_MAX) {
-                                err(rules->udev, "invalid ATTRS operation\n");
-                                goto invalid;
-                        }
-                        attr = get_key_attribute(rules->udev, key + sizeof("ATTRS")-1);
-                        if (attr == NULL) {
-                                err(rules->udev, "error parsing ATTRS attribute\n");
-                                goto invalid;
-                        }
-                        if (strncmp(attr, "device/", 7) == 0)
-                                err(rules->udev, "the 'device' link may not be available in a future kernel, "
-                                    "please fix it in %s:%u", filename, lineno);
-                        else if (strstr(attr, "../") != NULL)
-                                err(rules->udev, "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 (strcmp(key, "TAGS") == 0) {
-                        if (op > OP_MATCH_MAX) {
-                                err(rules->udev, "invalid TAGS operation\n");
-                                goto invalid;
-                        }
-                        rule_add_key(&rule_tmp, TK_M_TAGS, op, value, NULL);
-                        continue;
-                }
-
-                if (strncmp(key, "ENV{", sizeof("ENV{")-1) == 0) {
-                        attr = get_key_attribute(rules->udev, key + sizeof("ENV")-1);
-                        if (attr == NULL) {
-                                err(rules->udev, "error parsing ENV attribute\n");
-                                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 < ARRAY_SIZE(blacklist); i++)
-                                        if (strcmp(attr, blacklist[i]) == 0) {
-                                                err(rules->udev, "invalid ENV attribute, '%s' can not be set %s:%u\n", attr, filename, lineno);
-                                                continue;
-                                        }
-                                if (rule_add_key(&rule_tmp, TK_A_ENV, op, value, attr) != 0)
-                                        goto invalid;
-                        }
-                        continue;
-                }
-
-                if (strcmp(key, "TAG") == 0) {
-                        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 (strcmp(key, "PROGRAM") == 0) {
-                        rule_add_key(&rule_tmp, TK_M_PROGRAM, op, value, NULL);
-                        continue;
-                }
-
-                if (strcmp(key, "RESULT") == 0) {
-                        if (op > OP_MATCH_MAX) {
-                                err(rules->udev, "invalid RESULT operation\n");
-                                goto invalid;
-                        }
-                        rule_add_key(&rule_tmp, TK_M_RESULT, op, value, NULL);
-                        continue;
-                }
-
-                if (strncmp(key, "IMPORT", sizeof("IMPORT")-1) == 0) {
-                        attr = get_key_attribute(rules->udev, key + sizeof("IMPORT")-1);
-                        if (attr == NULL) {
-                                err(rules->udev, "IMPORT{} type missing, ignoring IMPORT %s:%u\n", filename, lineno);
-                                continue;
-                        }
-                        if (strstr(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) {
-                                                info(rules->udev, "IMPORT found builtin '%s', replacing %s:%u\n",
-                                                     value, filename, lineno);
-                                                rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd);
-                                                continue;
-                                        }
-                                }
-                                dbg(rules->udev, "IMPORT will be executed\n");
-                                rule_add_key(&rule_tmp, TK_M_IMPORT_PROG, op, value, NULL);
-                        } else if (strstr(attr, "builtin")) {
-                                enum udev_builtin_cmd cmd = udev_builtin_lookup(value);
-
-                                dbg(rules->udev, "IMPORT execute builtin\n");
-                                if (cmd < UDEV_BUILTIN_MAX)
-                                        rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd);
-                                else
-                                        err(rules->udev, "IMPORT{builtin}: '%s' unknown %s:%u\n", value, filename, lineno);
-                        } else if (strstr(attr, "file")) {
-                                dbg(rules->udev, "IMPORT will be included as file\n");
-                                rule_add_key(&rule_tmp, TK_M_IMPORT_FILE, op, value, NULL);
-                        } else if (strstr(attr, "db")) {
-                                dbg(rules->udev, "IMPORT will include db values\n");
-                                rule_add_key(&rule_tmp, TK_M_IMPORT_DB, op, value, NULL);
-                        } else if (strstr(attr, "cmdline")) {
-                                dbg(rules->udev, "IMPORT will include db values\n");
-                                rule_add_key(&rule_tmp, TK_M_IMPORT_CMDLINE, op, value, NULL);
-                        } else if (strstr(attr, "parent")) {
-                                dbg(rules->udev, "IMPORT will include the parent values\n");
-                                rule_add_key(&rule_tmp, TK_M_IMPORT_PARENT, op, value, NULL);
-                        }
-                        continue;
-                }
-
-                if (strncmp(key, "TEST", sizeof("TEST")-1) == 0) {
-                        mode_t mode = 0;
-
-                        if (op > OP_MATCH_MAX) {
-                                err(rules->udev, "invalid TEST operation\n");
-                                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 (strcmp(key, "RUN") == 0) {
-                        if (strncmp(value, "socket:", 7) == 0)
-                                err(rules->udev, "RUN+=\"socket:...\" support will be removed from a future udev release. "
-                                    "Please remove it from: %s:%u and use libudev to subscribe to events.\n", filename, lineno);
-                        rule_add_key(&rule_tmp, TK_A_RUN, op, value, NULL);
-                        continue;
-                }
-
-                if (strcmp(key, "WAIT_FOR") == 0 || strcmp(key, "WAIT_FOR_SYSFS") == 0) {
-                        rule_add_key(&rule_tmp, TK_M_WAITFOR, 0, value, NULL);
-                        continue;
-                }
-
-                if (strcmp(key, "LABEL") == 0) {
-                        rule_tmp.rule.rule.label_off = add_string(rules, value);
-                        continue;
-                }
-
-                if (strcmp(key, "GOTO") == 0) {
-                        rule_add_key(&rule_tmp, TK_A_GOTO, 0, value, NULL);
-                        continue;
-                }
-
-                if (strncmp(key, "NAME", sizeof("NAME")-1) == 0) {
-                        if (op < OP_MATCH_MAX) {
-                                rule_add_key(&rule_tmp, TK_M_NAME, op, value, NULL);
-                        } else {
-                                if (strcmp(value, "%k") == 0) {
-                                        err(rules->udev, "NAME=\"%%k\" is ignored, because it breaks kernel supplied names, "
-                                            "please remove it from %s:%u\n", filename, lineno);
-                                        continue;
-                                }
-                                if (value[0] == '\0') {
-                                        info(rules->udev, "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 (strncmp(key, "SYMLINK", sizeof("SYMLINK")-1) == 0) {
-                        if (op < OP_MATCH_MAX) {
-                                rule_add_key(&rule_tmp, TK_M_DEVLINK, op, value, NULL);
-                        } else {
-                                int flag = 0;
-
-                                attr = get_key_attribute(rules->udev, key + sizeof("SYMLINK")-1);
-                                if (attr != NULL && strstr(attr, "unique") != NULL)
-                                        flag = 1;
-                                rule_add_key(&rule_tmp, TK_A_DEVLINK, op, value, &flag);
-                        }
-                        rule_tmp.rule.rule.can_set_name = true;
-                        continue;
-                }
-
-                if (strcmp(key, "OWNER") == 0) {
-                        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 (strcmp(key, "GROUP") == 0) {
-                        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 (strcmp(key, "MODE") == 0) {
-                        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 (strcmp(key, "OPTIONS") == 0) {
-                        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);
-                                dbg(rules->udev, "link priority=%i\n", 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);
-                                dbg(rules->udev, "event timeout=%i\n", tout);
-                        }
-
-                        pos = strstr(value, "string_escape=");
-                        if (pos != NULL) {
-                                pos = &pos[strlen("string_escape=")];
-                                if (strncmp(pos, "none", strlen("none")) == 0)
-                                        rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_NONE, op, NULL, NULL);
-                                else if (strncmp(pos, "replace", strlen("replace")) == 0)
-                                        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);
-                                dbg(rules->udev, "inotify watch of device disabled\n");
-                        } else {
-                                pos = strstr(value, "watch");
-                                if (pos != NULL) {
-                                        const int on = 1;
-
-                                        rule_add_key(&rule_tmp, TK_A_INOTIFY_WATCH, op, NULL, &on);
-                                        dbg(rules->udev, "inotify watch of device requested\n");
-                                }
-                        }
-
-                        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;
-                }
-
-                err(rules->udev, "unknown key '%s' in %s:%u\n", 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:
-        err(rules->udev, "invalid rule '%s:%u'\n", filename, lineno);
-        return -1;
-}
-
-static int parse_file(struct udev_rules *rules, const char *filename, unsigned short filename_off)
-{
-        FILE *f;
-        unsigned int first_token;
-        char line[UTIL_LINE_SIZE];
-        int line_nr = 0;
-        unsigned int i;
-
-        info(rules->udev, "reading '%s' as rules file\n", filename);
-
-        f = fopen(filename, "r");
-        if (f == NULL)
-                return -1;
-
-        first_token = rules->token_cur;
-
-        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)) {
-                        err(rules->udev, "line too long '%s':%u, ignored\n", 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->buf[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 (strcmp(label, &rules->buf[rules->tokens[j].rule.label_off]) != 0)
-                                        continue;
-                                rules->tokens[i].key.rule_goto = j;
-                                break;
-                        }
-                        if (rules->tokens[i].key.rule_goto == 0)
-                                err(rules->udev, "GOTO '%s' has no matching label in: '%s'\n", label, filename);
-                }
-        }
-        return 0;
-}
-
-static int add_matching_files(struct udev *udev, struct udev_list *file_list, const char *dirname, const char *suffix)
-{
-        DIR *dir;
-        struct dirent *dent;
-        char filename[UTIL_PATH_SIZE];
-
-        dbg(udev, "open directory '%s'\n", dirname);
-        dir = opendir(dirname);
-        if (dir == NULL) {
-                info(udev, "unable to open '%s': %m\n", dirname);
-                return -1;
-        }
-
-        for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
-                if (dent->d_name[0] == '.')
-                        continue;
-
-                /* look for file matching with specified suffix */
-                if (suffix != NULL) {
-                        const char *ext;
-
-                        ext = strrchr(dent->d_name, '.');
-                        if (ext == NULL)
-                                continue;
-                        if (strcmp(ext, suffix) != 0)
-                                continue;
-                }
-                util_strscpyl(filename, sizeof(filename), dirname, "/", dent->d_name, NULL);
-                dbg(udev, "put file '%s' into list\n", filename);
-                /*
-                 * the basename is the key, the filename the value
-                 * identical basenames from different directories override each other
-                 * entries are sorted after basename
-                 */
-                udev_list_entry_add(file_list, dent->d_name, filename);
-        }
-
-        closedir(dir);
-        return 0;
-}
-
-struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names)
-{
-        struct udev_rules *rules;
-        struct udev_list file_list;
-        struct udev_list_entry *file_loop;
-        struct token end_token;
-        char **s;
-
-        rules = calloc(1, sizeof(struct udev_rules));
-        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) {
-                free(rules);
-                return NULL;
-        }
-        rules->token_max = PREALLOC_TOKEN;
-
-        rules->buf = malloc(PREALLOC_STRBUF);
-        if (rules->buf == NULL) {
-                free(rules->tokens);
-                free(rules);
-                return NULL;
-        }
-        rules->buf_max = PREALLOC_STRBUF;
-        /* offset 0 is always '\0' */
-        rules->buf[0] = '\0';
-        rules->buf_cur = 1;
-        dbg(udev, "prealloc %zu bytes tokens (%u * %zu bytes), %zu bytes buffer\n",
-            rules->token_max * sizeof(struct token), rules->token_max, sizeof(struct token), rules->buf_max);
-
-        rules->trie_nodes = malloc(PREALLOC_TRIE * sizeof(struct trie_node));
-        if (rules->trie_nodes == NULL) {
-                free(rules->buf);
-                free(rules->tokens);
-                free(rules);
-                return NULL;
-        }
-        rules->trie_nodes_max = PREALLOC_TRIE;
-        /* offset 0 is the trie root, with an empty string */
-        memset(rules->trie_nodes, 0x00, sizeof(struct trie_node));
-        rules->trie_nodes_cur = 1;
-
-        for (udev_get_rules_path(udev, &s, NULL); *s != NULL; s++)
-                add_matching_files(udev, &file_list, *s, ".rules");
-
-        /* add all filenames to the string buffer */
-        udev_list_entry_foreach(file_loop, udev_list_get_entry(&file_list)) {
-                const char *filename = udev_list_entry_get_value(file_loop);
-                unsigned int filename_off;
-
-                filename_off = add_string(rules, filename);
-                /* the offset in the rule is limited to unsigned short */
-                if (filename_off < USHRT_MAX)
-                        udev_list_entry_set_num(file_loop, filename_off);
-        }
-
-        /* parse all rules files */
-        udev_list_entry_foreach(file_loop, udev_list_get_entry(&file_list)) {
-                const char *filename = udev_list_entry_get_value(file_loop);
-                unsigned int filename_off = udev_list_entry_get_num(file_loop);
-                struct stat st;
-
-                if (stat(filename, &st) != 0) {
-                        err(udev, "can not find '%s': %m\n", filename);
-                        continue;
-                }
-                if (S_ISREG(st.st_mode) && st.st_size <= 0) {
-                        info(udev, "ignore empty '%s'\n", filename);
-                        continue;
-                }
-                if (S_ISCHR(st.st_mode)) {
-                        info(udev, "ignore masked '%s'\n", filename);
-                        continue;
-                }
-                parse_file(rules, filename, filename_off);
-        }
-        udev_list_cleanup(&file_list);
-
-        memset(&end_token, 0x00, sizeof(struct token));
-        end_token.type = TK_END;
-        add_token(rules, &end_token);
-
-        /* shrink allocated token and string buffer */
-        if (rules->token_cur < rules->token_max) {
-                struct token *tokens;
-
-                tokens = realloc(rules->tokens, rules->token_cur * sizeof(struct token));
-                if (tokens != NULL || rules->token_cur == 0) {
-                        rules->tokens = tokens;
-                        rules->token_max = rules->token_cur;
-                }
-        }
-        if (rules->buf_cur < rules->buf_max) {
-                char *buf;
-
-                buf = realloc(rules->buf, rules->buf_cur);
-                if (buf != NULL || rules->buf_cur == 0) {
-                        rules->buf = buf;
-                        rules->buf_max = rules->buf_cur;
-                }
-        }
-        info(udev, "rules use %zu bytes tokens (%u * %zu bytes), %zu bytes buffer\n",
-             rules->token_max * sizeof(struct token), rules->token_max, sizeof(struct token), rules->buf_max);
-        info(udev, "temporary index used %zu bytes (%u * %zu bytes)\n",
-             rules->trie_nodes_cur * sizeof(struct trie_node),
-             rules->trie_nodes_cur, sizeof(struct trie_node));
-
-        /* cleanup trie */
-        free(rules->trie_nodes);
-        rules->trie_nodes = NULL;
-        rules->trie_nodes_cur = 0;
-        rules->trie_nodes_max = 0;
-
-        /* 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);
-        free(rules->buf);
-        free(rules->trie_nodes);
-        free(rules->uids);
-        free(rules->gids);
-        free(rules);
-        return NULL;
-}
-
-static int match_key(struct udev_rules *rules, struct token *token, const char *val)
-{
-        char *key_value = &rules->buf[token->key.value_off];
-        char *pos;
-        bool match = false;
-
-        if (val == NULL)
-                val = "";
-
-        switch (token->key.glob) {
-        case GL_PLAIN:
-                match = (strcmp(key_value, val) == 0);
-                break;
-        case GL_GLOB:
-                match = (fnmatch(key_value, val, 0) == 0);
-                break;
-        case GL_SPLIT:
-                {
-                        const char *split;
-                        size_t len;
-
-                        split = &rules->buf[token->key.value_off];
-                        len = strlen(val);
-                        for (;;) {
-                                const char *next;
-
-                                next = strchr(split, '|');
-                                if (next != NULL) {
-                                        size_t matchlen = (size_t)(next - split);
-
-                                        match = (matchlen == len && strncmp(split, val, matchlen) == 0);
-                                        if (match)
-                                                break;
-                                } else {
-                                        match = (strcmp(split, val) == 0);
-                                        break;
-                                }
-                                split = &next[1];
-                        }
-                        break;
-                }
-        case GL_SPLIT_GLOB:
-                {
-                        char value[UTIL_PATH_SIZE];
-
-                        util_strscpy(value, sizeof(value), &rules->buf[token->key.value_off]);
-                        key_value = value;
-                        while (key_value != NULL) {
-                                pos = strchr(key_value, '|');
-                                if (pos != NULL) {
-                                        pos[0] = '\0';
-                                        pos = &pos[1];
-                                }
-                                dbg(rules->udev, "match %s '%s' <-> '%s'\n", token_str(token->type), key_value, val);
-                                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)) {
-                dbg(rules->udev, "%s is true (matching value)\n", token_str(token->type));
-                return 0;
-        }
-        if (!match && (token->key.op == OP_NOMATCH)) {
-                dbg(rules->udev, "%s is true (non-matching value)\n", token_str(token->type));
-                return 0;
-        }
-        dbg(rules->udev, "%s is not true\n", token_str(token->type));
-        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->buf[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->buf[cur->key.value_off];
-                klen = strlen(key_value);
-                if (klen > 0 && !isspace(key_value[klen-1])) {
-                        if (value != vbuf) {
-                                util_strscpy(vbuf, sizeof(vbuf), value);
-                                value = vbuf;
-                        }
-                        while (len > 0 && isspace(vbuf[--len]))
-                                vbuf[len] = '\0';
-                        dbg(rules->udev, "removed trailing whitespace from '%s'\n", value);
-                }
-        }
-
-        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 = ((strcmp(udev_device_get_action(event->dev), "remove") != 0) &&
-                        (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: {
-                        size_t devlen = strlen(udev_get_dev_path(event->udev))+1;
-                        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)[devlen];
-                                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->buf[cur->key.attr_off];
-                        const char *value;
-
-                        value = udev_device_get_property_value(event->dev, key_name);
-                        if (value == NULL) {
-                                dbg(event->udev, "ENV{%s} is not set, treat as empty\n", key_name);
-                                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 (strcmp(&rules->buf[cur->key.value_off], udev_list_entry_get_name(list_entry)) == 0) {
-                                        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->buf[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;
-
-                                dbg(event->udev, "parent: '%s'\n", udev_device_get_syspath(event->dev_parent));
-                                /* 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->buf[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;
-                                        }
-                                        dbg(event->udev, "parent key matched\n");
-                                }
-                                dbg(event->udev, "all parent keys matched\n");
-                                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->buf[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];
-
-                                        util_strscpy(tmp, sizeof(tmp), filename);
-                                        util_strscpyl(filename, sizeof(filename),
-                                                      udev_device_get_syspath(event->dev), "/", tmp, NULL);
-                                }
-                        }
-                        attr_subst_subdir(filename, sizeof(filename));
-
-                        match = (stat(filename, &statbuf) == 0);
-                        dbg(event->udev, "'%s' %s", filename, match ? "exists\n" : "does not exist\n");
-                        if (match && cur->key.mode > 0) {
-                                match = ((statbuf.st_mode & cur->key.mode) > 0);
-                                dbg(event->udev, "'%s' has mode=%#o and %s %#o\n", filename, statbuf.st_mode,
-                                    match ? "matches" : "does not match", cur->key.mode);
-                        }
-                        if (match && cur->key.op == OP_NOMATCH)
-                                goto nomatch;
-                        if (!match && cur->key.op == OP_MATCH)
-                                goto nomatch;
-                        break;
-                }
-                case TK_M_EVENT_TIMEOUT:
-                        info(event->udev, "OPTIONS event_timeout=%u\n", 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->buf[cur->key.value_off], program, sizeof(program));
-                        envp = udev_device_get_properties_envp(event->dev);
-                        info(event->udev, "PROGRAM '%s' %s:%u\n",
-                             program,
-                             &rules->buf[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)
-                                                info(event->udev, "%i character(s) replaced\n" , count);
-                                }
-                                event->program_result = strdup(result);
-                                dbg(event->udev, "storing result '%s'\n", event->program_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->buf[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->buf[cur->key.value_off], import, sizeof(import));
-                        info(event->udev, "IMPORT '%s' %s:%u\n",
-                             import,
-                             &rules->buf[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)) {
-                                        info(event->udev, "IMPORT builtin skip '%s' %s:%u\n",
-                                             udev_builtin_name(cur->key.builtin_cmd),
-                                             &rules->buf[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->buf[cur->key.value_off], command, sizeof(command));
-                        info(event->udev, "IMPORT builtin '%s' %s:%u\n",
-                             udev_builtin_name(cur->key.builtin_cmd),
-                             &rules->buf[rule->rule.filename_off],
-                             rule->rule.filename_line);
-
-                        if (udev_builtin_run(event->dev, cur->key.builtin_cmd, command, false) != 0) {
-                                /* remember failure */
-                                info(rules->udev, "IMPORT builtin '%s' returned non-zero\n",
-                                     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->buf[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", "r");
-                        if (f != NULL) {
-                                char cmdline[4096];
-
-                                if (fgets(cmdline, sizeof(cmdline), f) != NULL) {
-                                        const char *key = &rules->buf[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->buf[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->buf[cur->key.value_off], owner, sizeof(owner));
-                        event->uid = util_lookup_user(event->udev, owner);
-                        info(event->udev, "OWNER %u %s:%u\n",
-                             event->uid,
-                             &rules->buf[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->buf[cur->key.value_off], group, sizeof(group));
-                        event->gid = util_lookup_group(event->udev, group);
-                        info(event->udev, "GROUP %u %s:%u\n",
-                             event->gid,
-                             &rules->buf[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->buf[cur->key.value_off], mode_str, sizeof(mode_str));
-                        mode = strtol(mode_str, &endptr, 8);
-                        if (endptr[0] != '\0') {
-                                err(event->udev, "ignoring invalid mode '%s'\n", mode_str);
-                                break;
-                        }
-                        if (cur->key.op == OP_ASSIGN_FINAL)
-                                event->mode_final = true;
-                        event->mode_set = true;
-                        event->mode = mode;
-                        info(event->udev, "MODE %#o %s:%u\n",
-                             event->mode,
-                             &rules->buf[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->uid = cur->key.uid;
-                        info(event->udev, "OWNER %u %s:%u\n",
-                             event->uid,
-                             &rules->buf[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->gid = cur->key.gid;
-                        info(event->udev, "GROUP %u %s:%u\n",
-                             event->gid,
-                             &rules->buf[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;
-                        info(event->udev, "MODE %#o %s:%u\n",
-                             event->mode,
-                             &rules->buf[rule->rule.filename_off],
-                             rule->rule.filename_line);
-                        break;
-                case TK_A_ENV: {
-                        const char *name = &rules->buf[cur->key.attr_off];
-                        char *value = &rules->buf[cur->key.value_off];
-
-                        if (value[0] != '\0') {
-                                char temp_value[UTIL_NAME_SIZE];
-                                struct udev_list_entry *entry;
-
-                                udev_event_apply_format(event, value, temp_value, sizeof(temp_value));
-                                entry = udev_device_add_property(event->dev, name, temp_value);
-                                /* store in db, skip private keys */
-                                if (name[0] != '.')
-                                        udev_list_entry_set_num(entry, true);
-                        } else {
-                                udev_device_add_property(event->dev, name, NULL);
-                        }
-                        break;
-                }
-                case TK_A_TAG: {
-                        char tag[UTIL_PATH_SIZE];
-                        const char *p;
-
-                        udev_event_apply_format(event, &rules->buf[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;
-                                err(event->udev, "ignoring invalid tag name '%s'\n", tag);
-                                break;
-                        }
-                        udev_device_add_tag(event->dev, tag);
-                        break;
-                }
-                case TK_A_NAME: {
-                        const char *name  = &rules->buf[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)
-                                        info(event->udev, "%i character(s) replaced\n", count);
-                        }
-                        if (major(udev_device_get_devnum(event->dev))) {
-                                size_t devlen = strlen(udev_get_dev_path(event->udev))+1;
-
-                                if (strcmp(name_str, &udev_device_get_devnode(event->dev)[devlen]) != 0) {
-                                        err(event->udev, "NAME=\"%s\" ignored, kernel device nodes "
-                                            "can not be renamed; please fix it in %s:%u\n", name,
-                                            &rules->buf[rule->rule.filename_off], rule->rule.filename_line);
-                                        break;
-                                }
-                        }
-                        free(event->name);
-                        event->name = strdup(name_str);
-                        info(event->udev, "NAME '%s' %s:%u\n",
-                             event->name,
-                             &rules->buf[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->buf[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)
-                                info(event->udev, "%i character(s) replaced\n" , count);
-                        dbg(event->udev, "rule applied, added symlink(s) '%s'\n", temp);
-                        pos = temp;
-                        while (isspace(pos[0]))
-                                pos++;
-                        next = strchr(pos, ' ');
-                        while (next != NULL) {
-                                next[0] = '\0';
-                                info(event->udev, "LINK '%s' %s:%u\n", pos,
-                                     &rules->buf[rule->rule.filename_off], rule->rule.filename_line);
-                                util_strscpyl(filename, sizeof(filename), udev_get_dev_path(event->udev), "/", pos, NULL);
-                                udev_device_add_devlink(event->dev, filename, cur->key.devlink_unique);
-                                while (isspace(next[1]))
-                                        next++;
-                                pos = &next[1];
-                                next = strchr(pos, ' ');
-                        }
-                        if (pos[0] != '\0') {
-                                info(event->udev, "LINK '%s' %s:%u\n", pos,
-                                     &rules->buf[rule->rule.filename_off], rule->rule.filename_line);
-                                util_strscpyl(filename, sizeof(filename), udev_get_dev_path(event->udev), "/", pos, NULL);
-                                udev_device_add_devlink(event->dev, filename, cur->key.devlink_unique);
-                        }
-                        break;
-                }
-                case TK_A_ATTR: {
-                        const char *key_name = &rules->buf[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)
-                                util_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->buf[cur->key.value_off], value, sizeof(value));
-                        info(event->udev, "ATTR '%s' writing '%s' %s:%u\n", attr, value,
-                             &rules->buf[rule->rule.filename_off],
-                             rule->rule.filename_line);
-                        f = fopen(attr, "w");
-                        if (f != NULL) {
-                                if (fprintf(f, "%s", value) <= 0)
-                                        err(event->udev, "error writing ATTR{%s}: %m\n", attr);
-                                fclose(f);
-                        } else {
-                                err(event->udev, "error opening ATTR{%s} for writing: %m\n", attr);
-                        }
-                        break;
-                }
-                case TK_A_RUN: {
-                        if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL)
-                                udev_list_cleanup(&event->run_list);
-                        info(event->udev, "RUN '%s' %s:%u\n",
-                             &rules->buf[cur->key.value_off],
-                             &rules->buf[rule->rule.filename_off],
-                             rule->rule.filename_line);
-                        udev_list_entry_add(&event->run_list, &rules->buf[cur->key.value_off], NULL);
-                        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:
-                        err(rules->udev, "wrong type %u\n", cur->type);
-                        goto nomatch;
-                }
-
-                cur++;
-                continue;
-        nomatch:
-                /* fast-forward to next rule */
-                cur = rule + rule->rule.token_count;
-                dbg(rules->udev, "forward to rule: %u\n",
-                                 (unsigned int) (cur - rules->tokens));
-        }
-}
-
-void 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;
-
-        if (rules->tokens == NULL)
-                return;
-
-        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;
-                        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_STATIC_NODE: {
-                        char filename[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)
-                                goto next;
-                        util_strscpyl(filename, sizeof(filename), udev_get_dev_path(rules->udev), "/",
-                                      &rules->buf[cur->key.value_off], NULL);
-                        if (stat(filename, &stats) != 0)
-                                goto next;
-                        if (!S_ISBLK(stats.st_mode) && !S_ISCHR(stats.st_mode))
-                                goto next;
-                        if (mode == 0) {
-                                if (gid > 0)
-                                        mode = 0660;
-                                else
-                                        mode = 0600;
-                        }
-                        if (mode != (stats.st_mode & 01777)) {
-                                chmod(filename, mode);
-                                info(rules->udev, "chmod '%s' %#o\n", filename, mode);
-                        }
-
-                        if ((uid != 0 && uid != stats.st_uid) || (gid != 0 && gid != stats.st_gid)) {
-                                chown(filename, uid, gid);
-                                info(rules->udev, "chown '%s' %u %u\n", filename, uid, gid);
-                        }
-
-                        utimensat(AT_FDCWD, filename, NULL, 0);
-                        break;
-                }
-                case TK_END:
-                        return;
-                }
-
-                cur++;
-                continue;
-next:
-                /* fast-forward to next rule */
-                cur = rule + rule->rule.token_count;
-                continue;
-        }
-}
diff --git a/src/udev/src/udev-settle.service.in b/src/udev/src/udev-settle.service.in
deleted file mode 100644 (file)
index b0a4964..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-# This service is usually not enabled by default. If enabled, it
-# acts as a barrier for basic.target -- so all later services will
-# wait for udev completely finishing its coldplug run.
-#
-# If needed, to work around broken or non-hotplug-aware services,
-# it might be enabled unconditionally, or pulled-in on-demand by
-# the services that assume a fully populated /dev at startup. It
-# should not be used or pulled-in ever on systems without such
-# legacy services running.
-
-[Unit]
-Description=udev Wait for Complete Device Initialization
-DefaultDependencies=no
-Wants=udev.service
-After=udev-trigger.service
-Before=basic.target
-
-[Service]
-Type=oneshot
-TimeoutSec=180
-RemainAfterExit=yes
-ExecStart=@bindir@/udevadm settle
-
-[Install]
-WantedBy=basic.target
diff --git a/src/udev/src/udev-trigger.service.in b/src/udev/src/udev-trigger.service.in
deleted file mode 100644 (file)
index cd81945..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-[Unit]
-Description=udev Coldplug all Devices
-Wants=udev.service
-After=udev-kernel.socket udev-control.socket
-DefaultDependencies=no
-
-[Service]
-Type=oneshot
-RemainAfterExit=yes
-ExecStart=@bindir@/udevadm trigger --type=subsystems --action=add ; @bindir@/udevadm trigger --type=devices --action=add
diff --git a/src/udev/src/udev-watch.c b/src/udev/src/udev-watch.c
deleted file mode 100644 (file)
index 228d18f..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2004-2010 Kay Sievers <kay.sievers@vrfy.org>
- * Copyright (C) 2009 Canonical Ltd.
- * Copyright (C) 2009 Scott James Remnant <scott@netsplit.com>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <sys/types.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <dirent.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/inotify.h>
-
-#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)
-                err(udev, "inotify_init failed: %m\n");
-        return inotify_fd;
-}
-
-/* move any old watches directory out of the way, and then restore
- * the watches
- */
-void udev_watch_restore(struct udev *udev)
-{
-        char filename[UTIL_PATH_SIZE], oldname[UTIL_PATH_SIZE];
-
-        if (inotify_fd < 0)
-                return;
-
-        util_strscpyl(oldname, sizeof(oldname), udev_get_run_path(udev), "/watch.old", NULL);
-        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/watch", NULL);
-        if (rename(filename, oldname) == 0) {
-                DIR *dir;
-                struct dirent *ent;
-
-                dir = opendir(oldname);
-                if (dir == NULL) {
-                        err(udev, "unable to open old watches dir '%s', old watches will not be restored: %m", oldname);
-                        return;
-                }
-
-                for (ent = readdir(dir); ent != NULL; ent = readdir(dir)) {
-                        char device[UTIL_PATH_SIZE];
-                        char *s;
-                        size_t l;
-                        ssize_t len;
-                        struct udev_device *dev;
-
-                        if (ent->d_name[0] == '.')
-                                continue;
-
-                        s = device;
-                        l = util_strpcpy(&s, sizeof(device), udev_get_sys_path(udev));
-                        len = readlinkat(dirfd(dir), ent->d_name, s, l);
-                        if (len <= 0 || len == (ssize_t)l)
-                                goto unlink;
-                        s[len] = '\0';
-
-                        dev = udev_device_new_from_id_filename(udev, s);
-                        if (dev == NULL)
-                                goto unlink;
-
-                        info(udev, "restoring old watch on '%s'\n", 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(oldname);
-
-        } else if (errno != ENOENT) {
-                err(udev, "unable to move watches dir '%s', old watches will not be restored: %m", filename);
-        }
-}
-
-void udev_watch_begin(struct udev *udev, struct udev_device *dev)
-{
-        char filename[UTIL_PATH_SIZE];
-        int wd;
-
-        if (inotify_fd < 0)
-                return;
-
-        info(udev, "adding watch on '%s'\n", udev_device_get_devnode(dev));
-        wd = inotify_add_watch(inotify_fd, udev_device_get_devnode(dev), IN_CLOSE_WRITE);
-        if (wd < 0) {
-                err(udev, "inotify_add_watch(%d, %s, %o) failed: %m\n",
-                    inotify_fd, udev_device_get_devnode(dev), IN_CLOSE_WRITE);
-                return;
-        }
-
-        snprintf(filename, sizeof(filename), "%s/watch/%d", udev_get_run_path(udev), wd);
-        util_create_path(udev, filename);
-        unlink(filename);
-        symlink(udev_device_get_id_filename(dev), 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;
-
-        info(udev, "removing watch on '%s'\n", udev_device_get_devnode(dev));
-        inotify_rm_watch(inotify_fd, wd);
-
-        snprintf(filename, sizeof(filename), "%s/watch/%d", udev_get_run_path(udev), 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 majmin[UTIL_PATH_SIZE];
-        char *s;
-        size_t l;
-        ssize_t len;
-
-        if (inotify_fd < 0 || wd < 0)
-                return NULL;
-
-        snprintf(filename, sizeof(filename), "%s/watch/%d", udev_get_run_path(udev), wd);
-        s = majmin;
-        l = util_strpcpy(&s, sizeof(majmin), udev_get_sys_path(udev));
-        len = readlink(filename, s, l);
-        if (len <= 0 || (size_t)len == l)
-                return NULL;
-        s[len] = '\0';
-
-        return udev_device_new_from_id_filename(udev, s);
-}
diff --git a/src/udev/src/udev.conf b/src/udev/src/udev.conf
deleted file mode 100644 (file)
index f39253e..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-# see udev(7) for details
-
-#udev_log="info"
diff --git a/src/udev/src/udev.h b/src/udev/src/udev.h
deleted file mode 100644 (file)
index bc051c9..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
- * Copyright (C) 2003-2010 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#ifndef _UDEV_H_
-#define _UDEV_H_
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <signal.h>
-
-#include "libudev.h"
-#include "libudev-private.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 run_list;
-        int exec_delay;
-        unsigned long long birth_usec;
-        unsigned long long timeout_usec;
-        int fd_signal;
-        unsigned int builtin_run;
-        unsigned int builtin_ret;
-        bool sigterm;
-        bool inotify_watch;
-        bool inotify_watch_final;
-        bool group_final;
-        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);
-int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event, const sigset_t *sigmask);
-void 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);
-int 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, mode_t mode, uid_t uid, gid_t gid);
-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_ref(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_ref(struct udev_ctrl_msg *ctrl_msg);
-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 {
-        UDEV_BUILTIN_BLKID,
-        UDEV_BUILTIN_FIRMWARE,
-        UDEV_BUILTIN_INPUT_ID,
-        UDEV_BUILTIN_KMOD,
-        UDEV_BUILTIN_PATH_ID,
-        UDEV_BUILTIN_PCI_DB,
-        UDEV_BUILTIN_USB_DB,
-        UDEV_BUILTIN_USB_ID,
-        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;
-};
-extern const struct udev_builtin udev_builtin_blkid;
-extern const struct udev_builtin udev_builtin_firmware;
-extern const struct udev_builtin udev_builtin_input_id;
-extern const struct udev_builtin udev_builtin_kmod;
-extern const struct udev_builtin udev_builtin_path_id;
-extern const struct udev_builtin udev_builtin_pci_db;
-extern const struct udev_builtin udev_builtin_usb_db;
-extern const struct udev_builtin udev_builtin_usb_id;
-int 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);
-int udev_builtin_add_property(struct udev_device *dev, bool test, const char *key, const char *val);
-
-/* 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);
-
-/* 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_test;
-extern const struct udevadm_cmd udevadm_test_builtin;
-#endif
diff --git a/src/udev/src/udev.pc.in b/src/udev/src/udev.pc.in
deleted file mode 100644 (file)
index 0b04c02..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-Name: udev
-Description: udev
-Version: @VERSION@
-
-udevdir=@pkglibexecdir@
diff --git a/src/udev/src/udev.service.in b/src/udev/src/udev.service.in
deleted file mode 100644 (file)
index c27eb1b..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-[Unit]
-Description=udev Kernel Device Manager
-Wants=udev-control.socket udev-kernel.socket
-After=udev-control.socket udev-kernel.socket
-Before=basic.target
-DefaultDependencies=no
-ConditionCapability=CAP_MKNOD
-
-[Service]
-Type=notify
-OOMScoreAdjust=-1000
-Sockets=udev-control.socket udev-kernel.socket
-Restart=on-failure
-ExecStart=@pkglibexecdir@/udevd
diff --git a/src/udev/src/udev.xml b/src/udev/src/udev.xml
deleted file mode 100644 (file)
index 8eb583a..0000000
+++ /dev/null
@@ -1,695 +0,0 @@
-<?xml version='1.0'?>
-<?xml-stylesheet type="text/xsl" href="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl"?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<refentry id="udev">
-  <refentryinfo>
-    <title>udev</title>
-    <productname>udev</productname>
-  </refentryinfo>
-
-  <refmeta>
-    <refentrytitle>udev</refentrytitle>
-    <manvolnum>7</manvolnum>
-  </refmeta>
-
-  <refnamediv>
-    <refname>udev</refname>
-    <refpurpose>Linux dynamic device management</refpurpose>
-  </refnamediv>
-
-  <refsect1><title>Description</title>
-    <para>udev supplies the system software with device events, manages permissions
-    of device nodes and may create additional symlinks in the <filename>/dev</filename>
-    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.</para>
-
-    <para>The udev daemon, <citerefentry><refentrytitle>udevd</refentrytitle>
-    <manvolnum>8</manvolnum></citerefentry>, 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.</para>
-
-    <para>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.</para>
-  </refsect1>
-
-  <refsect1><title>Configuration</title>
-    <para>udev configuration files are placed in <filename>/etc/udev</filename>
-    and <filename>/usr/lib/udev</filename>. All empty lines or lines beginning with
-    '#' are ignored.</para>
-
-    <refsect2><title>Configuration file</title>
-      <para>udev expects its main configuration file at <filename>/etc/udev/udev.conf</filename>.
-      It consists of a set of variables allowing the user to override default udev values.
-      The following variables can be set:</para>
-      <variablelist>
-        <varlistentry>
-          <term><option>udev_root</option></term>
-          <listitem>
-            <para>Specifies where to place the device nodes in the filesystem.
-            The default value is <filename>/dev</filename>.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>udev_log</option></term>
-          <listitem>
-            <para>The logging priority. Valid values are the numerical syslog priorities
-            or their textual representations: <option>err</option>, <option>info</option>
-            and <option>debug</option>.</para>
-          </listitem>
-        </varlistentry>
-      </variablelist>
-    </refsect2>
-
-    <refsect2><title>Rules files</title>
-      <para>The udev rules are read from the files located in the
-      system rules directory <filename>/usr/lib/udev/rules.d</filename>,
-      the volatile runtime directory <filename>/run/udev/rules.d</filename>
-      and the local administration directory <filename>/etc/udev/rules.d</filename>.
-      All rules files are collectively sorted and processed in lexical order,
-      regardless of the directories in which they live. However, files with
-      identical file names replace each other. Files in <filename>/etc</filename>
-      have the highest priority, files in <filename>/run</filename> take precedence
-      over files with the same name in <filename>/lib</filename>. This can be
-      used to override a system-supplied rules file with a local file if needed;
-      a symlink in <filename>/etc</filename> with the same name as a rules file in
-      <filename>/lib</filename>, pointing to <filename>/dev/null</filename>,
-      disables the rules file entirely.</para>
-
-      <para>Rule files must have the extension <filename>.rules</filename>; other
-      extensions are ignored.</para>
-
-      <para>Every line in the rules file contains at least one key-value pair.
-      There are two kind of keys: match and assignment.
-      If all match keys are matching against its value, the rule gets applied and the
-      assignment keys get the specified value assigned.</para>
-
-      <para>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.</para>
-
-      <para>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:</para>
-      <variablelist>
-        <varlistentry>
-          <term><option>==</option></term>
-          <listitem>
-            <para>Compare for equality.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>!=</option></term>
-          <listitem>
-            <para>Compare for inequality.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>=</option></term>
-          <listitem>
-            <para>Assign a value to a key. Keys that represent a list are reset
-            and only this single value is assigned.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>+=</option></term>
-          <listitem>
-            <para>Add the value to a key that holds a list of entries.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>:=</option></term>
-          <listitem>
-            <para>Assign  a  value  to  a key finally; disallow any later changes.</para>
-          </listitem>
-        </varlistentry>
-      </variablelist>
-
-      <para>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.</para>
-      <variablelist>
-        <varlistentry>
-          <term><option>ACTION</option></term>
-          <listitem>
-            <para>Match the name of the event action.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>DEVPATH</option></term>
-          <listitem>
-            <para>Match the devpath of the event device.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>KERNEL</option></term>
-          <listitem>
-            <para>Match the name of the event device.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>NAME</option></term>
-          <listitem>
-            <para>Match the name of a network interface. It can be used once the
-            NAME key has been set in one of the preceding rules.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>SYMLINK</option></term>
-          <listitem>
-            <para>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.
-            </para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>SUBSYSTEM</option></term>
-          <listitem>
-            <para>Match the subsystem of the event device.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>DRIVER</option></term>
-          <listitem>
-            <para>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.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>ATTR{<replaceable>filename</replaceable>}</option></term>
-          <listitem>
-            <para>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.
-            </para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>KERNELS</option></term>
-          <listitem>
-            <para>Search the devpath upwards for a matching device name.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>SUBSYSTEMS</option></term>
-          <listitem>
-            <para>Search the devpath upwards for a matching device subsystem name.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>DRIVERS</option></term>
-          <listitem>
-            <para>Search the devpath upwards for a matching device driver name.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>ATTRS{<replaceable>filename</replaceable>}</option></term>
-          <listitem>
-            <para>Search the devpath upwards for a device with matching sysfs attribute values.
-            If multiple <option>ATTRS</option> 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.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>TAGS</option></term>
-          <listitem>
-            <para>Search the devpath upwards for a device with matching tag.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>ENV{<replaceable>key</replaceable>}</option></term>
-          <listitem>
-            <para>Match against a device property value.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>TAG</option></term>
-          <listitem>
-            <para>Match against a device tag.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>TEST{<replaceable>octal mode mask</replaceable>}</option></term>
-          <listitem>
-            <para>Test the existence of a file. An octal mode mask can be specified
-            if needed.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>PROGRAM</option></term>
-          <listitem>
-            <para>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 stdout
-            is available in the RESULT key.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>RESULT</option></term>
-          <listitem>
-            <para>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.</para>
-          </listitem>
-        </varlistentry>
-      </variablelist>
-
-      <para>Most of the fields support shell-style pattern matching. The following
-      pattern characters are supported:</para>
-      <variablelist>
-        <varlistentry>
-          <term><option>*</option></term>
-          <listitem>
-            <para>Matches zero or more characters.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>?</option></term>
-          <listitem>
-            <para>Matches any single character.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>[]</option></term>
-          <listitem>
-            <para>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.</para>
-          </listitem>
-        </varlistentry>
-      </variablelist>
-
-      <para>The following keys can get values assigned:</para>
-      <variablelist>
-        <varlistentry>
-          <term><option>NAME</option></term>
-          <listitem>
-            <para>The name to use for a network interface. The name of a device node
-            can not be changed by udev, only additional symlinks can be created.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>SYMLINK</option></term>
-          <listitem>
-            <para>The name of a symlink targeting the node. Every matching rule adds
-            this value to the list of symlinks to be created. 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. Also, symlink names must
-            never conflict with the kernel's default device node names, as that would
-            result in unpredictable behavior.
-            </para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>OWNER, GROUP, MODE</option></term>
-          <listitem>
-            <para>The permissions for the device node. Every specified value overrides
-            the compiled-in default value.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>ATTR{<replaceable>key</replaceable>}</option></term>
-          <listitem>
-            <para>The value that should be written to a sysfs attribute of the
-            event device.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>ENV{<replaceable>key</replaceable>}</option></term>
-          <listitem>
-            <para>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, say, the PROGRAM match key).</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>TAG</option></term>
-          <listitem>
-            <para>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.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>RUN</option></term>
-          <listitem>
-            <para>Add a program to the list of programs to be executed for a specific
-            device.</para>
-            <para>If no absolute path is given, the program is expected to live in
-            /usr/lib/udev, otherwise the absolute path must be specified. The program
-            name and following arguments are separated by spaces. Single quotes can
-            be used to specify arguments with spaces.</para>
-            <para>This can only be used for very short running 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.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>LABEL</option></term>
-          <listitem>
-            <para>A named label to which a GOTO may jump.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>GOTO</option></term>
-          <listitem>
-            <para>Jumps to the next LABEL with a matching name.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>IMPORT{<replaceable>type</replaceable>}</option></term>
-          <listitem>
-            <para>Import a set of variables as device properties,
-            depending on <replaceable>type</replaceable>:</para>
-            <variablelist>
-              <varlistentry>
-                <term><option>program</option></term>
-                <listitem>
-                  <para>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 <option>RUN</option>.</para>
-                </listitem>
-              </varlistentry>
-              <varlistentry>
-                <term><option>file</option></term>
-                <listitem>
-                  <para>Import a text file specified as the assigned value, the content
-                  of which must be in environment key format.</para>
-                </listitem>
-              </varlistentry>
-              <varlistentry>
-                <term><option>db</option></term>
-                <listitem>
-                  <para>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.</para>
-                </listitem>
-              </varlistentry>
-              <varlistentry>
-                <term><option>cmdline</option></term>
-                <listitem>
-                  <para>Import a single property from the kernel command line. For simple flags
-                  the value of the property is set to '1'.</para>
-                </listitem>
-              </varlistentry>
-              <varlistentry>
-                <term><option>parent</option></term>
-                <listitem>
-                  <para>Import the stored keys from the parent device by reading
-                  the database entry of the parent device. The value assigned to
-                  <option>IMPORT{parent}</option> is used as a filter of key names
-                  to import (with the same shell-style pattern matching used for
-                  comparisons).</para>
-                </listitem>
-              </varlistentry>
-            </variablelist>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>WAIT_FOR</option></term>
-          <listitem>
-            <para>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.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>OPTIONS</option></term>
-          <listitem>
-            <para>Rule and device options:</para>
-            <variablelist>
-              <varlistentry>
-                <term><option>link_priority=<replaceable>value</replaceable></option></term>
-                <listitem>
-                  <para>Specify the priority of the created symlinks. Devices with higher
-                  priorities overwrite existing symlinks of other devices. The default is 0.</para>
-                </listitem>
-              </varlistentry>
-              <varlistentry>
-                <term><option>event_timeout=</option></term>
-                <listitem>
-                  <para>Number of seconds an event waits for operations to finish before
-                  giving up and terminating itself.</para>
-                </listitem>
-              </varlistentry>
-              <varlistentry>
-                <term><option>string_escape=<replaceable>none|replace</replaceable></option></term>
-                <listitem>
-                  <para>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.</para>
-                </listitem>
-              </varlistentry>
-              <varlistentry>
-                <term><option>static_node=</option></term>
-                <listitem>
-                  <para>Apply the permissions specified in this rule to the static device node with
-                  the specified name. Static device nodes might be provided by kernel modules
-                  or copied from <filename>/usr/lib/udev/devices</filename>. These nodes might not have
-                  a corresponding kernel device at the time udevd is started; they can trigger
-                  automatic kernel module loading.</para>
-                </listitem>
-              </varlistentry>
-              <varlistentry>
-                <term><option>watch</option></term>
-                <listitem>
-                  <para>Watch the device node with inotify; when the node is closed after being opened for
-                  writing, a change uevent is synthesized.</para>
-                </listitem>
-              </varlistentry>
-              <varlistentry>
-                <term><option>nowatch</option></term>
-                <listitem>
-                  <para>Disable the watching of a device node with inotify.</para>
-                </listitem>
-              </varlistentry>
-            </variablelist>
-          </listitem>
-        </varlistentry>
-      </variablelist>
-
-      <para>The <option>NAME</option>, <option>SYMLINK</option>, <option>PROGRAM</option>,
-      <option>OWNER</option>, <option>GROUP</option>, <option>MODE</option>  and  <option>RUN</option>
-      fields support simple string substitutions. The <option>RUN</option>
-      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:</para>
-      <variablelist>
-        <varlistentry>
-          <term><option>$kernel</option>, <option>%k</option></term>
-          <listitem>
-            <para>The kernel name for this device.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>$number</option>, <option>%n</option></term>
-          <listitem>
-            <para>The kernel number for this device. For example, 'sda3' has
-            kernel number of '3'</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>$devpath</option>, <option>%p</option></term>
-          <listitem>
-            <para>The devpath of the device.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>$id</option>, <option>%b</option></term>
-          <listitem>
-            <para>The name of the device matched while searching the devpath upwards for
-              <option>SUBSYSTEMS</option>, <option>KERNELS</option>, <option>DRIVERS</option> and <option>ATTRS</option>.
-            </para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>$driver</option></term>
-          <listitem>
-            <para>The driver name of the device matched while searching the devpath upwards for
-              <option>SUBSYSTEMS</option>, <option>KERNELS</option>, <option>DRIVERS</option> and <option>ATTRS</option>.
-            </para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>$attr{<replaceable>file</replaceable>}</option>, <option>%s{<replaceable>file</replaceable>}</option></term>
-          <listitem>
-            <para>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 KERNELS, SUBSYSTEMS, DRIVERS, or
-            ATTRS test selected a parent device, then the attribute from that
-            parent device is used.</para>
-            <para>If the attribute is a symlink, the last element of the symlink target is
-            returned as the value.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>$env{<replaceable>key</replaceable>}</option>, <option>%E{<replaceable>key</replaceable>}</option></term>
-          <listitem>
-            <para>A device property value.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>$major</option>, <option>%M</option></term>
-          <listitem>
-            <para>The kernel major number for the device.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>$minor</option>, <option>%m</option></term>
-          <listitem>
-            <para>The kernel minor number for the device.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>$result</option>, <option>%c</option></term>
-          <listitem>
-            <para>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: <option>%c{N}</option>.
-            If the number is followed by the '+' character, this part plus all remaining parts
-            of the result string are substituted: <option>%c{N+}</option></para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>$parent</option>, <option>%P</option></term>
-          <listitem>
-            <para>The node name of the parent device.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>$name</option></term>
-          <listitem>
-            <para>The current name of the device. If not changed by a rule, it is the
-            name of the kernel device.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>$links</option></term>
-          <listitem>
-            <para>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.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>$root</option>, <option>%r</option></term>
-          <listitem>
-            <para>The udev_root value.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>$sys</option>, <option>%S</option></term>
-          <listitem>
-            <para>The sysfs mount point.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>$devnode</option>, <option>%N</option></term>
-          <listitem>
-            <para>The name of the device node.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>%%</option></term>
-          <listitem>
-          <para>The '%' character itself.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term><option>$$</option></term>
-          <listitem>
-          <para>The '$' character itself.</para>
-          </listitem>
-        </varlistentry>
-      </variablelist>
-    </refsect2>
-  </refsect1>
-
-  <refsect1><title>Author</title>
-    <para>Written by Greg Kroah-Hartman <email>greg@kroah.com</email> and
-    Kay Sievers <email>kay.sievers@vrfy.org</email>. With much help from
-    Dan Stekloff and many others.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>See Also</title>
-    <para><citerefentry>
-        <refentrytitle>udevd</refentrytitle><manvolnum>8</manvolnum>
-      </citerefentry>,
-      <citerefentry>
-        <refentrytitle>udevadm</refentrytitle><manvolnum>8</manvolnum>
-    </citerefentry></para>
-  </refsect1>
-</refentry>
diff --git a/src/udev/src/udevadm-control.c b/src/udev/src/udevadm-control.c
deleted file mode 100644 (file)
index cafa214..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2005-2011 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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 <time.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/wait.h>
-#include <sys/un.h>
-
-#include "udev.h"
-
-static void print_help(void)
-{
-        printf("Usage: udevadm control COMMAND\n"
-                "  --exit                   instruct the daemon to cleanup and exit\n"
-                "  --log-priority=<level>   set the udev log level for the daemon\n"
-                "  --stop-exec-queue        do not execute events, queue only\n"
-                "  --start-exec-queue       execute events, flush queue\n"
-                "  --reload                 reload rules and databases\n"
-                "  --property=<KEY>=<value> set a global property for all events\n"
-                "  --children-max=<N>       maximum number of children\n"
-                "  --timeout=<seconds>      maximum time to block for a reply\n"
-                "  --help                   print this help text\n\n");
-}
-
-static int adm_control(struct udev *udev, int argc, char *argv[])
-{
-        struct udev_ctrl *uctrl = NULL;
-        int timeout = 60;
-        int rc = 1;
-
-        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' },
-                { "property", required_argument, NULL, 'p' },
-                { "env", required_argument, NULL, '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;
-
-        for (;;) {
-                int option;
-
-                option = getopt_long(argc, argv, "el:sSRp:m:h", options, NULL);
-                if (option == -1)
-                        break;
-
-                switch (option) {
-                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);
-                                goto out;
-                        }
-                        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 <KEY>=<value> instead of '%s'\n", optarg);
-                                goto out;
-                        }
-                        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);
-                                goto out;
-                        }
-                        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 (argv[optind] != NULL)
-                fprintf(stderr, "unknown option\n");
-        else if (optind == 1)
-                fprintf(stderr, "missing option\n");
-out:
-        udev_ctrl_unref(uctrl);
-        return rc;
-}
-
-const struct udevadm_cmd udevadm_control = {
-        .name = "control",
-        .cmd = adm_control,
-        .help = "control the udev daemon",
-};
diff --git a/src/udev/src/udevadm-info.c b/src/udev/src/udevadm-info.c
deleted file mode 100644 (file)
index ee9b59f..0000000
+++ /dev/null
@@ -1,568 +0,0 @@
-/*
- * Copyright (C) 2004-2009 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <ctype.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <errno.h>
-#include <getopt.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include "udev.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 < ARRAY_SIZE(skip); i++)
-                if (strcmp(name, skip[i]) == 0)
-                        return true;
-        return false;
-}
-
-static void print_all_attributes(struct udev_device *device, const char *key)
-{
-        struct udev *udev = udev_device_get_udev(device);
-        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;
-                dbg(udev, "attr '%s'='%s'\n", name, value);
-
-                /* 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) {
-                        dbg(udev, "attribute value of '%s' non-printable, skip\n", name);
-                        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)
-{
-        size_t len;
-        const char *str;
-        int i;
-        struct udev_list_entry *list_entry;
-
-        printf("P: %s\n", udev_device_get_devpath(device));
-
-        len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
-        str = udev_device_get_devnode(device);
-        if (str != NULL)
-                printf("N: %s\n", &str[len+1]);
-
-        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)) {
-                len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
-                printf("S: %s\n", &udev_list_entry_get_name(list_entry)[len+1]);
-        }
-
-        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)
-{
-        char filename[UTIL_PATH_SIZE];
-        DIR *dir;
-
-        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/queue.bin", NULL);
-        unlink(filename);
-
-        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/data", NULL);
-        dir = opendir(filename);
-        if (dir != NULL) {
-                cleanup_dir(dir, S_ISVTX, 1);
-                closedir(dir);
-        }
-
-        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/links", NULL);
-        dir = opendir(filename);
-        if (dir != NULL) {
-                cleanup_dir(dir, 0, 2);
-                closedir(dir);
-        }
-
-        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/tags", NULL);
-        dir = opendir(filename);
-        if (dir != NULL) {
-                cleanup_dir(dir, 0, 2);
-                closedir(dir);
-        }
-
-        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/watch", NULL);
-        dir = opendir(filename);
-        if (dir != NULL) {
-                cleanup_dir(dir, 0, 1);
-                closedir(dir);
-        }
-
-        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/firmware-missing", NULL);
-        dir = opendir(filename);
-        if (dir != NULL) {
-                cleanup_dir(dir, 0, 1);
-                closedir(dir);
-        }
-}
-
-static int uinfo(struct udev *udev, int argc, char *argv[])
-{
-        struct udev_device *device = NULL;
-        bool root = 0;
-        bool export = 0;
-        const char *export_prefix = NULL;
-        char path[UTIL_PATH_SIZE];
-        char name[UTIL_PATH_SIZE];
-        struct udev_list_entry *list_entry;
-        int rc = 0;
-
-        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' },
-                { "run", 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' },
-                {}
-        };
-
-        enum action_type {
-                ACTION_NONE,
-                ACTION_QUERY,
-                ACTION_ATTRIBUTE_WALK,
-                ACTION_ROOT,
-                ACTION_DEVICE_ID_FILE,
-        } action = ACTION_NONE;
-
-        enum query_type {
-                QUERY_NONE,
-                QUERY_NAME,
-                QUERY_PATH,
-                QUERY_SYMLINK,
-                QUERY_PROPERTY,
-                QUERY_ALL,
-        } query = QUERY_NONE;
-
-        for (;;) {
-                int option;
-                struct stat statbuf;
-
-                option = getopt_long(argc, argv, "aced:n:p:q:rxP:RVh", options, NULL);
-                if (option == -1)
-                        break;
-
-                dbg(udev, "option '%c'\n", option);
-                switch (option) {
-                case 'n':
-                        if (device != NULL) {
-                                fprintf(stderr, "device already specified\n");
-                                rc = 2;
-                                goto exit;
-                        }
-                        /* remove /dev if given */
-                        if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0)
-                                util_strscpyl(name, sizeof(name), udev_get_dev_path(udev), "/", optarg, NULL);
-                        else
-                                util_strscpy(name, sizeof(name), optarg);
-                        util_remove_trailing_chars(name, '/');
-                        if (stat(name, &statbuf) < 0) {
-                                fprintf(stderr, "device node not found\n");
-                                rc = 2;
-                                goto exit;
-                        } else {
-                                char type;
-
-                                if (S_ISBLK(statbuf.st_mode)) {
-                                        type = 'b';
-                                } else if (S_ISCHR(statbuf.st_mode)) {
-                                        type = 'c';
-                                } else {
-                                        fprintf(stderr, "device node has wrong file type\n");
-                                        rc = 2;
-                                        goto exit;
-                                }
-                                device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
-                                if (device == NULL) {
-                                        fprintf(stderr, "device node not found\n");
-                                        rc = 2;
-                                        goto exit;
-                                }
-                        }
-                        break;
-                case 'p':
-                        if (device != NULL) {
-                                fprintf(stderr, "device already specified\n");
-                                rc = 2;
-                                goto exit;
-                        }
-                        /* add sys dir if needed */
-                        if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
-                                util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), optarg, NULL);
-                        else
-                                util_strscpy(path, sizeof(path), optarg);
-                        util_remove_trailing_chars(path, '/');
-                        device = udev_device_new_from_syspath(udev, path);
-                        if (device == NULL) {
-                                fprintf(stderr, "device path not found\n");
-                                rc = 2;
-                                goto exit;
-                        }
-                        break;
-                case 'q':
-                        action = ACTION_QUERY;
-                        if (strcmp(optarg, "property") == 0 || strcmp(optarg, "env") == 0) {
-                                query = QUERY_PROPERTY;
-                        } else if (strcmp(optarg, "name") == 0) {
-                                query = QUERY_NAME;
-                        } else if (strcmp(optarg, "symlink") == 0) {
-                                query = QUERY_SYMLINK;
-                        } else if (strcmp(optarg, "path") == 0) {
-                                query = QUERY_PATH;
-                        } else if (strcmp(optarg, "all") == 0) {
-                                query = QUERY_ALL;
-                        } else {
-                                fprintf(stderr, "unknown query type\n");
-                                rc = 3;
-                                goto exit;
-                        }
-                        break;
-                case 'r':
-                        if (action == ACTION_NONE)
-                                action = ACTION_ROOT;
-                        root = true;
-                        break;
-                case 'R':
-                        printf("%s\n", udev_get_run_path(udev));
-                        goto exit;
-                case 'd':
-                        action = ACTION_DEVICE_ID_FILE;
-                        util_strscpy(name, sizeof(name), optarg);
-                        break;
-                case 'a':
-                        action = ACTION_ATTRIBUTE_WALK;
-                        break;
-                case 'e':
-                        export_devices(udev);
-                        goto exit;
-                case 'c':
-                        cleanup_db(udev);
-                        goto exit;
-                case 'x':
-                        export = true;
-                        break;
-                case 'P':
-                        export_prefix = optarg;
-                        break;
-                case 'V':
-                        printf("%s\n", VERSION);
-                        goto exit;
-                case 'h':
-                        printf("Usage: udevadm info OPTIONS\n"
-                               "  --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"
-                               "  --path=<syspath>           sys device path used for query or attribute walk\n"
-                               "  --name=<name>              node or symlink name used for query or attribute walk\n"
-                               "  --root                     prepend dev directory to path names\n"
-                               "  --attribute-walk           print all key matches while walking along the chain\n"
-                               "                             of parent devices\n"
-                               "  --device-id-of-file=<file> print major:minor of device containing this file\n"
-                               "  --export                   export key/value pairs\n"
-                               "  --export-prefix            export the key name with a prefix\n"
-                               "  --export-db                export the content of the udev database\n"
-                               "  --cleanup-db               cleanup the udev database\n"
-                               "  --help\n\n");
-                        goto exit;
-                default:
-                        rc = 1;
-                        goto exit;
-                }
-        }
-
-        switch (action) {
-        case ACTION_QUERY:
-                if (device == NULL) {
-                        fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
-                        rc = 4;
-                        goto exit;
-                }
-
-                switch(query) {
-                case QUERY_NAME: {
-                        const char *node = udev_device_get_devnode(device);
-
-                        if (node == NULL) {
-                                fprintf(stderr, "no device node found\n");
-                                rc = 5;
-                                goto exit;
-                        }
-
-                        if (root) {
-                                printf("%s\n", udev_device_get_devnode(device));
-                        } else {
-                                size_t len = strlen(udev_get_dev_path(udev));
-
-                                printf("%s\n", &udev_device_get_devnode(device)[len+1]);
-                        }
-                        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 {
-                                        size_t len;
-
-                                        len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
-                                        printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
-                                }
-                                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));
-                        goto exit;
-                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 == NULL) {
-                        fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
-                        rc = 4;
-                        goto exit;
-                }
-                print_device_chain(device);
-                break;
-        case ACTION_DEVICE_ID_FILE:
-                if (stat_device(name, export, export_prefix) != 0)
-                        rc = 1;
-                break;
-        case ACTION_ROOT:
-                printf("%s\n", udev_get_dev_path(udev));
-                break;
-        default:
-                fprintf(stderr, "missing option\n");
-                rc = 1;
-                break;
-        }
-
-exit:
-        udev_device_unref(device);
-        return rc;
-}
-
-const struct udevadm_cmd udevadm_info = {
-        .name = "info",
-        .cmd = uinfo,
-        .help = "query sysfs or the udev database",
-};
diff --git a/src/udev/src/udevadm-monitor.c b/src/udev/src/udevadm-monitor.c
deleted file mode 100644 (file)
index 5997dd8..0000000
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * Copyright (C) 2004-2010 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <signal.h>
-#include <getopt.h>
-#include <time.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/epoll.h>
-#include <linux/types.h>
-#include <linux/netlink.h>
-
-#include "udev.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 int adm_monitor(struct udev *udev, int argc, char *argv[])
-{
-        struct sigaction act;
-        sigset_t mask;
-        int option;
-        bool prop = false;
-        bool print_kernel = false;
-        bool print_udev = false;
-        struct udev_list subsystem_match_list;
-        struct udev_list tag_match_list;
-        struct udev_monitor *udev_monitor = NULL;
-        struct udev_monitor *kernel_monitor = NULL;
-        int fd_ep = -1;
-        int fd_kernel = -1, fd_udev = -1;
-        struct epoll_event ep_kernel, ep_udev;
-        int rc = 0;
-
-        static const struct option options[] = {
-                { "property", no_argument, NULL, 'p' },
-                { "environment", no_argument, NULL, 'e' },
-                { "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);
-
-        for (;;) {
-                option = getopt_long(argc, argv, "pekus:t:h", options, NULL);
-                if (option == -1)
-                        break;
-
-                switch (option) {
-                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;
-
-                                util_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':
-                        printf("Usage: udevadm monitor [--property] [--kernel] [--udev] [--help]\n"
-                               "  --property                              print the event properties\n"
-                               "  --kernel                                print kernel uevents\n"
-                               "  --udev                                  print udev events\n"
-                               "  --subsystem-match=<subsystem[/devtype]> filter events by subsystem\n"
-                               "  --tag-match=<tag>                       filter events by tag\n"
-                               "  --help\n\n");
-                        goto out;
-                default:
-                        rc = 1;
-                        goto out;
-                }
-        }
-
-        if (!print_kernel && !print_udev) {
-                print_kernel = true;
-                print_udev = true;
-        }
-
-        /* set signal handlers */
-        memset(&act, 0x00, sizeof(struct sigaction));
-        act.sa_handler = sig_handler;
-        sigemptyset(&act.sa_mask);
-        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) {
-                err(udev, "error creating epoll fd: %m\n");
-                goto out;
-        }
-
-        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");
-                        rc = 1;
-                        goto out;
-                }
-                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");
-                        rc = 2;
-                        goto out;
-                }
-
-                memset(&ep_udev, 0, 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) {
-                        err(udev, "fail to add fd to epoll: %m\n");
-                        goto out;
-                }
-
-                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");
-                        rc = 3;
-                        goto out;
-                }
-                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");
-                        rc = 4;
-                        goto out;
-                }
-
-                memset(&ep_kernel, 0, 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) {
-                        err(udev, "fail to add fd to epoll: %m\n");
-                        goto out;
-                }
-
-                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, ARRAY_SIZE(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);
-                        }
-                }
-        }
-out:
-        if (fd_ep >= 0)
-                close(fd_ep);
-        udev_monitor_unref(udev_monitor);
-        udev_monitor_unref(kernel_monitor);
-        udev_list_cleanup(&subsystem_match_list);
-        udev_list_cleanup(&tag_match_list);
-        return rc;
-}
-
-const struct udevadm_cmd udevadm_monitor = {
-        .name = "monitor",
-        .cmd = adm_monitor,
-        .help = "listen to kernel and udev events",
-};
diff --git a/src/udev/src/udevadm-settle.c b/src/udev/src/udevadm-settle.c
deleted file mode 100644 (file)
index b168def..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright (C) 2006-2009 Kay Sievers <kay@vrfy.org>
- * Copyright (C) 2009 Canonical Ltd.
- * Copyright (C) 2009 Scott James Remnant <scott@netsplit.com>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <syslog.h>
-#include <getopt.h>
-#include <signal.h>
-#include <time.h>
-#include <sys/inotify.h>
-#include <sys/poll.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include "udev.h"
-
-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' },
-                {}
-        };
-        unsigned long long start_usec = now_usec();
-        unsigned long long start = 0;
-        unsigned long long end = 0;
-        int quiet = 0;
-        const char *exists = NULL;
-        unsigned int timeout = 120;
-        struct pollfd pfd[1];
-        struct udev_queue *udev_queue = NULL;
-        int rc = EXIT_FAILURE;
-
-        dbg(udev, "version %s\n", VERSION);
-
-        for (;;) {
-                int option;
-                int seconds;
-
-                option = getopt_long(argc, argv, "s:e:t:E:qh", options, NULL);
-                if (option == -1)
-                        break;
-
-                switch (option) {
-                case 's':
-                        start = strtoull(optarg, NULL, 0);
-                        break;
-                case 'e':
-                        end = strtoull(optarg, NULL, 0);
-                        break;
-                case 't':
-                        seconds = atoi(optarg);
-                        if (seconds >= 0)
-                                timeout = seconds;
-                        else
-                                fprintf(stderr, "invalid timeout value\n");
-                        dbg(udev, "timeout=%i\n", timeout);
-                        break;
-                case 'q':
-                        quiet = 1;
-                        break;
-                case 'E':
-                        exists = optarg;
-                        break;
-                case 'h':
-                        printf("Usage: udevadm settle OPTIONS\n"
-                               "  --timeout=<seconds>     maximum time to wait for events\n"
-                               "  --seq-start=<seqnum>    first seqnum to wait for\n"
-                               "  --seq-end=<seqnum>      last seqnum to wait for\n"
-                               "  --exit-if-exists=<file> stop waiting if file exists\n"
-                               "  --quiet                 do not print list after timeout\n"
-                               "  --help\n\n");
-                        exit(EXIT_SUCCESS);
-                default:
-                        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) {
-                        err(udev, "seq-start larger than seq-end, ignoring\n");
-                        start = 0;
-                        end = 0;
-                }
-
-                if (start > kernel_seq || end > kernel_seq) {
-                        err(udev, "seq-start or seq-end larger than current kernel value, ignoring\n");
-                        start = 0;
-                        end = 0;
-                }
-                info(udev, "start=%llu end=%llu current=%llu\n", start, end, kernel_seq);
-        } else {
-                if (end > 0) {
-                        err(udev, "seq-end needs seq-start parameter, ignoring\n");
-                        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) {
-                                info(udev, "no connection to daemon\n");
-                                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) {
-                err(udev, "inotify_init failed: %m\n");
-        } else {
-                if (inotify_add_watch(pfd[0].fd, udev_get_run_path(udev), IN_MOVED_TO) < 0) {
-                        err(udev, "watching '%s' failed\n", udev_get_run_path(udev));
-                        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) {
-                        unsigned long long age_usec;
-
-                        age_usec = now_usec() - 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) {
-                                        info(udev, "timeout waiting for udev queue\n");
-                                        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);
-        udev_queue_unref(udev_queue);
-        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/src/udevadm-test-builtin.c b/src/udev/src/udevadm-test-builtin.c
deleted file mode 100644 (file)
index 3a49f7c..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2011 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <syslog.h>
-#include <getopt.h>
-#include <signal.h>
-#include <time.h>
-#include <sys/inotify.h>
-#include <sys/poll.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#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;
-
-        dbg(udev, "version %s\n", VERSION);
-
-        for (;;) {
-                int option;
-
-                option = getopt_long(argc, argv, "h", options, NULL);
-                if (option == -1)
-                        break;
-
-                switch (option) {
-                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\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 (strncmp(syspath, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
-                util_strscpyl(filename, sizeof(filename), udev_get_sys_path(udev), syspath, NULL);
-        else
-                util_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;
-        }
-
-        if (udev_builtin_run(dev, cmd, command, true) < 0) {
-                fprintf(stderr, "error executing '%s'\n\n", command);
-                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/src/udevadm-test.c b/src/udev/src/udevadm-test.c
deleted file mode 100644 (file)
index 6275cff..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2003-2004 Greg Kroah-Hartman <greg@kroah.com>
- * Copyright (C) 2004-2008 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <errno.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <syslog.h>
-#include <getopt.h>
-#include <sys/signalfd.h>
-
-#include "udev.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_event *event = NULL;
-        struct udev_device *dev = NULL;
-        struct udev_rules *rules = NULL;
-        struct udev_list_entry *entry;
-        sigset_t mask, sigmask_orig;
-        int err;
-        int rc = 0;
-
-        static const struct option options[] = {
-                { "action", required_argument, NULL, 'a' },
-                { "resolve-names", required_argument, NULL, 'N' },
-                { "help", no_argument, NULL, 'h' },
-                {}
-        };
-
-        info(udev, "version %s\n", VERSION);
-
-        for (;;) {
-                int option;
-
-                option = getopt_long(argc, argv, "a:s:N:fh", options, NULL);
-                if (option == -1)
-                        break;
-
-                dbg(udev, "option '%c'\n", option);
-                switch (option) {
-                case 'a':
-                        action = optarg;
-                        break;
-                case 'N':
-                        if (strcmp (optarg, "early") == 0) {
-                                resolve_names = 1;
-                        } else if (strcmp (optarg, "late") == 0) {
-                                resolve_names = 0;
-                        } else if (strcmp (optarg, "never") == 0) {
-                                resolve_names = -1;
-                        } else {
-                                fprintf(stderr, "resolve-names must be early, late or never\n");
-                                err(udev, "resolve-names must be early, late or never\n");
-                                exit(EXIT_FAILURE);
-                        }
-                        break;
-                case 'h':
-                        printf("Usage: udevadm test OPTIONS <syspath>\n"
-                               "  --action=<string>     set action string\n"
-                               "  --help\n\n");
-                        exit(EXIT_SUCCESS);
-                default:
-                        exit(EXIT_FAILURE);
-                }
-        }
-        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 (strncmp(syspath, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
-                util_strscpyl(filename, sizeof(filename), udev_get_sys_path(udev), syspath, NULL);
-        else
-                util_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_event_unref(event);
-        udev_device_unref(dev);
-        udev_rules_unref(rules);
-        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/src/udevadm-trigger.c b/src/udev/src/udevadm-trigger.c
deleted file mode 100644 (file)
index 3cce23d..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright (C) 2008-2009 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <errno.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <syslog.h>
-#include <fnmatch.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-
-#include "udev.h"
-
-static int verbose;
-static int dry_run;
-
-static void exec_list(struct udev_enumerate *udev_enumerate, const char *action)
-{
-        struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
-        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;
-                util_strscpyl(filename, sizeof(filename), udev_list_entry_get_name(entry), "/uevent", NULL);
-                fd = open(filename, O_WRONLY);
-                if (fd < 0) {
-                        dbg(udev, "error on opening %s: %m\n", filename);
-                        continue;
-                }
-                if (write(fd, action, strlen(action)) < 0)
-                        info(udev, "error writing '%s' to '%s': %m\n", action, filename);
-                close(fd);
-        }
-}
-
-static const char *keyval(const char *str, const char **val, char *buf, size_t size)
-{
-        char *pos;
-
-        util_strscpy(buf, size,str);
-        pos = strchr(buf, '=');
-        if (pos != NULL) {
-                pos[0] = 0;
-                pos++;
-        }
-        *val = pos;
-        return buf;
-}
-
-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";
-        struct udev_enumerate *udev_enumerate;
-        int rc = 0;
-
-        dbg(udev, "version %s\n", VERSION);
-        udev_enumerate = udev_enumerate_new(udev);
-        if (udev_enumerate == NULL) {
-                rc = 1;
-                goto exit;
-        }
-
-        for (;;) {
-                int option;
-                const char *key;
-                const char *val;
-                char buf[UTIL_PATH_SIZE];
-
-                option = getopt_long(argc, argv, "vng:o:t:hc:p:s:S:a:A:y:b:", options, NULL);
-                if (option == -1)
-                        break;
-
-                switch (option) {
-                case 'v':
-                        verbose = 1;
-                        break;
-                case 'n':
-                        dry_run = 1;
-                        break;
-                case 't':
-                        if (strcmp(optarg, "devices") == 0) {
-                                device_type = TYPE_DEVICES;
-                        } else if (strcmp(optarg, "subsystems") == 0) {
-                                device_type = TYPE_SUBSYSTEMS;
-                        } else {
-                                err(udev, "unknown type --type=%s\n", optarg);
-                                rc = 2;
-                                goto exit;
-                        }
-                        break;
-                case 'c':
-                        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 (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
-                                util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), optarg, NULL);
-                        else
-                                util_strscpy(path, sizeof(path), optarg);
-                        util_remove_trailing_chars(path, '/');
-                        dev = udev_device_new_from_syspath(udev, path);
-                        if (dev == NULL) {
-                                err(udev, "unable to open the device '%s'\n", optarg);
-                                rc = 2;
-                                goto exit;
-                        }
-                        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':
-                        printf("Usage: udevadm trigger OPTIONS\n"
-                               "  --verbose                       print the list of devices while running\n"
-                               "  --dry-run                       do not actually trigger the events\n"
-                               "  --type=                         type of events to trigger\n"
-                               "      devices                       sys devices (default)\n"
-                               "      subsystems                    sys subsystems and drivers\n"
-                               "  --action=<action>               event action value, default is \"change\"\n"
-                               "  --subsystem-match=<subsystem>   trigger devices from a matching subsystem\n"
-                               "  --subsystem-nomatch=<subsystem> exclude devices from a matching subsystem\n"
-                               "  --attr-match=<file[=<value>]>   trigger devices with a matching attribute\n"
-                               "  --attr-nomatch=<file[=<value>]> exclude devices with a matching attribute\n"
-                               "  --property-match=<key>=<value>  trigger devices with a matching property\n"
-                               "  --tag-match=<key>=<value>       trigger devices with a matching property\n"
-                               "  --sysname-match=<name>          trigger devices with a matching name\n"
-                               "  --parent-match=<name>           trigger devices with that parent device\n"
-                               "  --help\n\n");
-                        goto exit;
-                default:
-                        rc = 1;
-                        goto exit;
-                }
-        }
-
-        switch (device_type) {
-        case TYPE_SUBSYSTEMS:
-                udev_enumerate_scan_subsystems(udev_enumerate);
-                exec_list(udev_enumerate, action);
-                goto exit;
-        case TYPE_DEVICES:
-                udev_enumerate_scan_devices(udev_enumerate);
-                exec_list(udev_enumerate, action);
-                goto exit;
-        default:
-                goto exit;
-        }
-exit:
-        udev_enumerate_unref(udev_enumerate);
-        return rc;
-}
-
-const struct udevadm_cmd udevadm_trigger = {
-        .name = "trigger",
-        .cmd = adm_trigger,
-        .help = "request events from the kernel",
-};
diff --git a/src/udev/src/udevadm.c b/src/udev/src/udevadm.c
deleted file mode 100644 (file)
index 224ece0..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2007-2009 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <errno.h>
-#include <getopt.h>
-
-#include "udev.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)
-{
-        if (debug) {
-                fprintf(stderr, "%s: ", fn);
-                vfprintf(stderr, format, args);
-        } else {
-                va_list args2;
-
-                va_copy(args2, args);
-                vfprintf(stderr, format, args2);
-                va_end(args2);
-                vsyslog(priority, 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_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 < ARRAY_SIZE(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) {
-                debug = true;
-                if (udev_get_log_priority(udev) < LOG_INFO)
-                        udev_set_log_priority(udev, LOG_INFO);
-        }
-        info(udev, "calling: %s\n", 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;
-
-        udev_log_init("udevadm");
-        udev_set_log_fn(udev, udev_main_log);
-        udev_selinux_init(udev);
-
-        for (;;) {
-                int option;
-
-                option = getopt_long(argc, argv, "+dhV", options, NULL);
-                if (option == -1)
-                        break;
-
-                switch (option) {
-                case 'd':
-                        debug = true;
-                        if (udev_get_log_priority(udev) < LOG_INFO)
-                                udev_set_log_priority(udev, LOG_INFO);
-                        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];
-
-        info(udev, "runtime dir '%s'\n", udev_get_run_path(udev));
-
-        if (command != NULL)
-                for (i = 0; i < ARRAY_SIZE(udevadm_cmds); i++) {
-                        if (strcmp(udevadm_cmds[i]->name, command) == 0) {
-                                argc -= optind;
-                                argv += optind;
-                                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:
-        udev_selinux_exit(udev);
-        udev_unref(udev);
-        udev_log_close();
-        return rc;
-}
diff --git a/src/udev/src/udevadm.xml b/src/udev/src/udevadm.xml
deleted file mode 100644 (file)
index 455ce80..0000000
+++ /dev/null
@@ -1,472 +0,0 @@
-<?xml version='1.0'?>
-<?xml-stylesheet type="text/xsl" href="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl"?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<refentry id="udevadm">
-  <refentryinfo>
-    <title>udevadm</title>
-    <productname>udev</productname>
-  </refentryinfo>
-
-  <refmeta>
-    <refentrytitle>udevadm</refentrytitle>
-    <manvolnum>8</manvolnum>
-    <refmiscinfo class="version"></refmiscinfo>
-  </refmeta>
-
-  <refnamediv>
-    <refname>udevadm</refname><refpurpose>udev management tool</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <cmdsynopsis>
-      <command>udevadm</command>
-        <arg><option>--debug</option></arg>
-        <arg><option>--version</option></arg>
-        <arg><option>--help</option></arg>
-    </cmdsynopsis>
-    <cmdsynopsis>
-      <command>udevadm info <replaceable>options</replaceable></command>
-    </cmdsynopsis>
-    <cmdsynopsis>
-      <command>udevadm trigger <optional>options</optional></command>
-    </cmdsynopsis>
-    <cmdsynopsis>
-      <command>udevadm settle <optional>options</optional></command>
-    </cmdsynopsis>
-    <cmdsynopsis>
-      <command>udevadm control <replaceable>command</replaceable></command>
-    </cmdsynopsis>
-    <cmdsynopsis>
-      <command>udevadm monitor <optional>options</optional></command>
-    </cmdsynopsis>
-    <cmdsynopsis>
-      <command>udevadm test <optional>options</optional> <replaceable>devpath</replaceable></command>
-    </cmdsynopsis>
-    <cmdsynopsis>
-      <command>udevadm test-builtin <optional>options</optional> <replaceable>command</replaceable> <replaceable>devpath</replaceable></command>
-    </cmdsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1><title>Description</title>
-    <para>udevadm expects a command and command specific options.  It
-    controls the runtime behavior of udev, requests kernel events,
-    manages the event queue, and provides simple debugging mechanisms.</para>
-  </refsect1>
-
-  <refsect1><title>OPTIONS</title>
-    <variablelist>
-      <varlistentry>
-        <term><option>--debug</option></term>
-        <listitem>
-          <para>Print debug messages to stderr.</para>
-        </listitem>
-      </varlistentry>
-      <varlistentry>
-        <term><option>--version</option></term>
-        <listitem>
-          <para>Print version number.</para>
-        </listitem>
-      </varlistentry>
-      <varlistentry>
-        <term><option>--help</option></term>
-        <listitem>
-          <para>Print help text.</para>
-        </listitem>
-      </varlistentry>
-    </variablelist>
-
-    <refsect2><title>udevadm info <replaceable>options</replaceable></title>
-      <para>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.</para>
-      <variablelist>
-        <varlistentry>
-          <term><option>--query=<replaceable>type</replaceable></option></term>
-          <listitem>
-            <para>Query the database for specified type of device data. It needs the
-            <option>--path</option> or <option>--name</option> to identify the specified
-            device. Valid queries are:
-            <command>name</command>, <command>symlink</command>, <command>path</command>,
-            <command>property</command>, <command>all</command>.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--path=<replaceable>devpath</replaceable></option></term>
-          <listitem>
-            <para>The devpath of the device to query.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--name=<replaceable>file</replaceable></option></term>
-          <listitem>
-            <para>The name of the device node or a symlink to query</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--root</option></term>
-          <listitem>
-            <para>The udev root directory: <filename>/dev</filename>. If used in conjunction
-            with a <command>name</command> or <command>symlink</command> query, the
-            query returns the absolute path including the root directory.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--run</option></term>
-          <listitem>
-            <para>The udev runtime directory: <filename>/run/udev</filename>.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--attribute-walk</option></term>
-          <listitem>
-            <para>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.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--export</option></term>
-          <listitem>
-            <para>Print output as key/value pairs. Values are enclosed in single quotes.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--export-prefix=<replaceable>name</replaceable></option></term>
-          <listitem>
-            <para>Add a prefix to the key name of exported values.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--device-id-of-file=<replaceable>file</replaceable></option></term>
-          <listitem>
-            <para>Print major/minor numbers of the underlying device, where the file
-            lives on.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--export-db</option></term>
-          <listitem>
-            <para>Export the content of the udev database.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--cleanup-db</option></term>
-          <listitem>
-            <para>Cleanup the udev database.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--version</option></term>
-          <listitem>
-            <para>Print version.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--help</option></term>
-          <listitem>
-            <para>Print help text.</para>
-          </listitem>
-        </varlistentry>
-      </variablelist>
-    </refsect2>
-
-    <refsect2><title>udevadm trigger <optional>options</optional></title>
-      <para>Request device events from the kernel. Primarily used to replay events at system coldplug time.</para>
-      <variablelist>
-        <varlistentry>
-          <term><option>--verbose</option></term>
-          <listitem>
-            <para>Print the list of devices which will be triggered.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--dry-run</option></term>
-          <listitem>
-            <para>Do not actually trigger the event.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--type=<replaceable>type</replaceable></option></term>
-          <listitem>
-            <para>Trigger a specific type of devices. Valid types are:
-            <command>devices</command>, <command>subsystems</command>.
-            The default value is <command>devices</command>.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--action=<replaceable>action</replaceable></option></term>
-          <listitem>
-            <para>Type of event to be triggered. The default value is <command>change</command>.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--subsystem-match=<replaceable>subsystem</replaceable></option></term>
-          <listitem>
-            <para>Trigger events for devices which belong to a matching subsystem. This option
-            can be specified multiple times and supports shell style pattern matching.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--subsystem-nomatch=<replaceable>subsystem</replaceable></option></term>
-          <listitem>
-            <para>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.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--attr-match=<replaceable>attribute</replaceable>=<replaceable>value</replaceable></option></term>
-          <listitem>
-            <para>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.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--attr-nomatch=<replaceable>attribute</replaceable>=<replaceable>value</replaceable></option></term>
-          <listitem>
-            <para>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.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--property-match=<replaceable>property</replaceable>=<replaceable>value</replaceable></option></term>
-          <listitem>
-            <para>Trigger events for devices with a matching property value. This option can be
-            specified multiple times and supports shell style pattern matching.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--tag-match=<replaceable>property</replaceable></option></term>
-          <listitem>
-            <para>Trigger events for devices with a matching tag. This option can be
-            specified multiple times.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--sysname-match=<replaceable>name</replaceable></option></term>
-          <listitem>
-            <para>Trigger events for devices with a matching sys device name. This option can be
-            specified multiple times and supports shell style pattern matching.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--parent-match=<replaceable>syspath</replaceable></option></term>
-          <listitem>
-            <para>Trigger events for all children of a given device.</para>
-          </listitem>
-        </varlistentry>
-      </variablelist>
-    </refsect2>
-
-    <refsect2><title>udevadm settle <optional>options</optional></title>
-      <para>Watches the udev event queue, and exits if all current events are handled.</para>
-      <variablelist>
-        <varlistentry>
-          <term><option>--timeout=<replaceable>seconds</replaceable></option></term>
-          <listitem>
-            <para>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.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--seq-start=<replaceable>seqnum</replaceable></option></term>
-          <listitem>
-            <para>Wait only for events after the given sequence number.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--seq-end=<replaceable>seqnum</replaceable></option></term>
-          <listitem>
-            <para>Wait only for events before the given sequence number.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--exit-if-exists=<replaceable>file</replaceable></option></term>
-          <listitem>
-            <para>Stop waiting if file exists.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--quiet</option></term>
-          <listitem>
-            <para>Do not print any output, like the remaining queue entries when reaching the timeout.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--help</option></term>
-          <listitem>
-            <para>Print help text.</para>
-          </listitem>
-        </varlistentry>
-      </variablelist>
-    </refsect2>
-
-    <refsect2><title>udevadm control <replaceable>command</replaceable></title>
-      <para>Modify the internal state of the running udev daemon.</para>
-      <variablelist>
-        <varlistentry>
-          <term><option>--exit</option></term>
-          <listitem>
-            <para>Signal and wait for udevd to exit.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--log-priority=<replaceable>value</replaceable></option></term>
-          <listitem>
-            <para>Set the internal log level of udevd. Valid values are the numerical
-            syslog priorities or their textual representations: <option>err</option>,
-            <option>info</option> and <option>debug</option>.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--stop-exec-queue</option></term>
-          <listitem>
-            <para>Signal udevd to stop executing new events. Incoming events
-            will be queued.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--start-exec-queue</option></term>
-          <listitem>
-            <para>Signal udevd to enable the execution of events.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--reload</option></term>
-          <listitem>
-            <para>Signal 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.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--property=<replaceable>KEY</replaceable>=<replaceable>value</replaceable></option></term>
-          <listitem>
-            <para>Set a global property for all events.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--children-max=</option><replaceable>value</replaceable></term>
-          <listitem>
-            <para>Set the maximum number of events, udevd will handle at the
-            same time.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--timeout=</option><replaceable>seconds</replaceable></term>
-          <listitem>
-            <para>The maximum number seconds to wait for a reply from udevd.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--help</option></term>
-          <listitem>
-            <para>Print help text.</para>
-          </listitem>
-        </varlistentry>
-      </variablelist>
-    </refsect2>
-
-    <refsect2><title>udevadm monitor <optional>options</optional></title>
-      <para>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.
-      </para>
-      <variablelist>
-        <varlistentry>
-          <term><option>--kernel</option></term>
-          <listitem>
-            <para>Print the kernel uevents.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--udev</option></term>
-          <listitem>
-            <para>Print the udev event after the rule processing.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--property</option></term>
-          <listitem>
-            <para>Also print the properties of the event.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--subsystem-match=<replaceable>string[/string]</replaceable></option></term>
-          <listitem>
-            <para>Filter events by subsystem[/devtype]. Only udev events with a matching subsystem value will pass.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--tag-match=<replaceable>string</replaceable></option></term>
-          <listitem>
-            <para>Filter events by property. Only udev events with a given tag attached will pass.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--help</option></term>
-          <listitem>
-            <para>Print help text.</para>
-          </listitem>
-        </varlistentry>
-      </variablelist>
-    </refsect2>
-
-    <refsect2><title>udevadm test <optional>options</optional> <replaceable>devpath</replaceable></title>
-      <para>Simulate a udev event run for the given device, and print debug output.</para>
-      <variablelist>
-        <varlistentry>
-          <term><option>--action=<replaceable>string</replaceable></option></term>
-          <listitem>
-            <para>The action string.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--subsystem=<replaceable>string</replaceable></option></term>
-          <listitem>
-            <para>The subsystem string.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>--help</option></term>
-          <listitem>
-            <para>Print help text.</para>
-          </listitem>
-        </varlistentry>
-      </variablelist>
-    </refsect2>
-
-    <refsect2><title>udevadm test-builtin <optional>options</optional> <replaceable>command</replaceable> <replaceable>devpath</replaceable></title>
-      <para>Run a built-in command for the given device, and print debug output.</para>
-      <variablelist>
-        <varlistentry>
-          <term><option>--help</option></term>
-          <listitem>
-            <para>Print help text.</para>
-          </listitem>
-        </varlistentry>
-      </variablelist>
-    </refsect2>
-  </refsect1>
-
-  <refsect1><title>Author</title>
-    <para>Written by Kay Sievers <email>kay.sievers@vrfy.org</email>.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>See Also</title>
-    <para><citerefentry>
-        <refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum>
-    </citerefentry>
-    <citerefentry>
-        <refentrytitle>udevd</refentrytitle><manvolnum>8</manvolnum>
-    </citerefentry></para>
-  </refsect1>
-</refentry>
diff --git a/src/udev/src/udevd.c b/src/udev/src/udevd.c
deleted file mode 100644 (file)
index 1702217..0000000
+++ /dev/null
@@ -1,1746 +0,0 @@
-/*
- * Copyright (C) 2004-2011 Kay Sievers <kay.sievers@vrfy.org>
- * Copyright (C) 2004 Chris Friesen <chris_friesen@sympatico.ca>
- * Copyright (C) 2009 Canonical Ltd.
- * Copyright (C) 2009 Scott James Remnant <scott@netsplit.com>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stddef.h>
-#include <signal.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <string.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <time.h>
-#include <getopt.h>
-#include <dirent.h>
-#include <sys/time.h>
-#include <sys/prctl.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/signalfd.h>
-#include <sys/epoll.h>
-#include <sys/poll.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/inotify.h>
-#include <sys/utsname.h>
-
-#include "udev.h"
-#include "sd-daemon.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)
-{
-        if (debug) {
-                char buf[1024];
-                struct timespec ts;
-
-                vsnprintf(buf, sizeof(buf), format, args);
-                clock_gettime(CLOCK_MONOTONIC, &ts);
-                fprintf(stderr, "[%llu.%06u] [%u] %s: %s",
-                        (unsigned long long) ts.tv_sec, (unsigned int) ts.tv_nsec/1000,
-                        (int) getpid(), fn, buf);
-        } else {
-                vsyslog(priority, 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 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;
-        bool is_block;
-        int ifindex;
-};
-
-static struct event *node_to_event(struct udev_list_node *node)
-{
-        char *event;
-
-        event = (char *)node;
-        event -= offsetof(struct event, node);
-        return (struct event *)event;
-}
-
-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;
-        unsigned long long event_start_usec;
-};
-
-/* passed from worker to main process */
-struct worker_message {
-        pid_t pid;
-        int exitcode;
-};
-
-static struct worker *node_to_worker(struct udev_list_node *node)
-{
-        char *worker;
-
-        worker = (char *)node;
-        worker -= offsetof(struct worker, node);
-        return (struct worker *)worker;
-}
-
-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);
-                info(event->udev, "seq %llu done with %i\n", 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;
-        info(worker->udev, "worker [%u] cleaned up\n", 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 = calloc(1, sizeof(struct worker));
-        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) {
-                        err(udev, "error creating signalfd %m\n");
-                        rc = 2;
-                        goto out;
-                }
-
-                fd_ep = epoll_create1(EPOLL_CLOEXEC);
-                if (fd_ep < 0) {
-                        err(udev, "error creating epoll fd: %m\n");
-                        rc = 3;
-                        goto out;
-                }
-
-                memset(&ep_signal, 0, sizeof(struct epoll_event));
-                ep_signal.events = EPOLLIN;
-                ep_signal.data.fd = fd_signal;
-
-                fd_monitor = udev_monitor_get_fd(worker_monitor);
-                memset(&ep_monitor, 0, 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) {
-                        err(udev, "fail to add fds to epoll: %m\n");
-                        rc = 4;
-                        goto out;
-                }
-
-                /* request TERM signal if parent exits */
-                prctl(PR_SET_PDEATHSIG, SIGTERM);
-
-                for (;;) {
-                        struct udev_event *udev_event;
-                        struct worker_message msg;
-                        int err;
-
-                        info(udev, "seq %llu running\n", 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 */
-                        memset(&msg, 0, sizeof(struct worker_message));
-                        if (err != 0)
-                                msg.exitcode = err;
-                        msg.pid = getpid();
-                        send(worker_watch[WRITE_END], &msg, sizeof(struct worker_message), 0);
-
-                        info(udev, "seq %llu processed with %i\n", 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, ARRAY_SIZE(ev), -1);
-                                if (fdcount < 0) {
-                                        if (errno == EINTR)
-                                                continue;
-                                        err = -errno;
-                                        err(udev, "failed to poll: %m\n");
-                                        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);
-                udev_log_close();
-                exit(rc);
-        }
-        case -1:
-                udev_monitor_unref(worker_monitor);
-                event->state = EVENT_QUEUED;
-                free(worker);
-                err(udev, "fork of child failed: %m\n");
-                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_usec();
-                worker->event = event;
-                event->state = EVENT_RUNNING;
-                udev_list_node_append(&worker->node, &worker_list);
-                children++;
-                info(udev, "seq %llu forked new worker [%u]\n", 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) {
-                        err(event->udev, "worker [%u] did not accept message %zi (%m), kill it\n", 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_usec();
-                event->state = EVENT_RUNNING;
-                return;
-        }
-
-        if (children >= children_max) {
-                if (children_max > 1)
-                        info(event->udev, "maximum number (%i) of children reached\n", 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 = calloc(1, sizeof(struct event));
-        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 = (strcmp("block", udev_device_get_subsystem(dev)) == 0);
-        event->ifindex = udev_device_get_ifindex(dev);
-
-        udev_queue_export_device_queued(udev_queue_export, dev);
-        info(event->udev, "seq %llu queued, '%s' '%s'\n", 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, int retain)
-{
-        struct udev_list_node *loop;
-        int max;
-
-        if (children <= retain)
-                return;
-
-        max = children - retain;
-
-        udev_list_node_foreach(loop, &worker_list) {
-                struct worker *worker = node_to_worker(loop);
-
-                if (max-- <= 0)
-                        break;
-
-                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 && strcmp(loop_event->devpath, event->devpath_old) == 0) {
-                        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;
-                }
-
-                /* 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)) {
-                        dbg(udev, "delay seq %llu (%s)\n", event->seqnum, event->devpath);
-                        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) {
-                info(udev, "udevd message (SET_LOG_PRIORITY) received, log_priority=%i\n", i);
-                udev_set_log_priority(udev, i);
-                worker_kill(udev, 0);
-        }
-
-        if (udev_ctrl_get_stop_exec_queue(ctrl_msg) > 0) {
-                info(udev, "udevd message (STOP_EXEC_QUEUE) received\n");
-                stop_exec_queue = true;
-        }
-
-        if (udev_ctrl_get_start_exec_queue(ctrl_msg) > 0) {
-                info(udev, "udevd message (START_EXEC_QUEUE) received\n");
-                stop_exec_queue = false;
-        }
-
-        if (udev_ctrl_get_reload(ctrl_msg) > 0) {
-                info(udev, "udevd message (RELOAD) received\n");
-                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') {
-                                        info(udev, "udevd message (ENV) received, unset '%s'\n", key);
-                                        udev_add_property(udev, key, NULL);
-                                } else {
-                                        info(udev, "udevd message (ENV) received, set '%s=%s'\n", key, val);
-                                        udev_add_property(udev, key, val);
-                                }
-                        } else {
-                                err(udev, "wrong key format '%s'\n", key);
-                        }
-                        free(key);
-                }
-                worker_kill(udev, 0);
-        }
-
-        i = udev_ctrl_get_set_children_max(ctrl_msg);
-        if (i >= 0) {
-                info(udev, "udevd message (SET_MAX_CHILDREN) received, children_max=%i\n", i);
-                children_max = i;
-        }
-
-        if (udev_ctrl_get_ping(ctrl_msg) > 0)
-                info(udev, "udevd message (SYNC) received\n");
-
-        if (udev_ctrl_get_exit(ctrl_msg) > 0) {
-                info(udev, "udevd message (EXIT) received\n");
-                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) {
-                err(udev, "error getting buffer for inotify\n");
-                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) {
-                        info(udev, "inotify event: %x for %s\n", ev->mask, udev_device_get_devnode(dev));
-                        if (ev->mask & IN_CLOSE_WRITE) {
-                                char filename[UTIL_PATH_SIZE];
-                                int fd;
-
-                                info(udev, "device %s closed, synthesising 'change'\n", udev_device_get_devnode(dev));
-                                util_strscpyl(filename, sizeof(filename), udev_device_get_syspath(dev), "/uevent", NULL);
-                                fd = open(filename, O_WRONLY);
-                                if (fd >= 0) {
-                                        if (write(fd, "change", 6) < 0)
-                                                info(udev, "error writing uevent: %m\n");
-                                        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;
-                                info(udev, "worker [%u] exit\n", pid);
-
-                                if (WIFEXITED(status)) {
-                                        if (WEXITSTATUS(status) != 0)
-                                                err(udev, "worker [%u] exit with return code %i\n", pid, WEXITSTATUS(status));
-                                } else if (WIFSIGNALED(status)) {
-                                        err(udev, "worker [%u] terminated by signal %i (%s)\n",
-                                            pid, WTERMSIG(status), strsignal(WTERMSIG(status)));
-                                } else if (WIFSTOPPED(status)) {
-                                        err(udev, "worker [%u] stopped\n", pid);
-                                } else if (WIFCONTINUED(status)) {
-                                        err(udev, "worker [%u] continued\n", pid);
-                                } else {
-                                        err(udev, "worker [%u] exit with status 0x%04x\n", pid, status);
-                                }
-
-                                if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
-                                        if (worker->event) {
-                                                err(udev, "worker [%u] failed while handling '%s'\n",
-                                                    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 void static_dev_create_from_modules(struct udev *udev)
-{
-        struct utsname kernel;
-        char modules[UTIL_PATH_SIZE];
-        char buf[4096];
-        FILE *f;
-
-        uname(&kernel);
-        util_strscpyl(modules, sizeof(modules), "/lib/modules/", kernel.release, "/modules.devname", NULL);
-        f = fopen(modules, "r");
-        if (f == NULL)
-                return;
-
-        while (fgets(buf, sizeof(buf), f) != NULL) {
-                char *s;
-                const char *modname;
-                const char *devname;
-                const char *devno;
-                int maj, min;
-                char type;
-                mode_t mode;
-                char filename[UTIL_PATH_SIZE];
-
-                if (buf[0] == '#')
-                        continue;
-
-                modname = buf;
-                s = strchr(modname, ' ');
-                if (s == NULL)
-                        continue;
-                s[0] = '\0';
-
-                devname = &s[1];
-                s = strchr(devname, ' ');
-                if (s == NULL)
-                        continue;
-                s[0] = '\0';
-
-                devno = &s[1];
-                s = strchr(devno, ' ');
-                if (s == NULL)
-                        s = strchr(devno, '\n');
-                if (s != NULL)
-                        s[0] = '\0';
-                if (sscanf(devno, "%c%u:%u", &type, &maj, &min) != 3)
-                        continue;
-
-                if (type == 'c')
-                        mode = S_IFCHR;
-                else if (type == 'b')
-                        mode = S_IFBLK;
-                else
-                        continue;
-
-                util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/", devname, NULL);
-                util_create_path_selinux(udev, filename);
-                udev_selinux_setfscreatecon(udev, filename, mode);
-                info(udev, "mknod '%s' %c%u:%u\n", filename, type, maj, min);
-                if (mknod(filename, mode, makedev(maj, min)) < 0 && errno == EEXIST)
-                        utimensat(AT_FDCWD, filename, NULL, 0);
-                udev_selinux_resetfscreatecon(udev);
-        }
-
-        fclose(f);
-}
-
-static int copy_dev_dir(struct udev *udev, DIR *dir_from, DIR *dir_to, int maxdepth)
-{
-        struct dirent *dent;
-
-        for (dent = readdir(dir_from); dent != NULL; dent = readdir(dir_from)) {
-                struct stat stats;
-
-                if (dent->d_name[0] == '.')
-                        continue;
-                if (fstatat(dirfd(dir_from), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) != 0)
-                        continue;
-
-                if (S_ISBLK(stats.st_mode) || S_ISCHR(stats.st_mode)) {
-                        udev_selinux_setfscreateconat(udev, dirfd(dir_to), dent->d_name, stats.st_mode & 0777);
-                        if (mknodat(dirfd(dir_to), dent->d_name, stats.st_mode, stats.st_rdev) == 0) {
-                                fchmodat(dirfd(dir_to), dent->d_name, stats.st_mode & 0777, 0);
-                                fchownat(dirfd(dir_to), dent->d_name, stats.st_uid, stats.st_gid, 0);
-                        } else {
-                                utimensat(dirfd(dir_to), dent->d_name, NULL, 0);
-                        }
-                        udev_selinux_resetfscreatecon(udev);
-                } else if (S_ISLNK(stats.st_mode)) {
-                        char target[UTIL_PATH_SIZE];
-                        ssize_t len;
-
-                        len = readlinkat(dirfd(dir_from), dent->d_name, target, sizeof(target));
-                        if (len <= 0 || len == (ssize_t)sizeof(target))
-                                continue;
-                        target[len] = '\0';
-                        udev_selinux_setfscreateconat(udev, dirfd(dir_to), dent->d_name, S_IFLNK);
-                        if (symlinkat(target, dirfd(dir_to), dent->d_name) < 0 && errno == EEXIST)
-                                utimensat(dirfd(dir_to), dent->d_name, NULL, AT_SYMLINK_NOFOLLOW);
-                        udev_selinux_resetfscreatecon(udev);
-                } else if (S_ISDIR(stats.st_mode)) {
-                        DIR *dir2_from, *dir2_to;
-
-                        if (maxdepth == 0)
-                                continue;
-
-                        udev_selinux_setfscreateconat(udev, dirfd(dir_to), dent->d_name, S_IFDIR|0755);
-                        mkdirat(dirfd(dir_to), dent->d_name, 0755);
-                        udev_selinux_resetfscreatecon(udev);
-
-                        dir2_to = fdopendir(openat(dirfd(dir_to), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
-                        if (dir2_to == NULL)
-                                continue;
-
-                        dir2_from = fdopendir(openat(dirfd(dir_from), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
-                        if (dir2_from == NULL) {
-                                closedir(dir2_to);
-                                continue;
-                        }
-
-                        copy_dev_dir(udev, dir2_from, dir2_to, maxdepth-1);
-
-                        closedir(dir2_to);
-                        closedir(dir2_from);
-                }
-        }
-
-        return 0;
-}
-
-static void static_dev_create_links(struct udev *udev, DIR *dir)
-{
-        struct stdlinks {
-                const char *link;
-                const char *target;
-        };
-        static const struct stdlinks stdlinks[] = {
-                { "core", "/proc/kcore" },
-                { "fd", "/proc/self/fd" },
-                { "stdin", "/proc/self/fd/0" },
-                { "stdout", "/proc/self/fd/1" },
-                { "stderr", "/proc/self/fd/2" },
-        };
-        unsigned int i;
-
-        for (i = 0; i < ARRAY_SIZE(stdlinks); i++) {
-                struct stat sb;
-
-                if (stat(stdlinks[i].target, &sb) == 0) {
-                        udev_selinux_setfscreateconat(udev, dirfd(dir), stdlinks[i].link, S_IFLNK);
-                        if (symlinkat(stdlinks[i].target, dirfd(dir), stdlinks[i].link) < 0 && errno == EEXIST)
-                                utimensat(dirfd(dir), stdlinks[i].link, NULL, AT_SYMLINK_NOFOLLOW);
-                        udev_selinux_resetfscreatecon(udev);
-                }
-        }
-}
-
-static void static_dev_create_from_devices(struct udev *udev, DIR *dir)
-{
-        DIR *dir_from;
-
-        dir_from = opendir(PKGLIBEXECDIR "/devices");
-        if (dir_from == NULL)
-                return;
-        copy_dev_dir(udev, dir_from, dir, 8);
-        closedir(dir_from);
-}
-
-static void static_dev_create(struct udev *udev)
-{
-        DIR *dir;
-
-        dir = opendir(udev_get_dev_path(udev));
-        if (dir == NULL)
-                return;
-
-        static_dev_create_links(udev, dir);
-        static_dev_create_from_devices(udev, dir);
-
-        closedir(dir);
-}
-
-static int mem_size_mb(void)
-{
-        FILE *f;
-        char buf[4096];
-        long int memsize = -1;
-
-        f = fopen("/proc/meminfo", "r");
-        if (f == NULL)
-                return -1;
-
-        while (fgets(buf, sizeof(buf), f) != NULL) {
-                long int value;
-
-                if (sscanf(buf, "MemTotal: %ld kB", &value) == 1) {
-                        memsize = value / 1024;
-                        break;
-                }
-        }
-
-        fclose(f);
-        return memsize;
-}
-
-static int convert_db(struct udev *udev)
-{
-        char filename[UTIL_PATH_SIZE];
-        FILE *f;
-        struct udev_enumerate *udev_enumerate;
-        struct udev_list_entry *list_entry;
-
-        /* current database */
-        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/data", NULL);
-        if (access(filename, F_OK) >= 0)
-                return 0;
-
-        /* make sure we do not get here again */
-        util_create_path(udev, filename);
-        mkdir(filename, 0755);
-
-        /* old database */
-        util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev/db", NULL);
-        if (access(filename, F_OK) < 0)
-                return 0;
-
-        f = fopen("/dev/kmsg", "w");
-        if (f != NULL) {
-                fprintf(f, "<30>udevd[%u]: converting old udev database\n", getpid());
-                fclose(f);
-        }
-
-        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)
-                        continue;
-
-                /* try to find the old database for devices without a current one */
-                if (udev_device_read_db(device, NULL) < 0) {
-                        bool have_db;
-                        const char *id;
-                        struct stat stats;
-                        char devpath[UTIL_PATH_SIZE];
-                        char from[UTIL_PATH_SIZE];
-
-                        have_db = false;
-
-                        /* find database in old location */
-                        id = udev_device_get_id_filename(device);
-                        util_strscpyl(from, sizeof(from), udev_get_dev_path(udev), "/.udev/db/", id, NULL);
-                        if (lstat(from, &stats) == 0) {
-                                if (!have_db) {
-                                        udev_device_read_db(device, from);
-                                        have_db = true;
-                                }
-                                unlink(from);
-                        }
-
-                        /* find old database with $subsys:$sysname name */
-                        util_strscpyl(from, sizeof(from), udev_get_dev_path(udev),
-                                     "/.udev/db/", udev_device_get_subsystem(device), ":",
-                                     udev_device_get_sysname(device), NULL);
-                        if (lstat(from, &stats) == 0) {
-                                if (!have_db) {
-                                        udev_device_read_db(device, from);
-                                        have_db = true;
-                                }
-                                unlink(from);
-                        }
-
-                        /* find old database with the encoded devpath name */
-                        util_path_encode(udev_device_get_devpath(device), devpath, sizeof(devpath));
-                        util_strscpyl(from, sizeof(from), udev_get_dev_path(udev), "/.udev/db/", devpath, NULL);
-                        if (lstat(from, &stats) == 0) {
-                                if (!have_db) {
-                                        udev_device_read_db(device, from);
-                                        have_db = true;
-                                }
-                                unlink(from);
-                        }
-
-                        /* write out new database */
-                        if (have_db)
-                                udev_device_update_db(device);
-                }
-                udev_device_unref(device);
-        }
-        udev_enumerate_unref(udev_enumerate);
-        return 0;
-}
-
-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;
-
-        info(udev, "ctrl=%i netlink=%i\n", ctrl, netlink);
-        *rctrl = ctrl;
-        *rnetlink = netlink;
-        return 0;
-}
-
-static bool check_rules_timestamp(struct udev *udev)
-{
-        char **p;
-        unsigned long long *stamp_usec;
-        int i, n;
-        bool changed = false;
-
-        n = udev_get_rules_path(udev, &p, &stamp_usec);
-        for (i = 0; i < n; i++) {
-                struct stat stats;
-
-                if (stat(p[i], &stats) < 0)
-                        continue;
-
-                if (stamp_usec[i] == ts_usec(&stats.st_mtim))
-                        continue;
-
-                /* first check */
-                if (stamp_usec[i] != 0) {
-                        info(udev, "reload - timestamp of '%s' changed\n", p[i]);
-                        changed = true;
-                }
-
-                /* update timestamp */
-                stamp_usec[i] = ts_usec(&stats.st_mtim);
-        }
-
-        return changed;
-}
-
-int main(int argc, char *argv[])
-{
-        struct udev *udev;
-        FILE *f;
-        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;
-        char **s;
-        int rc = 1;
-
-        udev = udev_new();
-        if (udev == NULL)
-                goto exit;
-
-        udev_log_init("udevd");
-        udev_set_log_fn(udev, udev_main_log);
-        info(udev, "version %s\n", VERSION);
-        udev_selinux_init(udev);
-
-        for (;;) {
-                int option;
-
-                option = getopt_long(argc, argv, "c:deDtN: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;
-                        if (udev_get_log_priority(udev) < LOG_INFO)
-                                udev_set_log_priority(udev, LOG_INFO);
-                        break;
-                case 'N':
-                        if (strcmp (optarg, "early") == 0) {
-                                resolve_names = 1;
-                        } else if (strcmp (optarg, "late") == 0) {
-                                resolve_names = 0;
-                        } else if (strcmp (optarg, "never") == 0) {
-                                resolve_names = -1;
-                        } else {
-                                fprintf(stderr, "resolve-names must be early, late or never\n");
-                                err(udev, "resolve-names must be early, late or never\n");
-                                goto exit;
-                        }
-                        break;
-                case 'h':
-                        printf("Usage: udevd OPTIONS\n"
-                               "  --daemon\n"
-                               "  --debug\n"
-                               "  --children-max=<maximum number of workers>\n"
-                               "  --exec-delay=<seconds to wait before executing RUN=>\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;
-                }
-        }
-
-        /*
-         * read the kernel commandline, in case we need to get into debug mode
-         *   udev.log-priority=<level>              syslog priority
-         *   udev.children-max=<number of workers>  events are fully serialized if set to 1
-         *
-         */
-        f = fopen("/proc/cmdline", "r");
-        if (f != NULL) {
-                char cmdline[4096];
-
-                if (fgets(cmdline, sizeof(cmdline), f) != NULL) {
-                        char *pos;
-
-                        pos = strstr(cmdline, "udev.log-priority=");
-                        if (pos != NULL) {
-                                pos += strlen("udev.log-priority=");
-                                udev_set_log_priority(udev, util_log_priority(pos));
-                        }
-
-                        pos = strstr(cmdline, "udev.children-max=");
-                        if (pos != NULL) {
-                                pos += strlen("udev.children-max=");
-                                children_max = strtoul(pos, NULL, 0);
-                        }
-
-                        pos = strstr(cmdline, "udev.exec-delay=");
-                        if (pos != NULL) {
-                                pos += strlen("udev.exec-delay=");
-                                exec_delay = strtoul(pos, NULL, 0);
-                        }
-                }
-                fclose(f);
-        }
-
-        if (getuid() != 0) {
-                fprintf(stderr, "root privileges required\n");
-                err(udev, "root privileges required\n");
-                goto exit;
-        }
-
-        /* set umask before creating any file/directory */
-        chdir("/");
-        umask(022);
-
-        /* /run/udev */
-        mkdir(udev_get_run_path(udev), 0755);
-
-        /* create standard links, copy static nodes, create nodes from modules */
-        static_dev_create(udev);
-        static_dev_create_from_modules(udev);
-
-        /* 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");
-                        err(udev, "cannot open /dev/null\n");
-                }
-        }
-
-        if (systemd_fds(udev, &fd_ctrl, &fd_netlink) >= 0) {
-                /* get control and netlink socket from from systemd */
-                udev_ctrl = udev_ctrl_new_from_fd(udev, fd_ctrl);
-                if (udev_ctrl == NULL) {
-                        err(udev, "error taking over udev control socket");
-                        rc = 1;
-                        goto exit;
-                }
-
-                monitor = udev_monitor_new_from_netlink_fd(udev, "kernel", fd_netlink);
-                if (monitor == NULL) {
-                        err(udev, "error taking over netlink socket\n");
-                        rc = 3;
-                        goto exit;
-                }
-        } else {
-                /* open control and netlink socket */
-                udev_ctrl = udev_ctrl_new(udev);
-                if (udev_ctrl == NULL) {
-                        fprintf(stderr, "error initializing udev control socket");
-                        err(udev, "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");
-                        err(udev, "error initializing netlink socket\n");
-                        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");
-                err(udev, "error binding netlink socket\n");
-                rc = 3;
-                goto exit;
-        }
-
-        if (udev_ctrl_enable_receiving(udev_ctrl) < 0) {
-                fprintf(stderr, "error binding udev control socket\n");
-                err(udev, "error binding udev control socket\n");
-                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) {
-                err(udev, "error creating queue file\n");
-                goto exit;
-        }
-
-        if (daemonize) {
-                pid_t pid;
-                int fd;
-
-                pid = fork();
-                switch (pid) {
-                case 0:
-                        break;
-                case -1:
-                        err(udev, "fork of daemon failed: %m\n");
-                        rc = 4;
-                        goto exit;
-                default:
-                        rc = EXIT_SUCCESS;
-                        goto exit_daemonize;
-                }
-
-                setsid();
-
-                fd = open("/proc/self/oom_score_adj", O_RDWR);
-                if (fd < 0) {
-                        /* Fallback to old interface */
-                        fd = open("/proc/self/oom_adj", O_RDWR);
-                        if (fd < 0) {
-                                err(udev, "error disabling OOM: %m\n");
-                        } else {
-                                /* OOM_DISABLE == -17 */
-                                write(fd, "-17", 3);
-                                close(fd);
-                        }
-                } else {
-                        write(fd, "-1000", 5);
-                        close(fd);
-                }
-        } else {
-                sd_notify(1, "READY=1");
-        }
-
-        f = fopen("/dev/kmsg", "w");
-        if (f != NULL) {
-                fprintf(f, "<30>udevd[%u]: starting version " VERSION "\n", getpid());
-                fclose(f);
-        }
-
-        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");
-                err(udev, "error initializing inotify\n");
-                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");
-                err(udev, "error creating signalfd\n");
-                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");
-                err(udev, "error creating socketpair\n");
-                rc = 6;
-                goto exit;
-        }
-        fd_worker = worker_watch[READ_END];
-
-        udev_builtin_init(udev);
-
-        rules = udev_rules_new(udev, resolve_names);
-        if (rules == NULL) {
-                err(udev, "error reading rules\n");
-                goto exit;
-        }
-
-        memset(&ep_ctrl, 0, sizeof(struct epoll_event));
-        ep_ctrl.events = EPOLLIN;
-        ep_ctrl.data.fd = fd_ctrl;
-
-        memset(&ep_inotify, 0, sizeof(struct epoll_event));
-        ep_inotify.events = EPOLLIN;
-        ep_inotify.data.fd = fd_inotify;
-
-        memset(&ep_signal, 0, sizeof(struct epoll_event));
-        ep_signal.events = EPOLLIN;
-        ep_signal.data.fd = fd_signal;
-
-        memset(&ep_netlink, 0, sizeof(struct epoll_event));
-        ep_netlink.events = EPOLLIN;
-        ep_netlink.data.fd = fd_netlink;
-
-        memset(&ep_worker, 0, sizeof(struct epoll_event));
-        ep_worker.events = EPOLLIN;
-        ep_worker.data.fd = fd_worker;
-
-        fd_ep = epoll_create1(EPOLL_CLOEXEC);
-        if (fd_ep < 0) {
-                err(udev, "error creating epoll fd: %m\n");
-                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) {
-                err(udev, "fail to add fds to epoll: %m\n");
-                goto exit;
-        }
-
-        /* if needed, convert old database from earlier udev version */
-        convert_db(udev);
-
-        if (children_max <= 0) {
-                int memsize = mem_size_mb();
-
-                /* set value depending on the amount of RAM */
-                if (memsize > 0)
-                        children_max = 128 + (memsize / 8);
-                else
-                        children_max = 128;
-        }
-        info(udev, "set children_max to %u\n", children_max);
-
-        udev_rules_apply_static_dev_perms(rules);
-
-        udev_list_node_init(&event_list);
-        udev_list_node_init(&worker_list);
-
-        for (;;) {
-                static unsigned long long 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, 0);
-
-                        /* 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 <= 2) {
-                        /* we are idle */
-                        timeout = -1;
-                } else {
-                        /* kill idle or hanging workers */
-                        timeout = 3 * 1000;
-                }
-                fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), timeout);
-                if (fdcount < 0)
-                        continue;
-
-                if (fdcount == 0) {
-                        struct udev_list_node *loop;
-
-                        /* timeout */
-                        if (udev_exit) {
-                                err(udev, "timeout, giving up waiting for workers to finish\n");
-                                break;
-                        }
-
-                        /* kill idle workers */
-                        if (udev_list_node_is_empty(&event_list)) {
-                                info(udev, "cleanup idle workers\n");
-                                worker_kill(udev, 2);
-                        }
-
-                        /* 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_usec() - worker->event_start_usec) > 30 * 1000 * 1000) {
-                                        err(udev, "worker [%u] timeout, kill it\n", worker->pid,
-                                            worker->event ? worker->event->devpath : "<idle>");
-                                        kill(worker->pid, SIGKILL);
-                                        worker->state = WORKER_KILLED;
-                                        /* drop reference taken for state 'running' */
-                                        worker_unref(worker);
-                                        if (worker->event) {
-                                                err(udev, "seq %llu '%s' killed\n",
-                                                    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_usec() - last_usec) > 3 * 1000 * 1000) {
-                        if (check_rules_timestamp(udev))
-                                reload = true;
-                        if (udev_builtin_validate(udev))
-                                reload = true;
-
-                        last_usec = now_usec();
-                }
-
-                /* reload requested, HUP signal received, rules changed, builtin changed */
-                if (reload) {
-                        worker_kill(udev, 0);
-                        rules = udev_rules_unref(rules);
-                        udev_builtin_exit(udev);
-                        reload = 0;
-                }
-
-                /* 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_usec());
-                                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) {
-                        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);
-        udev_selinux_exit(udev);
-        udev_unref(udev);
-        udev_log_close();
-        return rc;
-}
diff --git a/src/udev/src/udevd.xml b/src/udev/src/udevd.xml
deleted file mode 100644 (file)
index c516eb9..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-<?xml version='1.0'?>
-<?xml-stylesheet type="text/xsl" href="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl"?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<refentry id="udevd">
-  <refentryinfo>
-    <title>udevd</title>
-    <productname>udev</productname>
-  </refentryinfo>
-
-  <refmeta>
-    <refentrytitle>udevd</refentrytitle>
-    <manvolnum>8</manvolnum>
-    <refmiscinfo class="version"></refmiscinfo>
-  </refmeta>
-
-  <refnamediv>
-    <refname>udevd</refname><refpurpose>event managing daemon</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <cmdsynopsis>
-      <command>udevd</command>
-      <arg><option>--daemon</option></arg>
-      <arg><option>--debug</option></arg>
-      <arg><option>--children-max=</option></arg>
-      <arg><option>--exec-delay=</option></arg>
-      <arg><option>--resolve-names=early|late|never</option></arg>
-      <arg><option>--version</option></arg>
-      <arg><option>--help</option></arg>
-    </cmdsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1><title>Description</title>
-    <para>udevd listens to kernel uevents. For every event, udevd executes matching
-    instructions specified in udev rules. See <citerefentry>
-        <refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum>
-      </citerefentry>.</para>
-    <para>On startup the content of the directory <filename>/usr/lib/udev/devices</filename>
-    is copied to <filename>/dev</filename>. If kernel modules specify static device
-    nodes, these nodes are created even without a corresponding kernel device, to
-    allow on-demand loading of kernel modules. Matching permissions specified in udev
-    rules are applied to these static device nodes.</para>
-    <para>The behavior of the running daemon can be changed with
-    <command>udevadm control</command>.</para>
-  </refsect1>
-
-  <refsect1><title>Options</title>
-    <variablelist>
-      <varlistentry>
-        <term><option>--daemon</option></term>
-        <listitem>
-          <para>Detach and run in the background.</para>
-        </listitem>
-      </varlistentry>
-      <varlistentry>
-        <term><option>--debug</option></term>
-        <listitem>
-          <para>Print debug messages to stderr.</para>
-        </listitem>
-      </varlistentry>
-      <varlistentry>
-        <term><option>--children-max=</option></term>
-        <listitem>
-          <para>Limit the number of parallel executed events.</para>
-        </listitem>
-      </varlistentry>
-      <varlistentry>
-        <term><option>--exec-delay=</option></term>
-        <listitem>
-          <para>Number of seconds to delay the execution of RUN instructions.
-          This might be useful when debugging system crashes during coldplug
-          cause by loading non-working kernel modules.</para>
-        </listitem>
-      </varlistentry>
-      <varlistentry>
-        <term><option>--resolve-names=</option></term>
-        <listitem>
-          <para>Specify when udevd should resolve names of users and groups.
-          When set to <option>early</option> (the default) names will be
-          resolved when the rules are parsed.  When set to
-          <option>late</option> names will be resolved for every event.
-          When set to <option>never</option> names will never be resolved
-          and all devices will be owned by root.</para>
-        </listitem>
-      </varlistentry>
-      <varlistentry>
-        <term><option>--version</option></term>
-        <listitem>
-          <para>Print version number.</para>
-        </listitem>
-      </varlistentry>
-      <varlistentry>
-        <term><option>--help</option></term>
-        <listitem>
-          <para>Print help text.</para>
-        </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1><title>Environment</title>
-    <variablelist>
-      <varlistentry>
-        <term><varname>UDEV_LOG=</varname></term>
-        <listitem>
-          <para>Set the logging priority.</para>
-        </listitem>
-      </varlistentry>
-    </variablelist>
- </refsect1>
-
-  <refsect1><title>Kernel command line</title>
-    <variablelist>
-      <varlistentry>
-        <term><varname>udev.log-priority=</varname></term>
-        <listitem>
-          <para>Set the logging priority.</para>
-        </listitem>
-      </varlistentry>
-      <varlistentry>
-        <term><varname>udev.children-max=</varname></term>
-        <listitem>
-          <para>Limit the number of parallel executed events.</para>
-        </listitem>
-      </varlistentry>
-      <varlistentry>
-        <term><varname>udev.exec-delay=</varname></term>
-        <listitem>
-          <para>Number of seconds to delay the execution of RUN instructions.
-          This might be useful when debugging system crashes during coldplug
-          cause by loading non-working kernel modules.</para>
-        </listitem>
-      </varlistentry>
-    </variablelist>
- </refsect1>
-
-  <refsect1><title>Author</title>
-    <para>Written by Kay Sievers <email>kay.sievers@vrfy.org</email>.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>See Also</title>
-    <para><citerefentry>
-        <refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum>
-      </citerefentry>, <citerefentry>
-        <refentrytitle>udevadm</refentrytitle><manvolnum>8</manvolnum>
-    </citerefentry></para>
-  </refsect1>
-</refentry>
diff --git a/src/udev/src/v4l_id/60-persistent-v4l.rules b/src/udev/src/v4l_id/60-persistent-v4l.rules
deleted file mode 100644 (file)
index 93c5ee8..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-# 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"
-
-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/src/udev/src/v4l_id/v4l_id.c b/src/udev/src/v4l_id/v4l_id.c
deleted file mode 100644 (file)
index a2a80b5..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2009 Kay Sievers <kay.sievers@vrfy.org>
- * Copyright (c) 2009 Filippo Argiolas <filippo.argiolas@gmail.com>
- *
- * 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 <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/ioctl.h>
-#include <linux/videodev2.h>
-
-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] <device file>\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/udev/test-libudev.c b/src/udev/test-libudev.c
new file mode 100644 (file)
index 0000000..6161fb3
--- /dev/null
@@ -0,0 +1,501 @@
+/*
+ * test-libudev
+ *
+ * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.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.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <getopt.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/epoll.h>
+
+#include "libudev.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[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)
+{
+        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);
+        udev_device_unref(device);
+        return 0;
+}
+
+static int test_device_parents(struct udev *udev, const char *syspath)
+{
+        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);
+        udev_device_unref(device);
+
+        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;
+        }
+
+        memset(&ep_udev, 0, 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;
+        }
+
+        memset(&ep_stdin, 0, 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 ? "<all>" : subsystem);
+        udev_enumerate = udev_enumerate_new(udev);
+        if (udev_enumerate == NULL)
+                return -1;
+        udev_enumerate_add_match_subsystem(udev_enumerate, subsystem);
+        udev_enumerate_scan_devices(udev_enumerate);
+        test_enumerate_print_list(udev_enumerate);
+        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;
+}
+
+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];
+        const char *str;
+
+        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;
+                }
+        }
+
+        str = udev_get_sys_path(udev);
+        printf("sys_path: '%s'\n", str);
+        str = udev_get_dev_path(udev);
+        printf("dev_path: '%s'\n", str);
+
+        /* add sys path if needed */
+        if (strncmp(syspath, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0) {
+                snprintf(path, sizeof(path), "%s%s", udev_get_sys_path(udev), 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_monitor(udev);
+out:
+        udev_unref(udev);
+        return 0;
+}
diff --git a/src/udev/test-udev.c b/src/udev/test-udev.c
new file mode 100644 (file)
index 0000000..c9712e9
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2003-2004 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2004-2008 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <grp.h>
+#include <sys/signalfd.h>
+
+#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) {}
+
+int main(int argc, char *argv[])
+{
+        struct udev *udev;
+        struct udev_event *event = NULL;
+        struct udev_device *dev = NULL;
+        struct udev_rules *rules = NULL;
+        char syspath[UTIL_PATH_SIZE];
+        const char *devpath;
+        const char *action;
+        sigset_t mask, sigmask_orig;
+        int err = -EINVAL;
+
+        udev = udev_new();
+        if (udev == NULL)
+                exit(1);
+        info(udev, "version %s\n", VERSION);
+        udev_selinux_init(udev);
+
+        sigprocmask(SIG_SETMASK, NULL, &sigmask_orig);
+
+        action = argv[1];
+        if (action == NULL) {
+                err(udev, "action missing\n");
+                goto out;
+        }
+
+        devpath = argv[2];
+        if (devpath == NULL) {
+                err(udev, "devpath missing\n");
+                goto out;
+        }
+
+        rules = udev_rules_new(udev, 1);
+
+        util_strscpyl(syspath, sizeof(syspath), udev_get_sys_path(udev), devpath, NULL);
+        dev = udev_device_new_from_syspath(udev, syspath);
+        if (dev == NULL) {
+                info(udev, "unknown device '%s'\n", 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;
+
+                if (strcmp(udev_device_get_subsystem(dev), "block") == 0)
+                        mode |= S_IFBLK;
+                else
+                        mode |= S_IFCHR;
+
+                if (strcmp(action, "remove") != 0) {
+                        util_create_path(udev, udev_device_get_devnode(dev));
+                        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);
+        udev_event_unref(event);
+        udev_device_unref(dev);
+        udev_rules_unref(rules);
+        udev_selinux_exit(udev);
+        udev_unref(udev);
+        if (err != 0)
+                return 1;
+        return 0;
+}
index 1e224ff8b59974ce562a7bb74a7f99b5c0be5871..5b3acea31fbdec91ede6e4590789229a1229fe6c 100755 (executable)
@@ -12,4 +12,4 @@ type python >/dev/null 2>&1 || {
         exit 0
 }
 
-$srcdir/test/rule-syntax-check.py `find $srcdir/rules -name '*.rules'`
+$srcdir/src/udev/test/rule-syntax-check.py `find $srcdir/rules -name '*.rules'`
diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c
new file mode 100644 (file)
index 0000000..e57f03e
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * probe disks for filesystems and partitions
+ *
+ * Copyright (C) 2011 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <sys/stat.h>
+#include <blkid/blkid.h>
+
+#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 (!strcmp(name, "TYPE")) {
+                udev_builtin_add_property(dev, test, "ID_FS_TYPE", value);
+
+        } else if (!strcmp(name, "USAGE")) {
+                udev_builtin_add_property(dev, test, "ID_FS_USAGE", value);
+
+        } else if (!strcmp(name, "VERSION")) {
+                udev_builtin_add_property(dev, test, "ID_FS_VERSION", value);
+
+        } else if (!strcmp(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 (!strcmp(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 (!strcmp(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 (!strcmp(name, "PTTYPE")) {
+                udev_builtin_add_property(dev, test, "ID_PART_TABLE_TYPE", value);
+
+        } else if (!strcmp(name, "PART_ENTRY_NAME")) {
+                blkid_encode_string(value, s, sizeof(s));
+                udev_builtin_add_property(dev, test, "ID_PART_ENTRY_NAME", s);
+
+        } else if (!strcmp(name, "PART_ENTRY_TYPE")) {
+                blkid_encode_string(value, s, sizeof(s));
+                udev_builtin_add_property(dev, test, "ID_PART_ENTRY_TYPE", s);
+
+        } else if (!strncmp(name, "PART_ENTRY_", 11)) {
+                util_strscpyl(s, sizeof(s), "ID_", name, NULL);
+                udev_builtin_add_property(dev, test, s, value);
+        }
+}
+
+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)
+{
+        struct udev *udev = udev_device_get_udev(dev);
+        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) {
+                err = -ENOMEM;
+                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;
+
+        info(udev, "probe %s %sraid offset=%llu\n",
+             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-firmware.c b/src/udev/udev-builtin-firmware.c
new file mode 100644 (file)
index 0000000..d212c64
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * firmware - Kernel firmware loader
+ *
+ * Copyright (C) 2009 Piter Punk <piterpunk@slackware.com>
+ * Copyright (C) 2009-2011 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/utsname.h>
+#include <sys/stat.h>
+
+#include "udev.h"
+
+static bool set_loading(struct udev *udev, char *loadpath, const char *state)
+{
+        FILE *ldfile;
+
+        ldfile = fopen(loadpath, "we");
+        if (ldfile == NULL) {
+                err(udev, "error: can not open '%s'\n", 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) {
+                err(udev,"No memory available to load firmware file");
+                return false;
+        }
+
+        info(udev, "writing '%s' (%zi) to '%s'\n", 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;
+}
+
+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 fwencpath[UTIL_PATH_SIZE];
+        char misspath[UTIL_PATH_SIZE];
+        char loadpath[UTIL_PATH_SIZE];
+        char datapath[UTIL_PATH_SIZE];
+        char fwpath[UTIL_PATH_SIZE];
+        const char *firmware;
+        FILE *fwfile;
+        struct utsname kernel;
+        struct stat statbuf;
+        unsigned int i;
+        int rc = EXIT_SUCCESS;
+
+        firmware = udev_device_get_property_value(dev, "FIRMWARE");
+        if (firmware == NULL) {
+                err(udev, "firmware parameter missing\n\n");
+                rc = EXIT_FAILURE;
+                goto exit;
+        }
+
+        /* lookup firmware file */
+        uname(&kernel);
+        for (i = 0; i < ARRAY_SIZE(searchpath); i++) {
+                util_strscpyl(fwpath, sizeof(fwpath), searchpath[i], kernel.release, "/", firmware, NULL);
+                dbg(udev, "trying %s\n", fwpath);
+                fwfile = fopen(fwpath, "re");
+                if (fwfile != NULL)
+                        break;
+
+                util_strscpyl(fwpath, sizeof(fwpath), searchpath[i], firmware, NULL);
+                dbg(udev, "trying %s\n", fwpath);
+                fwfile = fopen(fwpath, "re");
+                if (fwfile != NULL)
+                        break;
+        }
+
+        util_path_encode(firmware, fwencpath, sizeof(fwencpath));
+        util_strscpyl(misspath, sizeof(misspath), udev_get_run_path(udev), "/firmware-missing/", fwencpath, NULL);
+        util_strscpyl(loadpath, sizeof(loadpath), udev_device_get_syspath(dev), "/loading", NULL);
+
+        if (fwfile == NULL) {
+                int err;
+
+                /* This link indicates the missing firmware file and the associated device */
+                info(udev, "did not find firmware file '%s'\n", firmware);
+                do {
+                        err = util_create_path(udev, misspath);
+                        if (err != 0 && err != -ENOENT)
+                                break;
+                        err = symlink(udev_device_get_devpath(dev), misspath);
+                        if (err != 0)
+                                err = -errno;
+                } while (err == -ENOENT);
+                rc = EXIT_FAILURE;
+                set_loading(udev, loadpath, "-1");
+                goto exit;
+        }
+
+        if (stat(fwpath, &statbuf) < 0 || statbuf.st_size == 0) {
+                rc = EXIT_FAILURE;
+                goto exit;
+        }
+        if (unlink(misspath) == 0)
+                util_delete_path(udev, misspath);
+
+        if (!set_loading(udev, loadpath, "1"))
+                goto exit;
+
+        util_strscpyl(datapath, sizeof(datapath), udev_device_get_syspath(dev), "/data", NULL);
+        if (!copy_firmware(udev, fwpath, datapath, statbuf.st_size)) {
+                err(udev, "error sending firmware '%s' to device\n", 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 (file)
index 0000000..aa996f3
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * usb-db, pci-db - lookup vendor/product database
+ *
+ * Copyright (C) 2009 Lennart Poettering <lennart@poettering.net>
+ * Copyright (C) 2011 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <inttypes.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "udev.h"
+
+static int get_id_attr(
+        struct udev_device *parent,
+        const char *name,
+        uint16_t *value) {
+
+        const char *t;
+        unsigned u;
+
+        if (!(t = udev_device_get_sysattr_value(parent, name))) {
+                fprintf(stderr, "%s lacks %s.\n", udev_device_get_syspath(parent), name);
+                return -1;
+        }
+
+        if (!strncmp(t, "0x", 2))
+                t += 2;
+
+        if (sscanf(t, "%04x", &u) != 1 || u > 0xFFFFU) {
+                fprintf(stderr, "Failed to parse %s on %s.\n", name, udev_device_get_syspath(parent));
+                return -1;
+        }
+
+        *value = (uint16_t) u;
+        return 0;
+}
+
+static int get_vid_pid(
+        struct udev_device *parent,
+        const char *vendor_attr,
+        const char *product_attr,
+        uint16_t *vid,
+        uint16_t *pid) {
+
+        if (get_id_attr(parent, vendor_attr, vid) < 0)
+                return -1;
+        else if (*vid <= 0) {
+                fprintf(stderr, "Invalid vendor id.\n");
+                return -1;
+        }
+
+        if (get_id_attr(parent, product_attr, pid) < 0)
+                return -1;
+
+        return 0;
+}
+
+static void rstrip(char *n) {
+        size_t i;
+
+        for (i = strlen(n); i > 0 && isspace(n[i-1]); i--)
+                n[i-1] = 0;
+}
+
+#define HEXCHARS "0123456789abcdefABCDEF"
+#define WHITESPACE " \t\n\r"
+static int lookup_vid_pid(const char *database,
+                          uint16_t vid, uint16_t pid,
+                          char **vendor, char **product)
+{
+
+        FILE *f;
+        int ret = -1;
+        int found_vendor = 0;
+        char *line = NULL;
+
+        *vendor = *product = NULL;
+
+        if (!(f = fopen(database, "rme"))) {
+                fprintf(stderr, "Failed to open database file '%s': %s\n", database, strerror(errno));
+                return -1;
+        }
+
+        for (;;) {
+                size_t n;
+
+                if (getline(&line, &n, f) < 0)
+                        break;
+
+                rstrip(line);
+
+                if (line[0] == '#' || line[0] == 0)
+                        continue;
+
+                if (strspn(line, HEXCHARS) == 4) {
+                        unsigned u;
+
+                        if (found_vendor)
+                                break;
+
+                        if (sscanf(line, "%04x", &u) == 1 && u == vid) {
+                                char *t;
+
+                                t = line+4;
+                                t += strspn(t, WHITESPACE);
+
+                                if (!(*vendor = strdup(t))) {
+                                        fprintf(stderr, "Out of memory.\n");
+                                        goto finish;
+                                }
+
+                                found_vendor = 1;
+                        }
+
+                        continue;
+                }
+
+                if (found_vendor && line[0] == '\t' && strspn(line+1, HEXCHARS) == 4) {
+                        unsigned u;
+
+                        if (sscanf(line+1, "%04x", &u) == 1 && u == pid) {
+                                char *t;
+
+                                t = line+5;
+                                t += strspn(t, WHITESPACE);
+
+                                if (!(*product = strdup(t))) {
+                                        fprintf(stderr, "Out of memory.\n");
+                                        goto finish;
+                                }
+
+                                break;
+                        }
+                }
+        }
+
+        ret = 0;
+
+finish:
+        free(line);
+        fclose(f);
+
+        if (ret < 0) {
+                free(*product);
+                free(*vendor);
+
+                *product = *vendor = NULL;
+        }
+
+        return ret;
+}
+
+static struct udev_device *find_device(struct udev_device *dev, const char *subsys, const char *devtype)
+{
+        const char *str;
+
+        str = udev_device_get_subsystem(dev);
+        if (str == NULL)
+                goto try_parent;
+        if (strcmp(str, subsys) != 0)
+                goto try_parent;
+
+        if (devtype != NULL) {
+                str = udev_device_get_devtype(dev);
+                if (str == NULL)
+                        goto try_parent;
+                if (strcmp(str, devtype) != 0)
+                        goto try_parent;
+        }
+        return dev;
+try_parent:
+        return udev_device_get_parent_with_subsystem_devtype(dev, subsys, devtype);
+}
+
+
+static int builtin_db(struct udev_device *dev, bool test,
+                      const char *database,
+                      const char *vendor_attr, const char *product_attr,
+                      const char *subsys, const char *devtype)
+{
+        struct udev_device *parent;
+        uint16_t vid = 0, pid = 0;
+        char *vendor = NULL, *product = NULL;
+
+        parent = find_device(dev, subsys, devtype);
+        if (!parent) {
+                fprintf(stderr, "Failed to find device.\n");
+                goto finish;
+        }
+
+        if (get_vid_pid(parent, vendor_attr, product_attr, &vid, &pid) < 0)
+                goto finish;
+
+        if (lookup_vid_pid(database, vid, pid, &vendor, &product) < 0)
+                goto finish;
+
+        if (vendor)
+                udev_builtin_add_property(dev, test, "ID_VENDOR_FROM_DATABASE", vendor);
+        if (product)
+                udev_builtin_add_property(dev, test, "ID_MODEL_FROM_DATABASE", product);
+
+finish:
+        free(vendor);
+        free(product);
+        return 0;
+}
+
+static int builtin_usb_db(struct udev_device *dev, int argc, char *argv[], bool test)
+{
+        return builtin_db(dev, test, USB_DATABASE, "idVendor", "idProduct", "usb", "usb_device");
+}
+
+static int builtin_pci_db(struct udev_device *dev, int argc, char *argv[], bool test)
+{
+        return builtin_db(dev, test, PCI_DATABASE, "vendor", "device", "pci", NULL);
+}
+
+const struct udev_builtin udev_builtin_usb_db = {
+        .name = "usb-db",
+        .cmd = builtin_usb_db,
+        .help = "USB vendor/product database",
+        .run_once = true,
+};
+
+const struct udev_builtin udev_builtin_pci_db = {
+        .name = "pci-db",
+        .cmd = builtin_pci_db,
+        .help = "PCI vendor/product database",
+        .run_once = true,
+};
diff --git a/src/udev/udev-builtin-input_id.c b/src/udev/udev-builtin-input_id.c
new file mode 100644 (file)
index 0000000..a062ef7
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * compose persistent device path
+ *
+ * Copyright (C) 2009 Martin Pitt <martin.pitt@ubuntu.com>
+ * Portions Copyright (C) 2004 David Zeuthen, <david@fubar.dk>
+ * Copyright (C) 2011 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <linux/limits.h>
+#include <linux/input.h>
+
+#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(x))
+#define LONG(x) ((x)/BITS_PER_LONG)
+#define test_bit(bit, array)    ((array[LONG(bit)] >> 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)
+{
+        struct udev *udev = udev_device_get_udev(dev);
+        char text[4096];
+        unsigned i;
+        char* word;
+        unsigned long val;
+
+        snprintf(text, sizeof(text), "%s", udev_device_get_sysattr_value(pdev, attr));
+        info(udev, "%s raw kernel attribute: %s\n", attr, text);
+
+        memset (bitmask, 0, 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
+                        info(udev, "ignoring %s block %lX which is larger than maximum size\n", attr, val);
+                *word = '\0';
+                ++i;
+        }
+        val = strtoul (text, NULL, 16);
+        if (i < bitmask_size / sizeof(unsigned long))
+                bitmask[i] = val;
+        else
+                info(udev, "ignoring %s block %lX which is larger than maximum size\n", 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));
+                info(udev, "%s decoded bit map:\n", 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)
+                        info(udev, text, i * BITS_PER_LONG, bitmask[i]);
+        }
+}
+
+/* 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)
+{
+        struct udev *udev = udev_device_get_udev(dev);
+        unsigned i;
+        unsigned long found;
+        unsigned long mask;
+
+        /* do we have any KEY_* capability? */
+        if (!test_bit (EV_KEY, bitmask_ev)) {
+                info(udev, "test_key: no EV_KEY capability\n");
+                return;
+        }
+
+        /* only consider KEY_* here, not BTN_* */
+        found = 0;
+        for (i = 0; i < BTN_MISC/BITS_PER_LONG; ++i) {
+                found |= bitmask_key[i];
+                info(udev, "test_key: checking bit block %lu for any keys; found=%i\n", 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)) {
+                                info(udev, "test_key: Found key %x in high block\n", 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-kmod.c b/src/udev/udev-builtin-kmod.c
new file mode 100644 (file)
index 0000000..57e813f
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * load kernel modules
+ *
+ * Copyright (C) 2011 Kay Sievers <kay.sievers@vrfy.org>
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <libkmod.h>
+
+#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)
+                info(udev, "no module matches '%s'\n", 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)
+                        info(udev, "module '%s' is blacklisted\n", kmod_module_get_name(mod));
+                else if (err == 0)
+                        info(udev, "inserted '%s'\n", kmod_module_get_name(mod));
+                else
+                        info(udev, "failed to insert '%s'\n", kmod_module_get_name(mod));
+
+                kmod_module_unref(mod);
+        }
+
+        kmod_module_unref_list(list);
+        return err;
+}
+
+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);
+}
+
+/* needs to re-instantiate the context after a reload */
+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) {
+                ctx = kmod_new(NULL, NULL);
+                if (!ctx)
+                        return -ENOMEM;
+
+                info(udev, "load module index\n");
+                kmod_set_log_fn(ctx, udev_kmod_log, udev);
+                kmod_load_resources(ctx);
+        }
+
+        if (argc < 3 || strcmp(argv[1], "load")) {
+                err(udev, "expect: %s load <module>\n", argv[0]);
+                return EXIT_FAILURE;
+        }
+
+        for (i = 2; argv[i]; i++) {
+                info(udev, "execute '%s' '%s'\n", argv[1], argv[i]);
+                load_module(udev, argv[i]);
+        }
+
+        return EXIT_SUCCESS;
+}
+
+/* called at udev startup */
+static int builtin_kmod_init(struct udev *udev)
+{
+        if (ctx)
+                return 0;
+
+        ctx = kmod_new(NULL, NULL);
+        if (!ctx)
+                return -ENOMEM;
+
+        info(udev, "load module index\n");
+        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)
+{
+        info(udev, "unload module index\n");
+        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)
+{
+        info(udev, "validate module index\n");
+        if (kmod_validate_resources(ctx) != KMOD_RESOURCES_OK)
+                return true;
+        return false;
+}
+
+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-path_id.c b/src/udev/udev-builtin-path_id.c
new file mode 100644 (file)
index 0000000..a8559d2
--- /dev/null
@@ -0,0 +1,498 @@
+/*
+ * compose persistent device path
+ *
+ * Copyright (C) 2009-2011 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <dirent.h>
+#include <getopt.h>
+
+#include "udev.h"
+
+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-%d", lun);
+        /* handle all other lun addressing methods by using a variant of the original lun format */
+        return path_prepend(path, "lun-0x%04x%04x00000000", (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 || strcmp(subsystem, subsys) != 0)
+                        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 (strncmp(udev_device_get_sysname(transportdev), "session", 7) == 0)
+                        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 */
+        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 (strncmp(dent->d_name, "host", 4) != 0)
+                        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(struct udev_device *parent, char **path)
+{
+        const char *devtype;
+        const char *name;
+        const char *id;
+
+        devtype = udev_device_get_devtype(parent);
+        if (devtype == NULL || strcmp(devtype, "scsi_device") != 0)
+                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;
+        }
+
+        /* lousy 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 creates duplicated link
+         * names as the fake SCSI host adapters are all separated, they are all
+         * re-based as host == 0. ATA should just stop faking two duplicated
+         * hierarchies for a single topology and leave the SCSI stuff alone;
+         * until that happens, there are no by-path/ links for ATA devices behind
+         * an ATA transport class.
+         */
+        if (strstr(name, "/ata") != NULL) {
+                parent = NULL;
+                goto out;
+        }
+
+        parent = handle_scsi_default(parent, path);
+out:
+        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 (strncmp(name, "nst", 3) == 0 && strchr("lma", name[3]) != NULL)
+                path_prepend(path, "nst%c", name[3]);
+        else if (strncmp(name, "st", 2) == 0 && 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 (strcmp(devtype, "usb_interface") != 0 && strcmp(devtype, "usb_device") != 0)
+                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_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;
+
+        /* 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 (strcmp(subsys, "scsi_tape") == 0) {
+                        handle_scsi_tape(parent, &path);
+                } else if (strcmp(subsys, "scsi") == 0) {
+                        parent = handle_scsi(parent, &path);
+                } else if (strcmp(subsys, "usb") == 0) {
+                        parent = handle_usb(parent, &path);
+                } else if (strcmp(subsys, "serio") == 0) {
+                        path_prepend(&path, "serio-%s", udev_device_get_sysnum(parent));
+                        parent = skip_subsystem(parent, "serio");
+                } else if (strcmp(subsys, "pci") == 0) {
+                        path_prepend(&path, "pci-%s", udev_device_get_sysname(parent));
+                        parent = skip_subsystem(parent, "pci");
+                } else if (strcmp(subsys, "platform") == 0) {
+                        path_prepend(&path, "platform-%s", udev_device_get_sysname(parent));
+                        parent = skip_subsystem(parent, "platform");
+                } else if (strcmp(subsys, "acpi") == 0) {
+                        path_prepend(&path, "acpi-%s", udev_device_get_sysname(parent));
+                        parent = skip_subsystem(parent, "acpi");
+                } else if (strcmp(subsys, "xen") == 0) {
+                        path_prepend(&path, "xen-%s", udev_device_get_sysname(parent));
+                        parent = skip_subsystem(parent, "xen");
+                } else if (strcmp(subsys, "virtio") == 0) {
+                        path_prepend(&path, "virtio-pci-%s", udev_device_get_sysname(parent));
+                        parent = skip_subsystem(parent, "virtio");
+                }
+
+                parent = udev_device_get_parent(parent);
+        }
+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-usb_id.c b/src/udev/udev-builtin-usb_id.c
new file mode 100644 (file)
index 0000000..85828e3
--- /dev/null
@@ -0,0 +1,482 @@
+/*
+ * USB device properties and persistent device path
+ *
+ * Copyright (c) 2005 SUSE Linux Products GmbH, Germany
+ *   Author: Hannes Reinecke <hare@suse.de>
+ *
+ * Copyright (C) 2005-2011 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "udev.h"
+
+static void set_usb_iftype(char *to, int if_class_num, size_t len)
+{
+        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;
+        char *type = "generic";
+
+        type_num = strtoul(from, &eptr, 0);
+        if (eptr != from) {
+                switch (type_num) {
+                case 2:
+                        type = "atapi";
+                        break;
+                case 3:
+                        type = "tape";
+                        break;
+                case 4: /* UFI */
+                case 5: /* SFF-8070i */
+                        type = "floppy";
+                        break;
+                case 1: /* RBC devices */
+                        type = "rbc";
+                        break;
+                case 6: /* Transparent SPC-2 devices */
+                        type = "scsi";
+                        break;
+                default:
+                        break;
+                }
+        }
+        util_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;
+        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;
+                }
+        }
+        util_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)
+{
+        char *filename = NULL;
+        int fd;
+        ssize_t size;
+        unsigned char buf[18 + 65535];
+        unsigned int pos, strpos;
+        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));
+        int err = 0;
+
+        if (asprintf(&filename, "%s/descriptors", udev_device_get_syspath(dev)) < 0) {
+                err = -1;
+                goto out;
+        }
+        fd = open(filename, O_RDONLY|O_CLOEXEC);
+        if (fd < 0) {
+                fprintf(stderr, "error opening USB device 'descriptors' file\n");
+                err = -1;
+                goto out;
+        }
+        size = read(fd, buf, sizeof(buf));
+        close(fd);
+        if (size < 18 || size == sizeof(buf)) {
+                err = -1;
+                goto out;
+        }
+
+        pos = 0;
+        strpos = 0;
+        ifs_str[0] = '\0';
+        while (pos < sizeof(buf) && 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';
+        }
+out:
+        free(filename);
+        return err;
+}
+
+/*
+ * 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 *udev = udev_device_get_udev(dev);
+        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';
+
+        dbg(udev, "syspath %s\n", udev_device_get_syspath(dev));
+
+        /* shortcut, if we are called directly for a "usb_device" type */
+        if (udev_device_get_devtype(dev) != NULL && strcmp(udev_device_get_devtype(dev), "usb_device") == 0) {
+                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) {
+                info(udev, "unable to access usb_interface device of '%s'\n",
+                     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) {
+                info(udev, "%s: cannot get bInterfaceClass attribute\n",
+                     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);
+        }
+
+        info(udev, "%s: if_class %d protocol %d\n",
+             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) {
+                info(udev, "unable to find parent 'usb' device of '%s'\n",
+                     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) {
+                        info(udev, "unable to find parent 'scsi' device of '%s'\n",
+                             udev_device_get_syspath(dev));
+                        goto fallback;
+                }
+                if (sscanf(udev_device_get_sysname(dev_scsi), "%d:%d:%d:%d", &host, &bus, &target, &lun) != 4) {
+                        info(udev, "invalid scsi device '%s'\n", 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) {
+                        info(udev, "%s: cannot get SCSI vendor attribute\n",
+                             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) {
+                        info(udev, "%s: cannot get SCSI model attribute\n",
+                             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) {
+                        info(udev, "%s: cannot get SCSI type attribute\n",
+                             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) {
+                        info(udev, "%s: cannot get SCSI revision attribute\n",
+                             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) {
+                        info(udev, "No USB vendor information available\n");
+                        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) {
+                        dbg(udev, "No USB model information available\n");
+                        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) {
+                        util_replace_whitespace(usb_serial, serial_str, sizeof(serial_str)-1);
+                        util_replace_chars(serial_str, NULL);
+                }
+        }
+
+        s = serial;
+        l = util_strpcpyl(&s, sizeof(serial), vendor_str, "_", model_str, NULL);
+        if (serial_str[0] != '\0')
+                l = util_strpcpyl(&s, l, "_", serial_str, NULL);
+
+        if (instance_str[0] != '\0')
+                util_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 (file)
index 0000000..5bc5fa6
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2007-2009 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+
+#include "udev.h"
+
+static const struct udev_builtin *builtins[] = {
+        [UDEV_BUILTIN_BLKID] = &udev_builtin_blkid,
+        [UDEV_BUILTIN_FIRMWARE] = &udev_builtin_firmware,
+        [UDEV_BUILTIN_INPUT_ID] = &udev_builtin_input_id,
+        [UDEV_BUILTIN_KMOD] = &udev_builtin_kmod,
+        [UDEV_BUILTIN_PATH_ID] = &udev_builtin_path_id,
+        [UDEV_BUILTIN_PCI_DB] = &udev_builtin_pci_db,
+        [UDEV_BUILTIN_USB_DB] = &udev_builtin_usb_db,
+        [UDEV_BUILTIN_USB_ID] = &udev_builtin_usb_id,
+};
+
+int udev_builtin_init(struct udev *udev)
+{
+        unsigned int i;
+        int err;
+
+        for (i = 0; i < ARRAY_SIZE(builtins); i++) {
+                if (builtins[i]->init) {
+                        err = builtins[i]->init(udev);
+                        if (err < 0)
+                                break;
+                }
+        }
+        return err;
+}
+
+void udev_builtin_exit(struct udev *udev)
+{
+        unsigned int i;
+
+        for (i = 0; i < ARRAY_SIZE(builtins); i++)
+                if (builtins[i]->exit)
+                        builtins[i]->exit(udev);
+}
+
+bool udev_builtin_validate(struct udev *udev)
+{
+        unsigned int i;
+        bool change = false;
+
+        for (i = 0; i < ARRAY_SIZE(builtins); i++)
+                if (builtins[i]->validate)
+                        if (builtins[i]->validate(udev))
+                                change = true;
+        return change;
+}
+
+void udev_builtin_list(struct udev *udev)
+{
+        unsigned int i;
+
+        for (i = 0; i < ARRAY_SIZE(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;
+
+        util_strscpy(name, sizeof(name), command);
+        pos = strchr(name, ' ');
+        if (pos)
+                pos[0] = '\0';
+        for (i = 0; i < ARRAY_SIZE(builtins); i++)
+                if (strcmp(builtins[i]->name, name) == 0)
+                        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];
+
+        optind = 0;
+        util_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);
+
+        info(udev_device_get_udev(dev), "%s=%s\n", key, val);
+        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 (file)
index 0000000..5556f1a
--- /dev/null
@@ -0,0 +1,494 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.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.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#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;
+
+        uctrl = calloc(1, sizeof(struct udev_ctrl));
+        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) {
+                        err(udev, "error getting socket: %m\n");
+                        udev_ctrl_unref(uctrl);
+                        return NULL;
+                }
+        } else {
+                uctrl->bound = true;
+                uctrl->sock = fd;
+        }
+
+        uctrl->saddr.sun_family = AF_LOCAL;
+        util_strscpyl(uctrl->saddr.sun_path, sizeof(uctrl->saddr.sun_path),
+                      udev_get_run_path(udev), "/control", NULL);
+        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;
+                        err(uctrl->udev, "bind failed: %m\n");
+                        return err;
+                }
+
+                err = listen(uctrl->sock, 0);
+                if (err < 0) {
+                        err = -errno;
+                        err(uctrl->udev, "listen failed: %m\n");
+                        return err;
+                }
+
+                uctrl->bound = true;
+                uctrl->cleanup_socket = true;
+        }
+        return 0;
+}
+
+struct udev *udev_ctrl_get_udev(struct udev_ctrl *uctrl)
+{
+        return uctrl->udev;
+}
+
+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;
+        socklen_t slen;
+        const int on = 1;
+
+        conn = calloc(1, sizeof(struct udev_ctrl_connection));
+        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)
+                        err(uctrl->udev, "unable to receive ctrl connection: %m\n");
+                goto err;
+        }
+
+        /* check peer credential of connection */
+        slen = sizeof(ucred);
+        if (getsockopt(conn->sock, SOL_SOCKET, SO_PEERCRED, &ucred, &slen) < 0) {
+                err(uctrl->udev, "unable to receive credentials of ctrl connection: %m\n");
+                goto err;
+        }
+        if (ucred.uid > 0) {
+                err(uctrl->udev, "sender uid=%i, message ignored\n", 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;
+
+        memset(&ctrl_msg_wire, 0x00, 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)
+                util_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 *udev = conn->uctrl->udev;
+        struct udev_ctrl_msg *uctrl_msg;
+        ssize_t size;
+        struct msghdr smsg;
+        struct cmsghdr *cmsg;
+        struct iovec iov;
+        struct ucred *cred;
+        char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
+
+        uctrl_msg = calloc(1, sizeof(struct udev_ctrl_msg));
+        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) {
+                        err(udev, "timeout waiting for ctrl message\n");
+                        goto err;
+                } else {
+                        if (!(pfd[0].revents & POLLIN)) {
+                                err(udev, "ctrl connection error: %m\n");
+                                goto err;
+                        }
+                }
+
+                break;
+        }
+
+        iov.iov_base = &uctrl_msg->ctrl_msg_wire;
+        iov.iov_len = sizeof(struct udev_ctrl_msg_wire);
+        memset(&smsg, 0x00, sizeof(struct msghdr));
+        smsg.msg_iov = &iov;
+        smsg.msg_iovlen = 1;
+        smsg.msg_control = cred_msg;
+        smsg.msg_controllen = sizeof(cred_msg);
+        size = recvmsg(conn->sock, &smsg, 0);
+        if (size <  0) {
+                err(udev, "unable to receive ctrl message: %m\n");
+                goto err;
+        }
+        cmsg = CMSG_FIRSTHDR(&smsg);
+        cred = (struct ucred *) CMSG_DATA(cmsg);
+
+        if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
+                err(udev, "no sender credentials received, message ignored\n");
+                goto err;
+        }
+
+        if (cred->uid != 0) {
+                err(udev, "sender uid=%i, message ignored\n", cred->uid);
+                goto err;
+        }
+
+        if (uctrl_msg->ctrl_msg_wire.magic != UDEV_CTRL_MAGIC) {
+                err(udev, "message magic 0x%08x doesn't match, ignore it\n", uctrl_msg->ctrl_msg_wire.magic);
+                goto err;
+        }
+
+        dbg(udev, "created ctrl_msg %p (%i)\n", uctrl_msg, uctrl_msg->ctrl_msg_wire.type);
+        return uctrl_msg;
+err:
+        udev_ctrl_msg_unref(uctrl_msg);
+        return NULL;
+}
+
+struct udev_ctrl_msg *udev_ctrl_msg_ref(struct udev_ctrl_msg *ctrl_msg)
+{
+        if (ctrl_msg == NULL)
+                return NULL;
+        ctrl_msg->refcount++;
+        return ctrl_msg;
+}
+
+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;
+        dbg(ctrl_msg->conn->uctrl->udev, "release ctrl_msg %p\n", 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 (file)
index 0000000..40a6b7d
--- /dev/null
@@ -0,0 +1,1011 @@
+/*
+ * Copyright (C) 2003-2010 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <sys/prctl.h>
+#include <sys/poll.h>
+#include <sys/epoll.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/signalfd.h>
+#include <linux/sockios.h>
+
+#include "udev.h"
+
+struct udev_event *udev_event_new(struct udev_device *dev)
+{
+        struct udev *udev = udev_device_get_udev(dev);
+        struct udev_event *event;
+
+        event = calloc(1, sizeof(struct udev_event));
+        if (event == NULL)
+                return NULL;
+        event->dev = dev;
+        event->udev = udev;
+        udev_list_init(udev, &event->run_list, false);
+        event->fd_signal = -1;
+        event->birth_usec = now_usec();
+        event->timeout_usec = 30 * 1000 * 1000;
+        dbg(event->udev, "allocated event %p\n", event);
+        return event;
+}
+
+void udev_event_unref(struct udev_event *event)
+{
+        if (event == NULL)
+                return;
+        udev_list_cleanup(&event->run_list);
+        free(event->program_result);
+        free(event->name);
+        dbg(event->udev, "free event %p\n", event);
+        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 {
+                char *name;
+                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 < ARRAY_SIZE(map); i++) {
+                                        if (strncmp(&from[1], map[i].name, strlen(map[i].name)) == 0) {
+                                                type = map[i].type;
+                                                from += strlen(map[i].name)+1;
+                                                dbg(event->udev, "will substitute format name '%s'\n", map[i].name);
+                                                goto subst;
+                                        }
+                                }
+                        } else if (from[0] == '%') {
+                                /* substitute format char */
+                                unsigned int i;
+
+                                if (from[1] == '%') {
+                                        from++;
+                                        goto copy;
+                                }
+
+                                for (i = 0; i < ARRAY_SIZE(map); i++) {
+                                        if (from[1] == map[i].fmt) {
+                                                type = map[i].type;
+                                                from += 2;
+                                                dbg(event->udev, "will substitute format char '%c'\n", map[i].fmt);
+                                                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') {
+                                        err(event->udev, "missing closing brace for format '%s'\n", 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 = util_strpcpy(&s, l, udev_device_get_devpath(dev));
+                        dbg(event->udev, "substitute devpath '%s'\n", udev_device_get_devpath(dev));
+                        break;
+                case SUBST_KERNEL:
+                        l = util_strpcpy(&s, l, udev_device_get_sysname(dev));
+                        dbg(event->udev, "substitute kernel name '%s'\n", udev_device_get_sysname(dev));
+                        break;
+                case SUBST_KERNEL_NUMBER:
+                        if (udev_device_get_sysnum(dev) == NULL)
+                                break;
+                        l = util_strpcpy(&s, l, udev_device_get_sysnum(dev));
+                        dbg(event->udev, "substitute kernel number '%s'\n", udev_device_get_sysnum(dev));
+                        break;
+                case SUBST_ID:
+                        if (event->dev_parent == NULL)
+                                break;
+                        l = util_strpcpy(&s, l, udev_device_get_sysname(event->dev_parent));
+                        dbg(event->udev, "substitute id '%s'\n", 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 = util_strpcpy(&s, l, driver);
+                        dbg(event->udev, "substitute driver '%s'\n", driver);
+                        break;
+                }
+                case SUBST_MAJOR: {
+                        char num[UTIL_PATH_SIZE];
+
+                        sprintf(num, "%d", major(udev_device_get_devnum(dev)));
+                        l = util_strpcpy(&s, l, num);
+                        dbg(event->udev, "substitute major number '%s'\n", num);
+                        break;
+                }
+                case SUBST_MINOR: {
+                        char num[UTIL_PATH_SIZE];
+
+                        sprintf(num, "%d", minor(udev_device_get_devnum(dev)));
+                        l = util_strpcpy(&s, l, num);
+                        dbg(event->udev, "substitute minor number '%s'\n", 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;
+
+                                dbg(event->udev, "request part #%d of result string\n", i);
+                                util_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) {
+                                        err(event->udev, "requested part of result string not found\n");
+                                        break;
+                                }
+                                util_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 = util_strpcpy(&s, l, tmp);
+                                dbg(event->udev, "substitute part of result string '%s'\n", tmp);
+                        } else {
+                                l = util_strpcpy(&s, l, event->program_result);
+                                dbg(event->udev, "substitute result string '%s'\n", event->program_result);
+                        }
+                        break;
+                }
+                case SUBST_ATTR: {
+                        const char *value = NULL;
+                        char vbuf[UTIL_NAME_SIZE];
+                        size_t len;
+                        int count;
+
+                        if (attr == NULL) {
+                                err(event->udev, "missing file parameter for attr\n");
+                                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)
+                                util_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)
+                                info(event->udev, "%i character(s) replaced\n" , count);
+                        l = util_strpcpy(&s, l, vbuf);
+                        dbg(event->udev, "substitute sysfs value '%s'\n", 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) {
+                                size_t devlen = strlen(udev_get_dev_path(event->udev))+1;
+
+                                l = util_strpcpy(&s, l, &devnode[devlen]);
+                                dbg(event->udev, "found parent '%s', got node name '%s'\n",
+                                    udev_device_get_syspath(dev_parent), &devnode[devlen]);
+                        }
+                        break;
+                }
+                case SUBST_DEVNODE:
+                        if (udev_device_get_devnode(dev) != NULL)
+                                l = util_strpcpy(&s, l, udev_device_get_devnode(dev));
+                        break;
+                case SUBST_NAME: {
+                        if (event->name != NULL) {
+                                l = util_strpcpy(&s, l, event->name);
+                                dbg(event->udev, "substitute custom node name '%s'\n", event->name);
+                        } else if (udev_device_get_devnode(dev) != NULL) {
+                                size_t devlen = strlen(udev_get_dev_path(event->udev))+1;
+
+                                l = util_strpcpy(&s, l, &udev_device_get_devnode(dev)[devlen]);
+                                dbg(event->udev, "substitute node name'%s'\n", &udev_device_get_devnode(dev)[devlen]);
+                        } else {
+                                l = util_strpcpy(&s, l, udev_device_get_sysname(dev));
+                                dbg(event->udev, "substitute device name'%s'\n", udev_device_get_sysname(dev));
+                        }
+                        break;
+                }
+                case SUBST_LINKS: {
+                        size_t devlen = strlen(udev_get_dev_path(event->udev))+1;
+                        struct udev_list_entry *list_entry;
+
+                        list_entry = udev_device_get_devlinks_list_entry(dev);
+                        if (list_entry == NULL)
+                                break;
+                        l = util_strpcpy(&s, l, &udev_list_entry_get_name(list_entry)[devlen]);
+                        udev_list_entry_foreach(list_entry, udev_list_entry_get_next(list_entry))
+                                l = util_strpcpyl(&s, l, " ", &udev_list_entry_get_name(list_entry)[devlen], NULL);
+                        break;
+                }
+                case SUBST_ROOT:
+                        l = util_strpcpy(&s, l, udev_get_dev_path(event->udev));
+                        dbg(event->udev, "substitute udev_root '%s'\n", udev_get_dev_path(event->udev));
+                        break;
+                case SUBST_SYS:
+                        l = util_strpcpy(&s, l, udev_get_sys_path(event->udev));
+                        dbg(event->udev, "substitute sys_path '%s'\n", udev_get_sys_path(event->udev));
+                        break;
+                case SUBST_ENV:
+                        if (attr == NULL) {
+                                dbg(event->udev, "missing attribute\n");
+                                break;
+                        } else {
+                                const char *value;
+
+                                value = udev_device_get_property_value(event->dev, attr);
+                                if (value == NULL)
+                                        break;
+                                dbg(event->udev, "substitute env '%s=%s'\n", attr, value);
+                                l = util_strpcpy(&s, l, value);
+                                break;
+                        }
+                default:
+                        err(event->udev, "unknown substitution type=%i\n", type);
+                        break;
+                }
+        }
+
+out:
+        s[0] = '\0';
+        dbg(event->udev, "'%s' -> '%s' (%zu)\n", src, dest, l);
+        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)
+{
+        struct udev *udev = event->udev;
+        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 {
+                err(udev, "open /dev/null failed: %m\n");
+        }
+
+        /* 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;
+        err(udev, "failed to execute '%s' '%s': %m\n", 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)
+{
+        struct udev *udev = event->udev;
+        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) {
+                err(udev, "error creating epoll fd: %m\n");
+                goto out;
+        }
+
+        if (fd_stdout >= 0) {
+                memset(&ep_outpipe, 0, 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) {
+                        err(udev, "fail to add fd to epoll: %m\n");
+                        goto out;
+                }
+        }
+
+        if (fd_stderr >= 0) {
+                memset(&ep_errpipe, 0, 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) {
+                        err(udev, "fail to add fd to epoll: %m\n");
+                        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) {
+                        unsigned long long age_usec;
+
+                        age_usec = now_usec() - event->birth_usec;
+                        if (age_usec >= event->timeout_usec) {
+                                err(udev, "timeout '%s'\n", cmd);
+                                goto out;
+                        }
+                        timeout = ((event->timeout_usec - age_usec) / 1000) + 1000;
+                } else {
+                        timeout = -1;
+                }
+
+                fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), timeout);
+                if (fdcount < 0) {
+                        if (errno == EINTR)
+                                continue;
+                        err(udev, "failed to poll: %m\n");
+                        goto out;
+                }
+                if (fdcount == 0) {
+                        err(udev, "timeout '%s'\n", 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 {
+                                                err(udev, "'%s' ressize %zd too short\n", 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')
+                                                        info(udev, "'%s'(%s) '%s'\n", cmd, *fd == fd_stdout ? "out" : "err" , line);
+                                        }
+                                }
+                        } else if (ev[i].events & EPOLLHUP) {
+                                if (epoll_ctl(fd_ep, EPOLL_CTL_DEL, *fd, NULL) < 0) {
+                                        err(udev, "failed to remove fd from epoll: %m\n");
+                                        goto out;
+                                }
+                                *fd = -1;
+                        }
+                }
+        }
+
+        /* return the child's stdout string */
+        if (result != NULL) {
+                result[respos] = '\0';
+                dbg(udev, "result='%s'\n", result);
+        }
+out:
+        if (fd_ep >= 0)
+                close(fd_ep);
+}
+
+static int spawn_wait(struct udev_event *event, const char *cmd, pid_t pid)
+{
+        struct udev *udev = event->udev;
+        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) {
+                        unsigned long long age_usec;
+
+                        age_usec = now_usec() - 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;
+                        err(udev, "failed to poll: %m\n");
+                        goto out;
+                }
+                if (fdcount == 0) {
+                        err(udev, "timeout: killing '%s' [%u]\n", 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)) {
+                                        info(udev, "'%s' [%u] exit with return code %i\n", cmd, pid, WEXITSTATUS(status));
+                                        if (WEXITSTATUS(status) != 0)
+                                                err = -1;
+                                } else if (WIFSIGNALED(status)) {
+                                        err(udev, "'%s' [%u] terminated by signal %i (%s)\n", cmd, pid, WTERMSIG(status), strsignal(WTERMSIG(status)));
+                                        err = -1;
+                                } else if (WIFSTOPPED(status)) {
+                                        err(udev, "'%s' [%u] stopped\n", cmd, pid);
+                                        err = -1;
+                                } else if (WIFCONTINUED(status)) {
+                                        err(udev, "'%s' [%u] continued\n", cmd, pid);
+                                        err = -1;
+                                } else {
+                                        err(udev, "'%s' [%u] exit with status 0x%04x\n", 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++;
+                }
+                dbg(udev, "argv[%i] '%s'\n", i, argv[i]);
+                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;
+
+        util_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;
+                        err(udev, "pipe failed: %m\n");
+                        goto out;
+                }
+        }
+        if (udev_get_log_priority(udev) >= LOG_INFO) {
+                if (pipe2(errpipe, O_NONBLOCK) != 0) {
+                        err = -errno;
+                        err(udev, "pipe failed: %m\n");
+                        goto out;
+                }
+        }
+
+        /* allow programs in /usr/lib/udev/ to be called without the path */
+        if (argv[0][0] != '/') {
+                util_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;
+                }
+
+                info(udev, "starting '%s'\n", cmd);
+
+                err = spawn_exec(event, cmd, argv, envp, sigmask,
+                                 outpipe[WRITE_END], errpipe[WRITE_END]);
+
+                _exit(2 );
+        case -1:
+                err(udev, "fork of '%s' failed: %m\n", 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 void rename_netif_kernel_log(struct ifreq ifr)
+{
+        int klog;
+        FILE *f;
+
+        klog = open("/dev/kmsg", O_WRONLY);
+        if (klog < 0)
+                return;
+
+        f = fdopen(klog, "w");
+        if (f == NULL) {
+                close(klog);
+                return;
+        }
+
+        fprintf(f, "<30>udevd[%u]: renamed network interface %s to %s\n",
+                getpid(), ifr.ifr_name, ifr.ifr_newname);
+        fclose(f);
+}
+
+static int rename_netif(struct udev_event *event)
+{
+        struct udev_device *dev = event->dev;
+        int sk;
+        struct ifreq ifr;
+        int loop;
+        int err;
+
+        info(event->udev, "changing net interface name from '%s' to '%s'\n",
+             udev_device_get_sysname(dev), event->name);
+
+        sk = socket(PF_INET, SOCK_DGRAM, 0);
+        if (sk < 0) {
+                err = -errno;
+                err(event->udev, "error opening socket: %m\n");
+                return err;
+        }
+
+        memset(&ifr, 0x00, sizeof(struct ifreq));
+        util_strscpy(ifr.ifr_name, IFNAMSIZ, udev_device_get_sysname(dev));
+        util_strscpy(ifr.ifr_newname, IFNAMSIZ, event->name);
+        err = ioctl(sk, SIOCSIFNAME, &ifr);
+        if (err == 0) {
+                rename_netif_kernel_log(ifr);
+                goto out;
+        }
+
+        /* keep trying if the destination interface name already exists */
+        err = -errno;
+        if (err != -EEXIST)
+                goto out;
+
+        /* free our own name, another process may wait for us */
+        snprintf(ifr.ifr_newname, IFNAMSIZ, "rename%u", udev_device_get_ifindex(dev));
+        err = ioctl(sk, SIOCSIFNAME, &ifr);
+        if (err < 0) {
+                err = -errno;
+                goto out;
+        }
+
+        /* log temporary name */
+        rename_netif_kernel_log(ifr);
+
+        /* wait a maximum of 90 seconds for our target to become available */
+        util_strscpy(ifr.ifr_name, IFNAMSIZ, ifr.ifr_newname);
+        util_strscpy(ifr.ifr_newname, IFNAMSIZ, event->name);
+        loop = 90 * 20;
+        while (loop--) {
+                const struct timespec duration = { 0, 1000 * 1000 * 1000 / 20 };
+
+                dbg(event->udev, "wait for netif '%s' to become free, loop=%i\n",
+                    event->name, (90 * 20) - loop);
+                nanosleep(&duration, NULL);
+
+                err = ioctl(sk, SIOCSIFNAME, &ifr);
+                if (err == 0) {
+                        rename_netif_kernel_log(ifr);
+                        break;
+                }
+                err = -errno;
+                if (err != -EEXIST)
+                        break;
+        }
+
+out:
+        if (err < 0)
+                err(event->udev, "error changing net interface name %s to %s: %m\n", ifr.ifr_name, ifr.ifr_newname);
+        close(sk);
+        return err;
+}
+
+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 (strcmp(udev_device_get_action(dev), "remove") == 0) {
+                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_from_syspath(event->udev, udev_device_get_syspath(dev));
+                if (event->dev_db != NULL) {
+                        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 && strcmp(udev_device_get_action(dev), "add") == 0 &&
+                    event->name != NULL && strcmp(event->name, udev_device_get_sysname(dev)) != 0) {
+                        char syspath[UTIL_PATH_SIZE];
+                        char *pos;
+
+                        err = rename_netif(event);
+                        if (err == 0) {
+                                info(event->udev, "renamed netif to '%s'\n", 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 */
+                                util_strscpy(syspath, sizeof(syspath), udev_device_get_syspath(dev));
+                                pos = strrchr(syspath, '/');
+                                if (pos != NULL) {
+                                        pos++;
+                                        util_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));
+                                        info(event->udev, "changed devpath to '%s'\n", udev_device_get_devpath(dev));
+                                }
+                        }
+                }
+
+                if (major(udev_device_get_devnum(dev)) > 0) {
+                        /* 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->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;
+                                }
+                        }
+
+                        udev_node_add(dev, event->mode, event->uid, event->gid);
+                }
+
+                /* 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_usec());
+
+                /* (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;
+        }
+out:
+        return err;
+}
+
+int udev_event_execute_run(struct udev_event *event, const sigset_t *sigmask)
+{
+        struct udev_list_entry *list_entry;
+        int err = 0;
+
+        dbg(event->udev, "executing run list\n");
+        udev_list_entry_foreach(list_entry, udev_list_get_entry(&event->run_list)) {
+                const char *cmd = udev_list_entry_get_name(list_entry);
+
+                if (strncmp(cmd, "socket:", strlen("socket:")) == 0) {
+                        struct udev_monitor *monitor;
+
+                        monitor = udev_monitor_new_from_socket(event->udev, &cmd[strlen("socket:")]);
+                        if (monitor == NULL)
+                                continue;
+                        udev_monitor_send_device(monitor, NULL, event->dev);
+                        udev_monitor_unref(monitor);
+                } else {
+                        char program[UTIL_PATH_SIZE];
+                        char **envp;
+
+                        if (event->exec_delay > 0) {
+                                info(event->udev, "delay execution of '%s'\n", program);
+                                sleep(event->exec_delay);
+                        }
+
+                        udev_event_apply_format(event, cmd, program, sizeof(program));
+                        envp = udev_device_get_properties_envp(event->dev);
+                        if (udev_event_spawn(event, program, envp, sigmask, NULL, 0) < 0) {
+                                if (udev_list_entry_get_num(list_entry))
+                                        err = -1;
+                        }
+                }
+        }
+        return err;
+}
diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
new file mode 100644 (file)
index 0000000..7a01a47
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ * Copyright (C) 2003-2010 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <grp.h>
+#include <dirent.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "udev.h"
+
+#define TMP_FILE_EXT                ".udev-tmp"
+
+static int node_symlink(struct udev *udev, 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 + sizeof(TMP_FILE_EXT)];
+        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 = util_strpcpy(&s, l, "../");
+                i++;
+        }
+        l = util_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)) {
+                        struct stat stats2;
+
+                        info(udev, "found existing node instead of symlink '%s'\n", slink);
+                        if (lstat(node, &stats2) == 0) {
+                                if ((stats.st_mode & S_IFMT) == (stats2.st_mode & S_IFMT) &&
+                                    stats.st_rdev == stats2.st_rdev && stats.st_ino != stats2.st_ino) {
+                                        info(udev, "replace device node '%s' with symlink to our node '%s'\n",
+                                             slink, node);
+                                } else {
+                                        err(udev, "device node '%s' already exists, "
+                                            "link to '%s' will not overwrite it\n",
+                                            slink, node);
+                                        goto exit;
+                                }
+                        }
+                } else if (S_ISLNK(stats.st_mode)) {
+                        char buf[UTIL_PATH_SIZE];
+                        int len;
+
+                        dbg(udev, "found existing symlink '%s'\n", slink);
+                        len = readlink(slink, buf, sizeof(buf));
+                        if (len > 0 && len < (int)sizeof(buf)) {
+                                buf[len] = '\0';
+                                if (strcmp(target, buf) == 0) {
+                                        info(udev, "preserve already existing symlink '%s' to '%s'\n",
+                                             slink, target);
+                                        udev_selinux_lsetfilecon(udev, slink, S_IFLNK);
+                                        utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW);
+                                        goto exit;
+                                }
+                        }
+                }
+        } else {
+                info(udev, "creating symlink '%s' to '%s'\n", slink, target);
+                do {
+                        err = util_create_path_selinux(udev, slink);
+                        if (err != 0 && err != -ENOENT)
+                                break;
+                        udev_selinux_setfscreatecon(udev, slink, S_IFLNK);
+                        err = symlink(target, slink);
+                        if (err != 0)
+                                err = -errno;
+                        udev_selinux_resetfscreatecon(udev);
+                } while (err == -ENOENT);
+                if (err == 0)
+                        goto exit;
+        }
+
+        info(udev, "atomically replace '%s'\n", slink);
+        util_strscpyl(slink_tmp, sizeof(slink_tmp), slink, TMP_FILE_EXT, NULL);
+        unlink(slink_tmp);
+        do {
+                err = util_create_path_selinux(udev, slink_tmp);
+                if (err != 0 && err != -ENOENT)
+                        break;
+                udev_selinux_setfscreatecon(udev, slink_tmp, S_IFLNK);
+                err = symlink(target, slink_tmp);
+                if (err != 0)
+                        err = -errno;
+                udev_selinux_resetfscreatecon(udev);
+        } while (err == -ENOENT);
+        if (err != 0) {
+                err(udev, "symlink '%s' '%s' failed: %m\n", target, slink_tmp);
+                goto exit;
+        }
+        err = rename(slink_tmp, slink);
+        if (err != 0) {
+                err(udev, "rename '%s' '%s' failed: %m\n", 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);
+                util_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;
+
+                info(udev, "found '%s' claiming '%s'\n", dent->d_name, stackdir);
+
+                /* did we find ourself? */
+                if (strcmp(dent->d_name, udev_device_get_id_filename(dev)) == 0)
+                        continue;
+
+                dev_db = udev_device_new_from_id_filename(udev, dent->d_name);
+                if (dev_db != NULL) {
+                        const char *devnode;
+
+                        devnode = udev_device_get_devnode(dev_db);
+                        if (devnode != NULL) {
+                                dbg(udev, "compare priority of '%s'(%i) > '%s'(%i)\n", target, priority,
+                                    udev_device_get_devnode(dev_db), udev_device_get_devlink_priority(dev_db));
+                                if (target == NULL || udev_device_get_devlink_priority(dev_db) > priority) {
+                                        info(udev, "'%s' claims priority %i for '%s'\n",
+                                             udev_device_get_syspath(dev_db), udev_device_get_devlink_priority(dev_db), stackdir);
+                                        priority = udev_device_get_devlink_priority(dev_db);
+                                        util_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];
+
+        dbg(udev, "update symlink '%s' of '%s'\n", slink, udev_device_get_syspath(dev));
+
+        util_path_encode(&slink[strlen(udev_get_dev_path(udev))+1], name_enc, sizeof(name_enc));
+        util_strscpyl(dirname, sizeof(dirname), udev_get_run_path(udev), "/links/", name_enc, NULL);
+        util_strscpyl(filename, sizeof(filename), dirname, "/", udev_device_get_id_filename(dev), NULL);
+
+        if (!add) {
+                dbg(udev, "removing index: '%s'\n", filename);
+                if (unlink(filename) == 0)
+                        rmdir(dirname);
+        }
+
+        target = link_find_prioritized(dev, add, dirname, buf, sizeof(buf));
+        if (target == NULL) {
+                info(udev, "no reference left, remove '%s'\n", slink);
+                if (unlink(slink) == 0)
+                        util_delete_path(udev, slink);
+        } else {
+                info(udev, "creating link '%s' to '%s'\n", slink, target);
+                node_symlink(udev, target, slink);
+        }
+
+        if (add) {
+                int err;
+
+                dbg(udev, "creating index: '%s'\n", filename);
+                do {
+                        int fd;
+
+                        err = util_create_path(udev, filename);
+                        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 *udev = udev_device_get_udev(dev);
+        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 (strcmp(name, name_current) == 0) {
+                                found = 1;
+                                break;
+                        }
+                }
+                if (found)
+                        continue;
+
+                info(udev, "update old name, '%s' no longer belonging to '%s'\n",
+                     name, udev_device_get_devpath(dev));
+                link_update(dev, name, 0);
+        }
+}
+
+static int node_fixup(struct udev_device *dev, mode_t mode, uid_t uid, gid_t gid)
+{
+        struct udev *udev = udev_device_get_udev(dev);
+        const char *devnode = udev_device_get_devnode(dev);
+        dev_t devnum = udev_device_get_devnum(dev);
+        struct stat stats;
+        int err = 0;
+
+        if (strcmp(udev_device_get_subsystem(dev), "block") == 0)
+                mode |= S_IFBLK;
+        else
+                mode |= S_IFCHR;
+
+        if (lstat(devnode, &stats) != 0) {
+                err = -errno;
+                info(udev, "can not stat() node '%s' (%m)\n", devnode);
+                goto out;
+        }
+
+        if (((stats.st_mode & S_IFMT) != (mode & S_IFMT)) || (stats.st_rdev != devnum)) {
+                err = -EEXIST;
+                info(udev, "found node '%s' with non-matching devnum %s, skip handling\n",
+                     udev_device_get_devnode(dev), udev_device_get_id_filename(dev));
+                goto out;
+        }
+
+        if ((stats.st_mode & 0777) != (mode & 0777) || stats.st_uid != uid || stats.st_gid != gid) {
+                info(udev, "set permissions %s, %#o, uid=%u, gid=%u\n", devnode, mode, uid, gid);
+                chmod(devnode, mode);
+                chown(devnode, uid, gid);
+        } else {
+                info(udev, "preserve permissions %s, %#o, uid=%u, gid=%u\n", devnode, mode, uid, gid);
+        }
+
+        /*
+         * Set initial selinux file context only on add events.
+         * We set the proper context on bootup (triger) or for newly
+         * added devices, but we don't change it later, in case
+         * something else has set a custom context in the meantime.
+         */
+        if (strcmp(udev_device_get_action(dev), "add") == 0)
+                udev_selinux_lsetfilecon(udev, devnode, mode);
+
+        /* 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, mode_t mode, uid_t uid, gid_t gid)
+{
+        struct udev *udev = udev_device_get_udev(dev);
+        char filename[UTIL_PATH_SIZE];
+        struct udev_list_entry *list_entry;
+        int err = 0;
+
+        info(udev, "handling device node '%s', devnum=%s, mode=%#o, uid=%d, gid=%d\n",
+             udev_device_get_devnode(dev), udev_device_get_id_filename(dev), mode, uid, gid);
+
+        if (node_fixup(dev, mode, uid, gid) < 0)
+                return;
+
+        /* always add /dev/{block,char}/$major:$minor */
+        snprintf(filename, sizeof(filename), "%s/%s/%u:%u",
+                 udev_get_dev_path(udev),
+                 strcmp(udev_device_get_subsystem(dev), "block") == 0 ? "block" : "char",
+                 major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev)));
+        node_symlink(udev, 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)) {
+                if (udev_list_entry_get_num(list_entry))
+                        /* simple unmanaged link name */
+                        node_symlink(udev, udev_device_get_devnode(dev), udev_list_entry_get_name(list_entry));
+                else
+                        link_update(dev, udev_list_entry_get_name(list_entry), 1);
+        }
+}
+
+void udev_node_remove(struct udev_device *dev)
+{
+        struct udev *udev = udev_device_get_udev(dev);
+        struct udev_list_entry *list_entry;
+        const char *devnode;
+        struct stat stats;
+        struct udev_device *dev_check;
+        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), 0);
+
+        /* remove /dev/{block,char}/$major:$minor */
+        snprintf(filename, sizeof(filename), "%s/%s/%u:%u",
+                 udev_get_dev_path(udev),
+                 strcmp(udev_device_get_subsystem(dev), "block") == 0 ? "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 (file)
index 0000000..8a85eae
--- /dev/null
@@ -0,0 +1,2767 @@
+/*
+ * Copyright (C) 2003-2010 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2008 Alan Jenkins <alan-jenkins@tuffmail.co.uk>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stddef.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+#include <dirent.h>
+#include <fnmatch.h>
+#include <time.h>
+
+#include "udev.h"
+
+#define PREALLOC_TOKEN          2048
+#define PREALLOC_STRBUF         32 * 1024
+#define PREALLOC_TRIE           256
+
+struct uid_gid {
+        unsigned int name_off;
+        union {
+                uid_t uid;
+                gid_t gid;
+        };
+};
+
+struct trie_node {
+        /* this node's first child */
+        unsigned int child_idx;
+        /* the next child of our parent node's child list */
+        unsigned int next_child_idx;
+        /* this node's last child (shortcut for append) */
+        unsigned int last_child_idx;
+        unsigned int value_off;
+        unsigned short value_len;
+        unsigned char key;
+};
+
+struct udev_rules {
+        struct udev *udev;
+        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 to a single string buffer */
+        char *buf;
+        size_t buf_cur;
+        size_t buf_max;
+        unsigned int buf_count;
+
+        /* during rule parsing, strings are indexed to find duplicates */
+        struct trie_node *trie_nodes;
+        unsigned int trie_nodes_cur;
+        unsigned int trie_nodes_max;
+
+        /* 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;
+};
+
+/* 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_STATIC_NODE,               /* val */
+        TK_A_ENV,                       /* val, attr */
+        TK_A_TAG,                       /* val */
+        TK_A_NAME,                      /* val */
+        TK_A_DEVLINK,                   /* val */
+        TK_A_ATTR,                      /* val, attr */
+        TK_A_RUN,                       /* 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;
+                                int devlink_unique;
+                                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 ENABLE_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_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] =                    "A RUN",
+                [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 = &rules->buf[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);
+
+                        dbg(rules->udev, "* RULE %s:%u, token: %u, count: %u, label: '%s'\n",
+                            &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:
+                dbg(rules->udev, "%s %s '%s'(%s)\n",
+                    token_str(type), operation_str(op), value, string_glob_str(glob));
+                break;
+        case TK_M_IMPORT_BUILTIN:
+                dbg(rules->udev, "%s %i '%s'\n", 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:
+                dbg(rules->udev, "%s %s '%s' '%s'(%s)\n",
+                    token_str(type), operation_str(op), attr, value, string_glob_str(glob));
+                break;
+        case TK_M_TAG:
+        case TK_A_TAG:
+                dbg(rules->udev, "%s %s '%s'\n", 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:
+                dbg(rules->udev, "%s\n", token_str(type));
+                break;
+        case TK_M_TEST:
+                dbg(rules->udev, "%s %s '%s'(%s) %#o\n",
+                    token_str(type), operation_str(op), value, string_glob_str(glob), token->key.mode);
+                break;
+        case TK_A_INOTIFY_WATCH:
+                dbg(rules->udev, "%s %u\n", token_str(type), token->key.watch);
+                break;
+        case TK_A_DEVLINK_PRIO:
+                dbg(rules->udev, "%s %u\n", token_str(type), token->key.devlink_prio);
+                break;
+        case TK_A_OWNER_ID:
+                dbg(rules->udev, "%s %s %u\n", token_str(type), operation_str(op), token->key.uid);
+                break;
+        case TK_A_GROUP_ID:
+                dbg(rules->udev, "%s %s %u\n", token_str(type), operation_str(op), token->key.gid);
+                break;
+        case TK_A_MODE_ID:
+                dbg(rules->udev, "%s %s %#o\n", token_str(type), operation_str(op), token->key.mode);
+                break;
+        case TK_A_STATIC_NODE:
+                dbg(rules->udev, "%s '%s'\n", token_str(type), value);
+                break;
+        case TK_M_EVENT_TIMEOUT:
+                dbg(rules->udev, "%s %u\n", token_str(type), token->key.event_timeout);
+                break;
+        case TK_A_GOTO:
+                dbg(rules->udev, "%s '%s' %u\n", token_str(type), value, token->key.rule_goto);
+                break;
+        case TK_END:
+                dbg(rules->udev, "* %s\n", token_str(type));
+                break;
+        case TK_M_PARENTS_MIN:
+        case TK_M_PARENTS_MAX:
+        case TK_M_MAX:
+        case TK_UNSET:
+                dbg(rules->udev, "unknown type %u\n", type);
+                break;
+        }
+}
+
+static void dump_rules(struct udev_rules *rules)
+{
+        unsigned int i;
+
+        dbg(rules->udev, "dumping %u (%zu bytes) tokens, %u (%zu bytes) strings\n",
+            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 const char *operation_str(enum operation_type type) { return NULL; }
+static inline const char *token_str(enum token_type type) { return NULL; }
+static inline void dump_token(struct udev_rules *rules, struct token *token) {}
+static inline void dump_rules(struct udev_rules *rules) {}
+#endif /* ENABLE_DEBUG */
+
+static int add_new_string(struct udev_rules *rules, const char *str, size_t bytes)
+{
+        int off;
+
+        /* grow buffer if needed */
+        if (rules->buf_cur + bytes+1 >= rules->buf_max) {
+                char *buf;
+                unsigned int add;
+
+                /* double the buffer size */
+                add = rules->buf_max;
+                if (add < bytes * 8)
+                        add = bytes * 8;
+
+                buf = realloc(rules->buf, rules->buf_max + add);
+                if (buf == NULL)
+                        return -1;
+                dbg(rules->udev, "extend buffer from %zu to %zu\n", rules->buf_max, rules->buf_max + add);
+                rules->buf = buf;
+                rules->buf_max += add;
+        }
+        off = rules->buf_cur;
+        memcpy(&rules->buf[rules->buf_cur], str, bytes);
+        rules->buf_cur += bytes;
+        rules->buf_count++;
+        return off;
+}
+
+static int add_string(struct udev_rules *rules, const char *str)
+{
+        unsigned int node_idx;
+        struct trie_node *new_node;
+        unsigned int new_node_idx;
+        unsigned char key;
+        unsigned short len;
+        unsigned int depth;
+        unsigned int off;
+        struct trie_node *parent;
+
+        /* walk trie, start from last character of str to find matching tails */
+        len = strlen(str);
+        key = str[len-1];
+        node_idx = 0;
+        for (depth = 0; depth <= len; depth++) {
+                struct trie_node *node;
+                unsigned int child_idx;
+
+                node = &rules->trie_nodes[node_idx];
+                off = node->value_off + node->value_len - len;
+
+                /* match against current node */
+                if (depth == len || (node->value_len >= len && memcmp(&rules->buf[off], str, len) == 0))
+                        return off;
+
+                /* lookup child node */
+                key = str[len - 1 - depth];
+                child_idx = node->child_idx;
+                while (child_idx > 0) {
+                        struct trie_node *child;
+
+                        child = &rules->trie_nodes[child_idx];
+                        if (child->key == key)
+                                break;
+                        child_idx = child->next_child_idx;
+                }
+                if (child_idx == 0)
+                        break;
+                node_idx = child_idx;
+        }
+
+        /* string not found, add it */
+        off = add_new_string(rules, str, len + 1);
+
+        /* grow trie nodes if needed */
+        if (rules->trie_nodes_cur >= rules->trie_nodes_max) {
+                struct trie_node *nodes;
+                unsigned int add;
+
+                /* double the buffer size */
+                add = rules->trie_nodes_max;
+                if (add < 8)
+                        add = 8;
+
+                nodes = realloc(rules->trie_nodes, (rules->trie_nodes_max + add) * sizeof(struct trie_node));
+                if (nodes == NULL)
+                        return -1;
+                dbg(rules->udev, "extend trie nodes from %u to %u\n",
+                    rules->trie_nodes_max, rules->trie_nodes_max + add);
+                rules->trie_nodes = nodes;
+                rules->trie_nodes_max += add;
+        }
+
+        /* get a new node */
+        new_node_idx = rules->trie_nodes_cur;
+        rules->trie_nodes_cur++;
+        new_node = &rules->trie_nodes[new_node_idx];
+        memset(new_node, 0x00, sizeof(struct trie_node));
+        new_node->value_off = off;
+        new_node->value_len = len;
+        new_node->key = key;
+
+        /* join the parent's child list */
+        parent = &rules->trie_nodes[node_idx];
+        if (parent->child_idx == 0) {
+                parent->child_idx = new_node_idx;
+        } else {
+                struct trie_node *last_child;
+
+                last_child = &rules->trie_nodes[parent->last_child_idx];
+                last_child->next_child_idx = new_node_idx;
+        }
+        parent->last_child_idx = new_node_idx;
+        return off;
+}
+
+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;
+                dbg(rules->udev, "extend tokens from %u to %u\n", rules->token_max, rules->token_max + add);
+                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 (strcmp(&rules->buf[off], owner) == 0) {
+                        uid = rules->uids[i].uid;
+                        dbg(rules->udev, "return existing %u for '%s'\n", uid, owner);
+                        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;
+                dbg(rules->udev, "extend uids from %u to %u\n", rules->uids_max, rules->uids_max + add);
+                rules->uids = uids;
+                rules->uids_max += add;
+        }
+        rules->uids[rules->uids_cur].uid = uid;
+        off = 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 (strcmp(&rules->buf[off], group) == 0) {
+                        gid = rules->gids[i].gid;
+                        dbg(rules->udev, "return existing %u for '%s'\n", gid, group);
+                        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;
+                dbg(rules->udev, "extend gids from %u to %u\n", rules->gids_max, rules->gids_max + add);
+                rules->gids = gids;
+                rules->gids_max += add;
+        }
+        rules->gids[rules->gids_cur].gid = gid;
+        off = 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)
+{
+        struct udev *udev = udev_device_get_udev(dev);
+        char *key;
+        char *val;
+        size_t len;
+
+        /* 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]) {
+                        info(udev, "inconsistent quoting: '%s', skip\n", line);
+                        return -1;
+                }
+                val[len-1] = '\0';
+                val++;
+        }
+
+        dbg(udev, "adding '%s'='%s'\n", key, val);
+
+        /* handle device, renamed by external tool, returning new path */
+        if (strcmp(key, "DEVPATH") == 0) {
+                char syspath[UTIL_PATH_SIZE];
+
+                info(udev, "updating devpath from '%s' to '%s'\n",
+                     udev_device_get_devpath(dev), val);
+                util_strscpyl(syspath, sizeof(syspath), udev_get_sys_path(udev), val, NULL);
+                udev_device_set_syspath(dev, syspath);
+        } else {
+                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;
+}
+
+static int import_file_into_properties(struct udev_device *dev, const char *filename)
+{
+        FILE *f;
+        char line[UTIL_LINE_SIZE];
+
+        f = fopen(filename, "r");
+        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 *udev = udev_device_get_udev(dev);
+        struct udev_device *dev_parent;
+        struct udev_list_entry *list_entry;
+
+        dev_parent = udev_device_get_parent(dev);
+        if (dev_parent == NULL)
+                return -1;
+
+        dbg(udev, "found parent '%s', get the node name\n", udev_device_get_syspath(dev_parent));
+        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;
+
+                        dbg(udev, "import key '%s=%s'\n", key, 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;
+}
+
+#define WAIT_LOOP_PER_SECOND                50
+static int wait_for_file(struct udev_device *dev, const char *file, int timeout)
+{
+        struct udev *udev = udev_device_get_udev(dev);
+        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] != '/') {
+                util_strscpyl(devicepath, sizeof(devicepath),
+                              udev_get_sys_path(udev), udev_device_get_devpath(dev), NULL);
+                util_strscpyl(filepath, sizeof(filepath), devicepath, "/", file, NULL);
+                file = filepath;
+        }
+
+        dbg(udev, "will wait %i sec for '%s'\n", timeout, file);
+        while (--loop) {
+                const struct timespec duration = { 0, 1000 * 1000 * 1000 / WAIT_LOOP_PER_SECOND };
+
+                /* lookup file */
+                if (stat(file, &stats) == 0) {
+                        info(udev, "file '%s' appeared after %i loops\n", 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) {
+                        info(udev, "device disappeared while waiting for '%s'\n", file);
+                        return -2;
+                }
+                info(udev, "wait for '%s' for %i mseconds\n", file, 1000 / WAIT_LOOP_PER_SECOND);
+                nanosleep(&duration, NULL);
+        }
+        info(udev, "waiting for '%s' failed\n", 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;
+
+                util_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;
+                                util_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++;
+        dbg(udev, "%s '%s'-'%s'\n", operation_str(*op), *key, *value);
+
+        /* move line to next key */
+        *line = temp;
+        return 0;
+}
+
+/* extract possible KEY{attr} */
+static 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) {
+                        err(udev, "missing closing brace for format\n");
+                        return NULL;
+                }
+                pos[0] = '\0';
+                dbg(udev, "attribute='%s'\n", attr);
+                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;
+
+        memset(token, 0x00, 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_NAME:
+        case TK_A_GOTO:
+        case TK_M_TAG:
+        case TK_A_TAG:
+                token->key.value_off = add_string(rule_tmp->rules, value);
+                break;
+        case TK_M_IMPORT_BUILTIN:
+                token->key.value_off = 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:
+                attr = data;
+                token->key.value_off = add_string(rule_tmp->rules, value);
+                token->key.attr_off = add_string(rule_tmp->rules, attr);
+                break;
+        case TK_A_DEVLINK:
+                token->key.value_off = add_string(rule_tmp->rules, value);
+                token->key.devlink_unique = *(int *)data;
+                break;
+        case TK_M_TEST:
+                token->key.value_off = 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:
+                token->key.value_off = 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_A_STATIC_NODE:
+                token->key.value_off = add_string(rule_tmp->rules, value);
+                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:
+                err(rule_tmp->rules->udev, "wrong type %u\n", 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 = (strchr(value, '*') != NULL || strchr(value, '?') != NULL || strchr(value, '[') != NULL);
+                if (has_split && has_glob) {
+                        glob = GL_SPLIT_GLOB;
+                } else if (has_split) {
+                        glob = GL_SPLIT;
+                } else if (has_glob) {
+                        if (strcmp(value, "?*") == 0)
+                                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/attribut 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 >= ARRAY_SIZE(rule_tmp->token)) {
+                err(rule_tmp->rules->udev, "temporary rule array too small\n");
+                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;
+        char *attr;
+        struct rule_tmp rule_tmp;
+
+        memset(&rule_tmp, 0x00, sizeof(struct rule_tmp));
+        rule_tmp.rules = rules;
+        rule_tmp.rule.type = TK_RULE;
+        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)
+                        break;
+
+                if (strcmp(key, "ACTION") == 0) {
+                        if (op > OP_MATCH_MAX) {
+                                err(rules->udev, "invalid ACTION operation\n");
+                                goto invalid;
+                        }
+                        rule_add_key(&rule_tmp, TK_M_ACTION, op, value, NULL);
+                        continue;
+                }
+
+                if (strcmp(key, "DEVPATH") == 0) {
+                        if (op > OP_MATCH_MAX) {
+                                err(rules->udev, "invalid DEVPATH operation\n");
+                                goto invalid;
+                        }
+                        rule_add_key(&rule_tmp, TK_M_DEVPATH, op, value, NULL);
+                        continue;
+                }
+
+                if (strcmp(key, "KERNEL") == 0) {
+                        if (op > OP_MATCH_MAX) {
+                                err(rules->udev, "invalid KERNEL operation\n");
+                                goto invalid;
+                        }
+                        rule_add_key(&rule_tmp, TK_M_KERNEL, op, value, NULL);
+                        continue;
+                }
+
+                if (strcmp(key, "SUBSYSTEM") == 0) {
+                        if (op > OP_MATCH_MAX) {
+                                err(rules->udev, "invalid SUBSYSTEM operation\n");
+                                goto invalid;
+                        }
+                        /* bus, class, subsystem events should all be the same */
+                        if (strcmp(value, "subsystem") == 0 ||
+                            strcmp(value, "bus") == 0 ||
+                            strcmp(value, "class") == 0) {
+                                if (strcmp(value, "bus") == 0 || strcmp(value, "class") == 0)
+                                        err(rules->udev, "'%s' must be specified as 'subsystem' \n"
+                                            "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 (strcmp(key, "DRIVER") == 0) {
+                        if (op > OP_MATCH_MAX) {
+                                err(rules->udev, "invalid DRIVER operation\n");
+                                goto invalid;
+                        }
+                        rule_add_key(&rule_tmp, TK_M_DRIVER, op, value, NULL);
+                        continue;
+                }
+
+                if (strncmp(key, "ATTR{", sizeof("ATTR{")-1) == 0) {
+                        attr = get_key_attribute(rules->udev, key + sizeof("ATTR")-1);
+                        if (attr == NULL) {
+                                err(rules->udev, "error parsing ATTR attribute\n");
+                                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 (strcmp(key, "KERNELS") == 0) {
+                        if (op > OP_MATCH_MAX) {
+                                err(rules->udev, "invalid KERNELS operation\n");
+                                goto invalid;
+                        }
+                        rule_add_key(&rule_tmp, TK_M_KERNELS, op, value, NULL);
+                        continue;
+                }
+
+                if (strcmp(key, "SUBSYSTEMS") == 0) {
+                        if (op > OP_MATCH_MAX) {
+                                err(rules->udev, "invalid SUBSYSTEMS operation\n");
+                                goto invalid;
+                        }
+                        rule_add_key(&rule_tmp, TK_M_SUBSYSTEMS, op, value, NULL);
+                        continue;
+                }
+
+                if (strcmp(key, "DRIVERS") == 0) {
+                        if (op > OP_MATCH_MAX) {
+                                err(rules->udev, "invalid DRIVERS operation\n");
+                                goto invalid;
+                        }
+                        rule_add_key(&rule_tmp, TK_M_DRIVERS, op, value, NULL);
+                        continue;
+                }
+
+                if (strncmp(key, "ATTRS{", sizeof("ATTRS{")-1) == 0) {
+                        if (op > OP_MATCH_MAX) {
+                                err(rules->udev, "invalid ATTRS operation\n");
+                                goto invalid;
+                        }
+                        attr = get_key_attribute(rules->udev, key + sizeof("ATTRS")-1);
+                        if (attr == NULL) {
+                                err(rules->udev, "error parsing ATTRS attribute\n");
+                                goto invalid;
+                        }
+                        if (strncmp(attr, "device/", 7) == 0)
+                                err(rules->udev, "the 'device' link may not be available in a future kernel, "
+                                    "please fix it in %s:%u", filename, lineno);
+                        else if (strstr(attr, "../") != NULL)
+                                err(rules->udev, "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 (strcmp(key, "TAGS") == 0) {
+                        if (op > OP_MATCH_MAX) {
+                                err(rules->udev, "invalid TAGS operation\n");
+                                goto invalid;
+                        }
+                        rule_add_key(&rule_tmp, TK_M_TAGS, op, value, NULL);
+                        continue;
+                }
+
+                if (strncmp(key, "ENV{", sizeof("ENV{")-1) == 0) {
+                        attr = get_key_attribute(rules->udev, key + sizeof("ENV")-1);
+                        if (attr == NULL) {
+                                err(rules->udev, "error parsing ENV attribute\n");
+                                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 < ARRAY_SIZE(blacklist); i++)
+                                        if (strcmp(attr, blacklist[i]) == 0) {
+                                                err(rules->udev, "invalid ENV attribute, '%s' can not be set %s:%u\n", attr, filename, lineno);
+                                                continue;
+                                        }
+                                if (rule_add_key(&rule_tmp, TK_A_ENV, op, value, attr) != 0)
+                                        goto invalid;
+                        }
+                        continue;
+                }
+
+                if (strcmp(key, "TAG") == 0) {
+                        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 (strcmp(key, "PROGRAM") == 0) {
+                        rule_add_key(&rule_tmp, TK_M_PROGRAM, op, value, NULL);
+                        continue;
+                }
+
+                if (strcmp(key, "RESULT") == 0) {
+                        if (op > OP_MATCH_MAX) {
+                                err(rules->udev, "invalid RESULT operation\n");
+                                goto invalid;
+                        }
+                        rule_add_key(&rule_tmp, TK_M_RESULT, op, value, NULL);
+                        continue;
+                }
+
+                if (strncmp(key, "IMPORT", sizeof("IMPORT")-1) == 0) {
+                        attr = get_key_attribute(rules->udev, key + sizeof("IMPORT")-1);
+                        if (attr == NULL) {
+                                err(rules->udev, "IMPORT{} type missing, ignoring IMPORT %s:%u\n", filename, lineno);
+                                continue;
+                        }
+                        if (strstr(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) {
+                                                info(rules->udev, "IMPORT found builtin '%s', replacing %s:%u\n",
+                                                     value, filename, lineno);
+                                                rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd);
+                                                continue;
+                                        }
+                                }
+                                dbg(rules->udev, "IMPORT will be executed\n");
+                                rule_add_key(&rule_tmp, TK_M_IMPORT_PROG, op, value, NULL);
+                        } else if (strstr(attr, "builtin")) {
+                                enum udev_builtin_cmd cmd = udev_builtin_lookup(value);
+
+                                dbg(rules->udev, "IMPORT execute builtin\n");
+                                if (cmd < UDEV_BUILTIN_MAX)
+                                        rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd);
+                                else
+                                        err(rules->udev, "IMPORT{builtin}: '%s' unknown %s:%u\n", value, filename, lineno);
+                        } else if (strstr(attr, "file")) {
+                                dbg(rules->udev, "IMPORT will be included as file\n");
+                                rule_add_key(&rule_tmp, TK_M_IMPORT_FILE, op, value, NULL);
+                        } else if (strstr(attr, "db")) {
+                                dbg(rules->udev, "IMPORT will include db values\n");
+                                rule_add_key(&rule_tmp, TK_M_IMPORT_DB, op, value, NULL);
+                        } else if (strstr(attr, "cmdline")) {
+                                dbg(rules->udev, "IMPORT will include db values\n");
+                                rule_add_key(&rule_tmp, TK_M_IMPORT_CMDLINE, op, value, NULL);
+                        } else if (strstr(attr, "parent")) {
+                                dbg(rules->udev, "IMPORT will include the parent values\n");
+                                rule_add_key(&rule_tmp, TK_M_IMPORT_PARENT, op, value, NULL);
+                        }
+                        continue;
+                }
+
+                if (strncmp(key, "TEST", sizeof("TEST")-1) == 0) {
+                        mode_t mode = 0;
+
+                        if (op > OP_MATCH_MAX) {
+                                err(rules->udev, "invalid TEST operation\n");
+                                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 (strcmp(key, "RUN") == 0) {
+                        if (strncmp(value, "socket:", 7) == 0)
+                                err(rules->udev, "RUN+=\"socket:...\" support will be removed from a future udev release. "
+                                    "Please remove it from: %s:%u and use libudev to subscribe to events.\n", filename, lineno);
+                        rule_add_key(&rule_tmp, TK_A_RUN, op, value, NULL);
+                        continue;
+                }
+
+                if (strcmp(key, "WAIT_FOR") == 0 || strcmp(key, "WAIT_FOR_SYSFS") == 0) {
+                        rule_add_key(&rule_tmp, TK_M_WAITFOR, 0, value, NULL);
+                        continue;
+                }
+
+                if (strcmp(key, "LABEL") == 0) {
+                        rule_tmp.rule.rule.label_off = add_string(rules, value);
+                        continue;
+                }
+
+                if (strcmp(key, "GOTO") == 0) {
+                        rule_add_key(&rule_tmp, TK_A_GOTO, 0, value, NULL);
+                        continue;
+                }
+
+                if (strncmp(key, "NAME", sizeof("NAME")-1) == 0) {
+                        if (op < OP_MATCH_MAX) {
+                                rule_add_key(&rule_tmp, TK_M_NAME, op, value, NULL);
+                        } else {
+                                if (strcmp(value, "%k") == 0) {
+                                        err(rules->udev, "NAME=\"%%k\" is ignored, because it breaks kernel supplied names, "
+                                            "please remove it from %s:%u\n", filename, lineno);
+                                        continue;
+                                }
+                                if (value[0] == '\0') {
+                                        info(rules->udev, "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 (strncmp(key, "SYMLINK", sizeof("SYMLINK")-1) == 0) {
+                        if (op < OP_MATCH_MAX) {
+                                rule_add_key(&rule_tmp, TK_M_DEVLINK, op, value, NULL);
+                        } else {
+                                int flag = 0;
+
+                                attr = get_key_attribute(rules->udev, key + sizeof("SYMLINK")-1);
+                                if (attr != NULL && strstr(attr, "unique") != NULL)
+                                        flag = 1;
+                                rule_add_key(&rule_tmp, TK_A_DEVLINK, op, value, &flag);
+                        }
+                        rule_tmp.rule.rule.can_set_name = true;
+                        continue;
+                }
+
+                if (strcmp(key, "OWNER") == 0) {
+                        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 (strcmp(key, "GROUP") == 0) {
+                        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 (strcmp(key, "MODE") == 0) {
+                        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 (strcmp(key, "OPTIONS") == 0) {
+                        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);
+                                dbg(rules->udev, "link priority=%i\n", 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);
+                                dbg(rules->udev, "event timeout=%i\n", tout);
+                        }
+
+                        pos = strstr(value, "string_escape=");
+                        if (pos != NULL) {
+                                pos = &pos[strlen("string_escape=")];
+                                if (strncmp(pos, "none", strlen("none")) == 0)
+                                        rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_NONE, op, NULL, NULL);
+                                else if (strncmp(pos, "replace", strlen("replace")) == 0)
+                                        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);
+                                dbg(rules->udev, "inotify watch of device disabled\n");
+                        } else {
+                                pos = strstr(value, "watch");
+                                if (pos != NULL) {
+                                        const int on = 1;
+
+                                        rule_add_key(&rule_tmp, TK_A_INOTIFY_WATCH, op, NULL, &on);
+                                        dbg(rules->udev, "inotify watch of device requested\n");
+                                }
+                        }
+
+                        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;
+                }
+
+                err(rules->udev, "unknown key '%s' in %s:%u\n", 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:
+        err(rules->udev, "invalid rule '%s:%u'\n", filename, lineno);
+        return -1;
+}
+
+static int parse_file(struct udev_rules *rules, const char *filename, unsigned short filename_off)
+{
+        FILE *f;
+        unsigned int first_token;
+        char line[UTIL_LINE_SIZE];
+        int line_nr = 0;
+        unsigned int i;
+
+        info(rules->udev, "reading '%s' as rules file\n", filename);
+
+        f = fopen(filename, "r");
+        if (f == NULL)
+                return -1;
+
+        first_token = rules->token_cur;
+
+        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)) {
+                        err(rules->udev, "line too long '%s':%u, ignored\n", 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->buf[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 (strcmp(label, &rules->buf[rules->tokens[j].rule.label_off]) != 0)
+                                        continue;
+                                rules->tokens[i].key.rule_goto = j;
+                                break;
+                        }
+                        if (rules->tokens[i].key.rule_goto == 0)
+                                err(rules->udev, "GOTO '%s' has no matching label in: '%s'\n", label, filename);
+                }
+        }
+        return 0;
+}
+
+static int add_matching_files(struct udev *udev, struct udev_list *file_list, const char *dirname, const char *suffix)
+{
+        DIR *dir;
+        struct dirent *dent;
+        char filename[UTIL_PATH_SIZE];
+
+        dbg(udev, "open directory '%s'\n", dirname);
+        dir = opendir(dirname);
+        if (dir == NULL) {
+                info(udev, "unable to open '%s': %m\n", dirname);
+                return -1;
+        }
+
+        for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+                if (dent->d_name[0] == '.')
+                        continue;
+
+                /* look for file matching with specified suffix */
+                if (suffix != NULL) {
+                        const char *ext;
+
+                        ext = strrchr(dent->d_name, '.');
+                        if (ext == NULL)
+                                continue;
+                        if (strcmp(ext, suffix) != 0)
+                                continue;
+                }
+                util_strscpyl(filename, sizeof(filename), dirname, "/", dent->d_name, NULL);
+                dbg(udev, "put file '%s' into list\n", filename);
+                /*
+                 * the basename is the key, the filename the value
+                 * identical basenames from different directories override each other
+                 * entries are sorted after basename
+                 */
+                udev_list_entry_add(file_list, dent->d_name, filename);
+        }
+
+        closedir(dir);
+        return 0;
+}
+
+struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names)
+{
+        struct udev_rules *rules;
+        struct udev_list file_list;
+        struct udev_list_entry *file_loop;
+        struct token end_token;
+        char **s;
+
+        rules = calloc(1, sizeof(struct udev_rules));
+        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) {
+                free(rules);
+                return NULL;
+        }
+        rules->token_max = PREALLOC_TOKEN;
+
+        rules->buf = malloc(PREALLOC_STRBUF);
+        if (rules->buf == NULL) {
+                free(rules->tokens);
+                free(rules);
+                return NULL;
+        }
+        rules->buf_max = PREALLOC_STRBUF;
+        /* offset 0 is always '\0' */
+        rules->buf[0] = '\0';
+        rules->buf_cur = 1;
+        dbg(udev, "prealloc %zu bytes tokens (%u * %zu bytes), %zu bytes buffer\n",
+            rules->token_max * sizeof(struct token), rules->token_max, sizeof(struct token), rules->buf_max);
+
+        rules->trie_nodes = malloc(PREALLOC_TRIE * sizeof(struct trie_node));
+        if (rules->trie_nodes == NULL) {
+                free(rules->buf);
+                free(rules->tokens);
+                free(rules);
+                return NULL;
+        }
+        rules->trie_nodes_max = PREALLOC_TRIE;
+        /* offset 0 is the trie root, with an empty string */
+        memset(rules->trie_nodes, 0x00, sizeof(struct trie_node));
+        rules->trie_nodes_cur = 1;
+
+        for (udev_get_rules_path(udev, &s, NULL); *s != NULL; s++)
+                add_matching_files(udev, &file_list, *s, ".rules");
+
+        /* add all filenames to the string buffer */
+        udev_list_entry_foreach(file_loop, udev_list_get_entry(&file_list)) {
+                const char *filename = udev_list_entry_get_value(file_loop);
+                unsigned int filename_off;
+
+                filename_off = add_string(rules, filename);
+                /* the offset in the rule is limited to unsigned short */
+                if (filename_off < USHRT_MAX)
+                        udev_list_entry_set_num(file_loop, filename_off);
+        }
+
+        /* parse all rules files */
+        udev_list_entry_foreach(file_loop, udev_list_get_entry(&file_list)) {
+                const char *filename = udev_list_entry_get_value(file_loop);
+                unsigned int filename_off = udev_list_entry_get_num(file_loop);
+                struct stat st;
+
+                if (stat(filename, &st) != 0) {
+                        err(udev, "can not find '%s': %m\n", filename);
+                        continue;
+                }
+                if (S_ISREG(st.st_mode) && st.st_size <= 0) {
+                        info(udev, "ignore empty '%s'\n", filename);
+                        continue;
+                }
+                if (S_ISCHR(st.st_mode)) {
+                        info(udev, "ignore masked '%s'\n", filename);
+                        continue;
+                }
+                parse_file(rules, filename, filename_off);
+        }
+        udev_list_cleanup(&file_list);
+
+        memset(&end_token, 0x00, sizeof(struct token));
+        end_token.type = TK_END;
+        add_token(rules, &end_token);
+
+        /* shrink allocated token and string buffer */
+        if (rules->token_cur < rules->token_max) {
+                struct token *tokens;
+
+                tokens = realloc(rules->tokens, rules->token_cur * sizeof(struct token));
+                if (tokens != NULL || rules->token_cur == 0) {
+                        rules->tokens = tokens;
+                        rules->token_max = rules->token_cur;
+                }
+        }
+        if (rules->buf_cur < rules->buf_max) {
+                char *buf;
+
+                buf = realloc(rules->buf, rules->buf_cur);
+                if (buf != NULL || rules->buf_cur == 0) {
+                        rules->buf = buf;
+                        rules->buf_max = rules->buf_cur;
+                }
+        }
+        info(udev, "rules use %zu bytes tokens (%u * %zu bytes), %zu bytes buffer\n",
+             rules->token_max * sizeof(struct token), rules->token_max, sizeof(struct token), rules->buf_max);
+        info(udev, "temporary index used %zu bytes (%u * %zu bytes)\n",
+             rules->trie_nodes_cur * sizeof(struct trie_node),
+             rules->trie_nodes_cur, sizeof(struct trie_node));
+
+        /* cleanup trie */
+        free(rules->trie_nodes);
+        rules->trie_nodes = NULL;
+        rules->trie_nodes_cur = 0;
+        rules->trie_nodes_max = 0;
+
+        /* 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);
+        free(rules->buf);
+        free(rules->trie_nodes);
+        free(rules->uids);
+        free(rules->gids);
+        free(rules);
+        return NULL;
+}
+
+static int match_key(struct udev_rules *rules, struct token *token, const char *val)
+{
+        char *key_value = &rules->buf[token->key.value_off];
+        char *pos;
+        bool match = false;
+
+        if (val == NULL)
+                val = "";
+
+        switch (token->key.glob) {
+        case GL_PLAIN:
+                match = (strcmp(key_value, val) == 0);
+                break;
+        case GL_GLOB:
+                match = (fnmatch(key_value, val, 0) == 0);
+                break;
+        case GL_SPLIT:
+                {
+                        const char *split;
+                        size_t len;
+
+                        split = &rules->buf[token->key.value_off];
+                        len = strlen(val);
+                        for (;;) {
+                                const char *next;
+
+                                next = strchr(split, '|');
+                                if (next != NULL) {
+                                        size_t matchlen = (size_t)(next - split);
+
+                                        match = (matchlen == len && strncmp(split, val, matchlen) == 0);
+                                        if (match)
+                                                break;
+                                } else {
+                                        match = (strcmp(split, val) == 0);
+                                        break;
+                                }
+                                split = &next[1];
+                        }
+                        break;
+                }
+        case GL_SPLIT_GLOB:
+                {
+                        char value[UTIL_PATH_SIZE];
+
+                        util_strscpy(value, sizeof(value), &rules->buf[token->key.value_off]);
+                        key_value = value;
+                        while (key_value != NULL) {
+                                pos = strchr(key_value, '|');
+                                if (pos != NULL) {
+                                        pos[0] = '\0';
+                                        pos = &pos[1];
+                                }
+                                dbg(rules->udev, "match %s '%s' <-> '%s'\n", token_str(token->type), key_value, val);
+                                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)) {
+                dbg(rules->udev, "%s is true (matching value)\n", token_str(token->type));
+                return 0;
+        }
+        if (!match && (token->key.op == OP_NOMATCH)) {
+                dbg(rules->udev, "%s is true (non-matching value)\n", token_str(token->type));
+                return 0;
+        }
+        dbg(rules->udev, "%s is not true\n", token_str(token->type));
+        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->buf[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->buf[cur->key.value_off];
+                klen = strlen(key_value);
+                if (klen > 0 && !isspace(key_value[klen-1])) {
+                        if (value != vbuf) {
+                                util_strscpy(vbuf, sizeof(vbuf), value);
+                                value = vbuf;
+                        }
+                        while (len > 0 && isspace(vbuf[--len]))
+                                vbuf[len] = '\0';
+                        dbg(rules->udev, "removed trailing whitespace from '%s'\n", value);
+                }
+        }
+
+        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 = ((strcmp(udev_device_get_action(event->dev), "remove") != 0) &&
+                        (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: {
+                        size_t devlen = strlen(udev_get_dev_path(event->udev))+1;
+                        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)[devlen];
+                                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->buf[cur->key.attr_off];
+                        const char *value;
+
+                        value = udev_device_get_property_value(event->dev, key_name);
+                        if (value == NULL) {
+                                dbg(event->udev, "ENV{%s} is not set, treat as empty\n", key_name);
+                                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 (strcmp(&rules->buf[cur->key.value_off], udev_list_entry_get_name(list_entry)) == 0) {
+                                        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->buf[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;
+
+                                dbg(event->udev, "parent: '%s'\n", udev_device_get_syspath(event->dev_parent));
+                                /* 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->buf[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;
+                                        }
+                                        dbg(event->udev, "parent key matched\n");
+                                }
+                                dbg(event->udev, "all parent keys matched\n");
+                                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->buf[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];
+
+                                        util_strscpy(tmp, sizeof(tmp), filename);
+                                        util_strscpyl(filename, sizeof(filename),
+                                                      udev_device_get_syspath(event->dev), "/", tmp, NULL);
+                                }
+                        }
+                        attr_subst_subdir(filename, sizeof(filename));
+
+                        match = (stat(filename, &statbuf) == 0);
+                        dbg(event->udev, "'%s' %s", filename, match ? "exists\n" : "does not exist\n");
+                        if (match && cur->key.mode > 0) {
+                                match = ((statbuf.st_mode & cur->key.mode) > 0);
+                                dbg(event->udev, "'%s' has mode=%#o and %s %#o\n", filename, statbuf.st_mode,
+                                    match ? "matches" : "does not match", cur->key.mode);
+                        }
+                        if (match && cur->key.op == OP_NOMATCH)
+                                goto nomatch;
+                        if (!match && cur->key.op == OP_MATCH)
+                                goto nomatch;
+                        break;
+                }
+                case TK_M_EVENT_TIMEOUT:
+                        info(event->udev, "OPTIONS event_timeout=%u\n", 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->buf[cur->key.value_off], program, sizeof(program));
+                        envp = udev_device_get_properties_envp(event->dev);
+                        info(event->udev, "PROGRAM '%s' %s:%u\n",
+                             program,
+                             &rules->buf[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)
+                                                info(event->udev, "%i character(s) replaced\n" , count);
+                                }
+                                event->program_result = strdup(result);
+                                dbg(event->udev, "storing result '%s'\n", event->program_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->buf[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->buf[cur->key.value_off], import, sizeof(import));
+                        info(event->udev, "IMPORT '%s' %s:%u\n",
+                             import,
+                             &rules->buf[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)) {
+                                        info(event->udev, "IMPORT builtin skip '%s' %s:%u\n",
+                                             udev_builtin_name(cur->key.builtin_cmd),
+                                             &rules->buf[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->buf[cur->key.value_off], command, sizeof(command));
+                        info(event->udev, "IMPORT builtin '%s' %s:%u\n",
+                             udev_builtin_name(cur->key.builtin_cmd),
+                             &rules->buf[rule->rule.filename_off],
+                             rule->rule.filename_line);
+
+                        if (udev_builtin_run(event->dev, cur->key.builtin_cmd, command, false) != 0) {
+                                /* remember failure */
+                                info(rules->udev, "IMPORT builtin '%s' returned non-zero\n",
+                                     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->buf[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", "r");
+                        if (f != NULL) {
+                                char cmdline[4096];
+
+                                if (fgets(cmdline, sizeof(cmdline), f) != NULL) {
+                                        const char *key = &rules->buf[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->buf[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->buf[cur->key.value_off], owner, sizeof(owner));
+                        event->uid = util_lookup_user(event->udev, owner);
+                        info(event->udev, "OWNER %u %s:%u\n",
+                             event->uid,
+                             &rules->buf[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->buf[cur->key.value_off], group, sizeof(group));
+                        event->gid = util_lookup_group(event->udev, group);
+                        info(event->udev, "GROUP %u %s:%u\n",
+                             event->gid,
+                             &rules->buf[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->buf[cur->key.value_off], mode_str, sizeof(mode_str));
+                        mode = strtol(mode_str, &endptr, 8);
+                        if (endptr[0] != '\0') {
+                                err(event->udev, "ignoring invalid mode '%s'\n", mode_str);
+                                break;
+                        }
+                        if (cur->key.op == OP_ASSIGN_FINAL)
+                                event->mode_final = true;
+                        event->mode_set = true;
+                        event->mode = mode;
+                        info(event->udev, "MODE %#o %s:%u\n",
+                             event->mode,
+                             &rules->buf[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->uid = cur->key.uid;
+                        info(event->udev, "OWNER %u %s:%u\n",
+                             event->uid,
+                             &rules->buf[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->gid = cur->key.gid;
+                        info(event->udev, "GROUP %u %s:%u\n",
+                             event->gid,
+                             &rules->buf[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;
+                        info(event->udev, "MODE %#o %s:%u\n",
+                             event->mode,
+                             &rules->buf[rule->rule.filename_off],
+                             rule->rule.filename_line);
+                        break;
+                case TK_A_ENV: {
+                        const char *name = &rules->buf[cur->key.attr_off];
+                        char *value = &rules->buf[cur->key.value_off];
+
+                        if (value[0] != '\0') {
+                                char temp_value[UTIL_NAME_SIZE];
+                                struct udev_list_entry *entry;
+
+                                udev_event_apply_format(event, value, temp_value, sizeof(temp_value));
+                                entry = udev_device_add_property(event->dev, name, temp_value);
+                                /* store in db, skip private keys */
+                                if (name[0] != '.')
+                                        udev_list_entry_set_num(entry, true);
+                        } else {
+                                udev_device_add_property(event->dev, name, NULL);
+                        }
+                        break;
+                }
+                case TK_A_TAG: {
+                        char tag[UTIL_PATH_SIZE];
+                        const char *p;
+
+                        udev_event_apply_format(event, &rules->buf[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;
+                                err(event->udev, "ignoring invalid tag name '%s'\n", tag);
+                                break;
+                        }
+                        udev_device_add_tag(event->dev, tag);
+                        break;
+                }
+                case TK_A_NAME: {
+                        const char *name  = &rules->buf[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)
+                                        info(event->udev, "%i character(s) replaced\n", count);
+                        }
+                        if (major(udev_device_get_devnum(event->dev))) {
+                                size_t devlen = strlen(udev_get_dev_path(event->udev))+1;
+
+                                if (strcmp(name_str, &udev_device_get_devnode(event->dev)[devlen]) != 0) {
+                                        err(event->udev, "NAME=\"%s\" ignored, kernel device nodes "
+                                            "can not be renamed; please fix it in %s:%u\n", name,
+                                            &rules->buf[rule->rule.filename_off], rule->rule.filename_line);
+                                        break;
+                                }
+                        }
+                        free(event->name);
+                        event->name = strdup(name_str);
+                        info(event->udev, "NAME '%s' %s:%u\n",
+                             event->name,
+                             &rules->buf[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->buf[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)
+                                info(event->udev, "%i character(s) replaced\n" , count);
+                        dbg(event->udev, "rule applied, added symlink(s) '%s'\n", temp);
+                        pos = temp;
+                        while (isspace(pos[0]))
+                                pos++;
+                        next = strchr(pos, ' ');
+                        while (next != NULL) {
+                                next[0] = '\0';
+                                info(event->udev, "LINK '%s' %s:%u\n", pos,
+                                     &rules->buf[rule->rule.filename_off], rule->rule.filename_line);
+                                util_strscpyl(filename, sizeof(filename), udev_get_dev_path(event->udev), "/", pos, NULL);
+                                udev_device_add_devlink(event->dev, filename, cur->key.devlink_unique);
+                                while (isspace(next[1]))
+                                        next++;
+                                pos = &next[1];
+                                next = strchr(pos, ' ');
+                        }
+                        if (pos[0] != '\0') {
+                                info(event->udev, "LINK '%s' %s:%u\n", pos,
+                                     &rules->buf[rule->rule.filename_off], rule->rule.filename_line);
+                                util_strscpyl(filename, sizeof(filename), udev_get_dev_path(event->udev), "/", pos, NULL);
+                                udev_device_add_devlink(event->dev, filename, cur->key.devlink_unique);
+                        }
+                        break;
+                }
+                case TK_A_ATTR: {
+                        const char *key_name = &rules->buf[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)
+                                util_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->buf[cur->key.value_off], value, sizeof(value));
+                        info(event->udev, "ATTR '%s' writing '%s' %s:%u\n", attr, value,
+                             &rules->buf[rule->rule.filename_off],
+                             rule->rule.filename_line);
+                        f = fopen(attr, "w");
+                        if (f != NULL) {
+                                if (fprintf(f, "%s", value) <= 0)
+                                        err(event->udev, "error writing ATTR{%s}: %m\n", attr);
+                                fclose(f);
+                        } else {
+                                err(event->udev, "error opening ATTR{%s} for writing: %m\n", attr);
+                        }
+                        break;
+                }
+                case TK_A_RUN: {
+                        if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL)
+                                udev_list_cleanup(&event->run_list);
+                        info(event->udev, "RUN '%s' %s:%u\n",
+                             &rules->buf[cur->key.value_off],
+                             &rules->buf[rule->rule.filename_off],
+                             rule->rule.filename_line);
+                        udev_list_entry_add(&event->run_list, &rules->buf[cur->key.value_off], NULL);
+                        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:
+                        err(rules->udev, "wrong type %u\n", cur->type);
+                        goto nomatch;
+                }
+
+                cur++;
+                continue;
+        nomatch:
+                /* fast-forward to next rule */
+                cur = rule + rule->rule.token_count;
+                dbg(rules->udev, "forward to rule: %u\n",
+                                 (unsigned int) (cur - rules->tokens));
+        }
+}
+
+void 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;
+
+        if (rules->tokens == NULL)
+                return;
+
+        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;
+                        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_STATIC_NODE: {
+                        char filename[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)
+                                goto next;
+                        util_strscpyl(filename, sizeof(filename), udev_get_dev_path(rules->udev), "/",
+                                      &rules->buf[cur->key.value_off], NULL);
+                        if (stat(filename, &stats) != 0)
+                                goto next;
+                        if (!S_ISBLK(stats.st_mode) && !S_ISCHR(stats.st_mode))
+                                goto next;
+                        if (mode == 0) {
+                                if (gid > 0)
+                                        mode = 0660;
+                                else
+                                        mode = 0600;
+                        }
+                        if (mode != (stats.st_mode & 01777)) {
+                                chmod(filename, mode);
+                                info(rules->udev, "chmod '%s' %#o\n", filename, mode);
+                        }
+
+                        if ((uid != 0 && uid != stats.st_uid) || (gid != 0 && gid != stats.st_gid)) {
+                                chown(filename, uid, gid);
+                                info(rules->udev, "chown '%s' %u %u\n", filename, uid, gid);
+                        }
+
+                        utimensat(AT_FDCWD, filename, NULL, 0);
+                        break;
+                }
+                case TK_END:
+                        return;
+                }
+
+                cur++;
+                continue;
+next:
+                /* fast-forward to next rule */
+                cur = rule + rule->rule.token_count;
+                continue;
+        }
+}
diff --git a/src/udev/udev-watch.c b/src/udev/udev-watch.c
new file mode 100644 (file)
index 0000000..228d18f
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2004-2010 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2009 Canonical Ltd.
+ * Copyright (C) 2009 Scott James Remnant <scott@netsplit.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/inotify.h>
+
+#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)
+                err(udev, "inotify_init failed: %m\n");
+        return inotify_fd;
+}
+
+/* move any old watches directory out of the way, and then restore
+ * the watches
+ */
+void udev_watch_restore(struct udev *udev)
+{
+        char filename[UTIL_PATH_SIZE], oldname[UTIL_PATH_SIZE];
+
+        if (inotify_fd < 0)
+                return;
+
+        util_strscpyl(oldname, sizeof(oldname), udev_get_run_path(udev), "/watch.old", NULL);
+        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/watch", NULL);
+        if (rename(filename, oldname) == 0) {
+                DIR *dir;
+                struct dirent *ent;
+
+                dir = opendir(oldname);
+                if (dir == NULL) {
+                        err(udev, "unable to open old watches dir '%s', old watches will not be restored: %m", oldname);
+                        return;
+                }
+
+                for (ent = readdir(dir); ent != NULL; ent = readdir(dir)) {
+                        char device[UTIL_PATH_SIZE];
+                        char *s;
+                        size_t l;
+                        ssize_t len;
+                        struct udev_device *dev;
+
+                        if (ent->d_name[0] == '.')
+                                continue;
+
+                        s = device;
+                        l = util_strpcpy(&s, sizeof(device), udev_get_sys_path(udev));
+                        len = readlinkat(dirfd(dir), ent->d_name, s, l);
+                        if (len <= 0 || len == (ssize_t)l)
+                                goto unlink;
+                        s[len] = '\0';
+
+                        dev = udev_device_new_from_id_filename(udev, s);
+                        if (dev == NULL)
+                                goto unlink;
+
+                        info(udev, "restoring old watch on '%s'\n", 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(oldname);
+
+        } else if (errno != ENOENT) {
+                err(udev, "unable to move watches dir '%s', old watches will not be restored: %m", filename);
+        }
+}
+
+void udev_watch_begin(struct udev *udev, struct udev_device *dev)
+{
+        char filename[UTIL_PATH_SIZE];
+        int wd;
+
+        if (inotify_fd < 0)
+                return;
+
+        info(udev, "adding watch on '%s'\n", udev_device_get_devnode(dev));
+        wd = inotify_add_watch(inotify_fd, udev_device_get_devnode(dev), IN_CLOSE_WRITE);
+        if (wd < 0) {
+                err(udev, "inotify_add_watch(%d, %s, %o) failed: %m\n",
+                    inotify_fd, udev_device_get_devnode(dev), IN_CLOSE_WRITE);
+                return;
+        }
+
+        snprintf(filename, sizeof(filename), "%s/watch/%d", udev_get_run_path(udev), wd);
+        util_create_path(udev, filename);
+        unlink(filename);
+        symlink(udev_device_get_id_filename(dev), 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;
+
+        info(udev, "removing watch on '%s'\n", udev_device_get_devnode(dev));
+        inotify_rm_watch(inotify_fd, wd);
+
+        snprintf(filename, sizeof(filename), "%s/watch/%d", udev_get_run_path(udev), 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 majmin[UTIL_PATH_SIZE];
+        char *s;
+        size_t l;
+        ssize_t len;
+
+        if (inotify_fd < 0 || wd < 0)
+                return NULL;
+
+        snprintf(filename, sizeof(filename), "%s/watch/%d", udev_get_run_path(udev), wd);
+        s = majmin;
+        l = util_strpcpy(&s, sizeof(majmin), udev_get_sys_path(udev));
+        len = readlink(filename, s, l);
+        if (len <= 0 || (size_t)len == l)
+                return NULL;
+        s[len] = '\0';
+
+        return udev_device_new_from_id_filename(udev, s);
+}
diff --git a/src/udev/udev.conf b/src/udev/udev.conf
new file mode 100644 (file)
index 0000000..f39253e
--- /dev/null
@@ -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 (file)
index 0000000..bc051c9
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2003-2010 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _UDEV_H_
+#define _UDEV_H_
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <signal.h>
+
+#include "libudev.h"
+#include "libudev-private.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 run_list;
+        int exec_delay;
+        unsigned long long birth_usec;
+        unsigned long long timeout_usec;
+        int fd_signal;
+        unsigned int builtin_run;
+        unsigned int builtin_ret;
+        bool sigterm;
+        bool inotify_watch;
+        bool inotify_watch_final;
+        bool group_final;
+        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);
+int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event, const sigset_t *sigmask);
+void 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);
+int 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, mode_t mode, uid_t uid, gid_t gid);
+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_ref(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_ref(struct udev_ctrl_msg *ctrl_msg);
+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 {
+        UDEV_BUILTIN_BLKID,
+        UDEV_BUILTIN_FIRMWARE,
+        UDEV_BUILTIN_INPUT_ID,
+        UDEV_BUILTIN_KMOD,
+        UDEV_BUILTIN_PATH_ID,
+        UDEV_BUILTIN_PCI_DB,
+        UDEV_BUILTIN_USB_DB,
+        UDEV_BUILTIN_USB_ID,
+        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;
+};
+extern const struct udev_builtin udev_builtin_blkid;
+extern const struct udev_builtin udev_builtin_firmware;
+extern const struct udev_builtin udev_builtin_input_id;
+extern const struct udev_builtin udev_builtin_kmod;
+extern const struct udev_builtin udev_builtin_path_id;
+extern const struct udev_builtin udev_builtin_pci_db;
+extern const struct udev_builtin udev_builtin_usb_db;
+extern const struct udev_builtin udev_builtin_usb_id;
+int 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);
+int udev_builtin_add_property(struct udev_device *dev, bool test, const char *key, const char *val);
+
+/* 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);
+
+/* 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_test;
+extern const struct udevadm_cmd udevadm_test_builtin;
+#endif
diff --git a/src/udev/udev.pc.in b/src/udev/udev.pc.in
new file mode 100644 (file)
index 0000000..0b04c02
--- /dev/null
@@ -0,0 +1,5 @@
+Name: udev
+Description: udev
+Version: @VERSION@
+
+udevdir=@pkglibexecdir@
diff --git a/src/udev/udevadm-control.c b/src/udev/udevadm-control.c
new file mode 100644 (file)
index 0000000..cafa214
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2005-2011 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <time.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+
+#include "udev.h"
+
+static void print_help(void)
+{
+        printf("Usage: udevadm control COMMAND\n"
+                "  --exit                   instruct the daemon to cleanup and exit\n"
+                "  --log-priority=<level>   set the udev log level for the daemon\n"
+                "  --stop-exec-queue        do not execute events, queue only\n"
+                "  --start-exec-queue       execute events, flush queue\n"
+                "  --reload                 reload rules and databases\n"
+                "  --property=<KEY>=<value> set a global property for all events\n"
+                "  --children-max=<N>       maximum number of children\n"
+                "  --timeout=<seconds>      maximum time to block for a reply\n"
+                "  --help                   print this help text\n\n");
+}
+
+static int adm_control(struct udev *udev, int argc, char *argv[])
+{
+        struct udev_ctrl *uctrl = NULL;
+        int timeout = 60;
+        int rc = 1;
+
+        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' },
+                { "property", required_argument, NULL, 'p' },
+                { "env", required_argument, NULL, '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;
+
+        for (;;) {
+                int option;
+
+                option = getopt_long(argc, argv, "el:sSRp:m:h", options, NULL);
+                if (option == -1)
+                        break;
+
+                switch (option) {
+                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);
+                                goto out;
+                        }
+                        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 <KEY>=<value> instead of '%s'\n", optarg);
+                                goto out;
+                        }
+                        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);
+                                goto out;
+                        }
+                        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 (argv[optind] != NULL)
+                fprintf(stderr, "unknown option\n");
+        else if (optind == 1)
+                fprintf(stderr, "missing option\n");
+out:
+        udev_ctrl_unref(uctrl);
+        return rc;
+}
+
+const struct udevadm_cmd udevadm_control = {
+        .name = "control",
+        .cmd = adm_control,
+        .help = "control the udev daemon",
+};
diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c
new file mode 100644 (file)
index 0000000..ee9b59f
--- /dev/null
@@ -0,0 +1,568 @@
+/*
+ * Copyright (C) 2004-2009 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "udev.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 < ARRAY_SIZE(skip); i++)
+                if (strcmp(name, skip[i]) == 0)
+                        return true;
+        return false;
+}
+
+static void print_all_attributes(struct udev_device *device, const char *key)
+{
+        struct udev *udev = udev_device_get_udev(device);
+        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;
+                dbg(udev, "attr '%s'='%s'\n", name, value);
+
+                /* 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) {
+                        dbg(udev, "attribute value of '%s' non-printable, skip\n", name);
+                        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)
+{
+        size_t len;
+        const char *str;
+        int i;
+        struct udev_list_entry *list_entry;
+
+        printf("P: %s\n", udev_device_get_devpath(device));
+
+        len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
+        str = udev_device_get_devnode(device);
+        if (str != NULL)
+                printf("N: %s\n", &str[len+1]);
+
+        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)) {
+                len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
+                printf("S: %s\n", &udev_list_entry_get_name(list_entry)[len+1]);
+        }
+
+        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)
+{
+        char filename[UTIL_PATH_SIZE];
+        DIR *dir;
+
+        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/queue.bin", NULL);
+        unlink(filename);
+
+        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/data", NULL);
+        dir = opendir(filename);
+        if (dir != NULL) {
+                cleanup_dir(dir, S_ISVTX, 1);
+                closedir(dir);
+        }
+
+        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/links", NULL);
+        dir = opendir(filename);
+        if (dir != NULL) {
+                cleanup_dir(dir, 0, 2);
+                closedir(dir);
+        }
+
+        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/tags", NULL);
+        dir = opendir(filename);
+        if (dir != NULL) {
+                cleanup_dir(dir, 0, 2);
+                closedir(dir);
+        }
+
+        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/watch", NULL);
+        dir = opendir(filename);
+        if (dir != NULL) {
+                cleanup_dir(dir, 0, 1);
+                closedir(dir);
+        }
+
+        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/firmware-missing", NULL);
+        dir = opendir(filename);
+        if (dir != NULL) {
+                cleanup_dir(dir, 0, 1);
+                closedir(dir);
+        }
+}
+
+static int uinfo(struct udev *udev, int argc, char *argv[])
+{
+        struct udev_device *device = NULL;
+        bool root = 0;
+        bool export = 0;
+        const char *export_prefix = NULL;
+        char path[UTIL_PATH_SIZE];
+        char name[UTIL_PATH_SIZE];
+        struct udev_list_entry *list_entry;
+        int rc = 0;
+
+        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' },
+                { "run", 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' },
+                {}
+        };
+
+        enum action_type {
+                ACTION_NONE,
+                ACTION_QUERY,
+                ACTION_ATTRIBUTE_WALK,
+                ACTION_ROOT,
+                ACTION_DEVICE_ID_FILE,
+        } action = ACTION_NONE;
+
+        enum query_type {
+                QUERY_NONE,
+                QUERY_NAME,
+                QUERY_PATH,
+                QUERY_SYMLINK,
+                QUERY_PROPERTY,
+                QUERY_ALL,
+        } query = QUERY_NONE;
+
+        for (;;) {
+                int option;
+                struct stat statbuf;
+
+                option = getopt_long(argc, argv, "aced:n:p:q:rxP:RVh", options, NULL);
+                if (option == -1)
+                        break;
+
+                dbg(udev, "option '%c'\n", option);
+                switch (option) {
+                case 'n':
+                        if (device != NULL) {
+                                fprintf(stderr, "device already specified\n");
+                                rc = 2;
+                                goto exit;
+                        }
+                        /* remove /dev if given */
+                        if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0)
+                                util_strscpyl(name, sizeof(name), udev_get_dev_path(udev), "/", optarg, NULL);
+                        else
+                                util_strscpy(name, sizeof(name), optarg);
+                        util_remove_trailing_chars(name, '/');
+                        if (stat(name, &statbuf) < 0) {
+                                fprintf(stderr, "device node not found\n");
+                                rc = 2;
+                                goto exit;
+                        } else {
+                                char type;
+
+                                if (S_ISBLK(statbuf.st_mode)) {
+                                        type = 'b';
+                                } else if (S_ISCHR(statbuf.st_mode)) {
+                                        type = 'c';
+                                } else {
+                                        fprintf(stderr, "device node has wrong file type\n");
+                                        rc = 2;
+                                        goto exit;
+                                }
+                                device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
+                                if (device == NULL) {
+                                        fprintf(stderr, "device node not found\n");
+                                        rc = 2;
+                                        goto exit;
+                                }
+                        }
+                        break;
+                case 'p':
+                        if (device != NULL) {
+                                fprintf(stderr, "device already specified\n");
+                                rc = 2;
+                                goto exit;
+                        }
+                        /* add sys dir if needed */
+                        if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
+                                util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), optarg, NULL);
+                        else
+                                util_strscpy(path, sizeof(path), optarg);
+                        util_remove_trailing_chars(path, '/');
+                        device = udev_device_new_from_syspath(udev, path);
+                        if (device == NULL) {
+                                fprintf(stderr, "device path not found\n");
+                                rc = 2;
+                                goto exit;
+                        }
+                        break;
+                case 'q':
+                        action = ACTION_QUERY;
+                        if (strcmp(optarg, "property") == 0 || strcmp(optarg, "env") == 0) {
+                                query = QUERY_PROPERTY;
+                        } else if (strcmp(optarg, "name") == 0) {
+                                query = QUERY_NAME;
+                        } else if (strcmp(optarg, "symlink") == 0) {
+                                query = QUERY_SYMLINK;
+                        } else if (strcmp(optarg, "path") == 0) {
+                                query = QUERY_PATH;
+                        } else if (strcmp(optarg, "all") == 0) {
+                                query = QUERY_ALL;
+                        } else {
+                                fprintf(stderr, "unknown query type\n");
+                                rc = 3;
+                                goto exit;
+                        }
+                        break;
+                case 'r':
+                        if (action == ACTION_NONE)
+                                action = ACTION_ROOT;
+                        root = true;
+                        break;
+                case 'R':
+                        printf("%s\n", udev_get_run_path(udev));
+                        goto exit;
+                case 'd':
+                        action = ACTION_DEVICE_ID_FILE;
+                        util_strscpy(name, sizeof(name), optarg);
+                        break;
+                case 'a':
+                        action = ACTION_ATTRIBUTE_WALK;
+                        break;
+                case 'e':
+                        export_devices(udev);
+                        goto exit;
+                case 'c':
+                        cleanup_db(udev);
+                        goto exit;
+                case 'x':
+                        export = true;
+                        break;
+                case 'P':
+                        export_prefix = optarg;
+                        break;
+                case 'V':
+                        printf("%s\n", VERSION);
+                        goto exit;
+                case 'h':
+                        printf("Usage: udevadm info OPTIONS\n"
+                               "  --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"
+                               "  --path=<syspath>           sys device path used for query or attribute walk\n"
+                               "  --name=<name>              node or symlink name used for query or attribute walk\n"
+                               "  --root                     prepend dev directory to path names\n"
+                               "  --attribute-walk           print all key matches while walking along the chain\n"
+                               "                             of parent devices\n"
+                               "  --device-id-of-file=<file> print major:minor of device containing this file\n"
+                               "  --export                   export key/value pairs\n"
+                               "  --export-prefix            export the key name with a prefix\n"
+                               "  --export-db                export the content of the udev database\n"
+                               "  --cleanup-db               cleanup the udev database\n"
+                               "  --help\n\n");
+                        goto exit;
+                default:
+                        rc = 1;
+                        goto exit;
+                }
+        }
+
+        switch (action) {
+        case ACTION_QUERY:
+                if (device == NULL) {
+                        fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
+                        rc = 4;
+                        goto exit;
+                }
+
+                switch(query) {
+                case QUERY_NAME: {
+                        const char *node = udev_device_get_devnode(device);
+
+                        if (node == NULL) {
+                                fprintf(stderr, "no device node found\n");
+                                rc = 5;
+                                goto exit;
+                        }
+
+                        if (root) {
+                                printf("%s\n", udev_device_get_devnode(device));
+                        } else {
+                                size_t len = strlen(udev_get_dev_path(udev));
+
+                                printf("%s\n", &udev_device_get_devnode(device)[len+1]);
+                        }
+                        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 {
+                                        size_t len;
+
+                                        len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
+                                        printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
+                                }
+                                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));
+                        goto exit;
+                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 == NULL) {
+                        fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
+                        rc = 4;
+                        goto exit;
+                }
+                print_device_chain(device);
+                break;
+        case ACTION_DEVICE_ID_FILE:
+                if (stat_device(name, export, export_prefix) != 0)
+                        rc = 1;
+                break;
+        case ACTION_ROOT:
+                printf("%s\n", udev_get_dev_path(udev));
+                break;
+        default:
+                fprintf(stderr, "missing option\n");
+                rc = 1;
+                break;
+        }
+
+exit:
+        udev_device_unref(device);
+        return rc;
+}
+
+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 (file)
index 0000000..5997dd8
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2004-2010 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#include <getopt.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/epoll.h>
+#include <linux/types.h>
+#include <linux/netlink.h>
+
+#include "udev.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 int adm_monitor(struct udev *udev, int argc, char *argv[])
+{
+        struct sigaction act;
+        sigset_t mask;
+        int option;
+        bool prop = false;
+        bool print_kernel = false;
+        bool print_udev = false;
+        struct udev_list subsystem_match_list;
+        struct udev_list tag_match_list;
+        struct udev_monitor *udev_monitor = NULL;
+        struct udev_monitor *kernel_monitor = NULL;
+        int fd_ep = -1;
+        int fd_kernel = -1, fd_udev = -1;
+        struct epoll_event ep_kernel, ep_udev;
+        int rc = 0;
+
+        static const struct option options[] = {
+                { "property", no_argument, NULL, 'p' },
+                { "environment", no_argument, NULL, 'e' },
+                { "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);
+
+        for (;;) {
+                option = getopt_long(argc, argv, "pekus:t:h", options, NULL);
+                if (option == -1)
+                        break;
+
+                switch (option) {
+                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;
+
+                                util_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':
+                        printf("Usage: udevadm monitor [--property] [--kernel] [--udev] [--help]\n"
+                               "  --property                              print the event properties\n"
+                               "  --kernel                                print kernel uevents\n"
+                               "  --udev                                  print udev events\n"
+                               "  --subsystem-match=<subsystem[/devtype]> filter events by subsystem\n"
+                               "  --tag-match=<tag>                       filter events by tag\n"
+                               "  --help\n\n");
+                        goto out;
+                default:
+                        rc = 1;
+                        goto out;
+                }
+        }
+
+        if (!print_kernel && !print_udev) {
+                print_kernel = true;
+                print_udev = true;
+        }
+
+        /* set signal handlers */
+        memset(&act, 0x00, sizeof(struct sigaction));
+        act.sa_handler = sig_handler;
+        sigemptyset(&act.sa_mask);
+        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) {
+                err(udev, "error creating epoll fd: %m\n");
+                goto out;
+        }
+
+        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");
+                        rc = 1;
+                        goto out;
+                }
+                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");
+                        rc = 2;
+                        goto out;
+                }
+
+                memset(&ep_udev, 0, 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) {
+                        err(udev, "fail to add fd to epoll: %m\n");
+                        goto out;
+                }
+
+                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");
+                        rc = 3;
+                        goto out;
+                }
+                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");
+                        rc = 4;
+                        goto out;
+                }
+
+                memset(&ep_kernel, 0, 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) {
+                        err(udev, "fail to add fd to epoll: %m\n");
+                        goto out;
+                }
+
+                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, ARRAY_SIZE(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);
+                        }
+                }
+        }
+out:
+        if (fd_ep >= 0)
+                close(fd_ep);
+        udev_monitor_unref(udev_monitor);
+        udev_monitor_unref(kernel_monitor);
+        udev_list_cleanup(&subsystem_match_list);
+        udev_list_cleanup(&tag_match_list);
+        return rc;
+}
+
+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 (file)
index 0000000..b168def
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2006-2009 Kay Sievers <kay@vrfy.org>
+ * Copyright (C) 2009 Canonical Ltd.
+ * Copyright (C) 2009 Scott James Remnant <scott@netsplit.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <getopt.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/inotify.h>
+#include <sys/poll.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "udev.h"
+
+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' },
+                {}
+        };
+        unsigned long long start_usec = now_usec();
+        unsigned long long start = 0;
+        unsigned long long end = 0;
+        int quiet = 0;
+        const char *exists = NULL;
+        unsigned int timeout = 120;
+        struct pollfd pfd[1];
+        struct udev_queue *udev_queue = NULL;
+        int rc = EXIT_FAILURE;
+
+        dbg(udev, "version %s\n", VERSION);
+
+        for (;;) {
+                int option;
+                int seconds;
+
+                option = getopt_long(argc, argv, "s:e:t:E:qh", options, NULL);
+                if (option == -1)
+                        break;
+
+                switch (option) {
+                case 's':
+                        start = strtoull(optarg, NULL, 0);
+                        break;
+                case 'e':
+                        end = strtoull(optarg, NULL, 0);
+                        break;
+                case 't':
+                        seconds = atoi(optarg);
+                        if (seconds >= 0)
+                                timeout = seconds;
+                        else
+                                fprintf(stderr, "invalid timeout value\n");
+                        dbg(udev, "timeout=%i\n", timeout);
+                        break;
+                case 'q':
+                        quiet = 1;
+                        break;
+                case 'E':
+                        exists = optarg;
+                        break;
+                case 'h':
+                        printf("Usage: udevadm settle OPTIONS\n"
+                               "  --timeout=<seconds>     maximum time to wait for events\n"
+                               "  --seq-start=<seqnum>    first seqnum to wait for\n"
+                               "  --seq-end=<seqnum>      last seqnum to wait for\n"
+                               "  --exit-if-exists=<file> stop waiting if file exists\n"
+                               "  --quiet                 do not print list after timeout\n"
+                               "  --help\n\n");
+                        exit(EXIT_SUCCESS);
+                default:
+                        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) {
+                        err(udev, "seq-start larger than seq-end, ignoring\n");
+                        start = 0;
+                        end = 0;
+                }
+
+                if (start > kernel_seq || end > kernel_seq) {
+                        err(udev, "seq-start or seq-end larger than current kernel value, ignoring\n");
+                        start = 0;
+                        end = 0;
+                }
+                info(udev, "start=%llu end=%llu current=%llu\n", start, end, kernel_seq);
+        } else {
+                if (end > 0) {
+                        err(udev, "seq-end needs seq-start parameter, ignoring\n");
+                        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) {
+                                info(udev, "no connection to daemon\n");
+                                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) {
+                err(udev, "inotify_init failed: %m\n");
+        } else {
+                if (inotify_add_watch(pfd[0].fd, udev_get_run_path(udev), IN_MOVED_TO) < 0) {
+                        err(udev, "watching '%s' failed\n", udev_get_run_path(udev));
+                        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) {
+                        unsigned long long age_usec;
+
+                        age_usec = now_usec() - 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) {
+                                        info(udev, "timeout waiting for udev queue\n");
+                                        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);
+        udev_queue_unref(udev_queue);
+        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 (file)
index 0000000..3a49f7c
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2011 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <getopt.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/inotify.h>
+#include <sys/poll.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#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;
+
+        dbg(udev, "version %s\n", VERSION);
+
+        for (;;) {
+                int option;
+
+                option = getopt_long(argc, argv, "h", options, NULL);
+                if (option == -1)
+                        break;
+
+                switch (option) {
+                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\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 (strncmp(syspath, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
+                util_strscpyl(filename, sizeof(filename), udev_get_sys_path(udev), syspath, NULL);
+        else
+                util_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;
+        }
+
+        if (udev_builtin_run(dev, cmd, command, true) < 0) {
+                fprintf(stderr, "error executing '%s'\n\n", command);
+                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 (file)
index 0000000..6275cff
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2003-2004 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2004-2008 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <syslog.h>
+#include <getopt.h>
+#include <sys/signalfd.h>
+
+#include "udev.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_event *event = NULL;
+        struct udev_device *dev = NULL;
+        struct udev_rules *rules = NULL;
+        struct udev_list_entry *entry;
+        sigset_t mask, sigmask_orig;
+        int err;
+        int rc = 0;
+
+        static const struct option options[] = {
+                { "action", required_argument, NULL, 'a' },
+                { "resolve-names", required_argument, NULL, 'N' },
+                { "help", no_argument, NULL, 'h' },
+                {}
+        };
+
+        info(udev, "version %s\n", VERSION);
+
+        for (;;) {
+                int option;
+
+                option = getopt_long(argc, argv, "a:s:N:fh", options, NULL);
+                if (option == -1)
+                        break;
+
+                dbg(udev, "option '%c'\n", option);
+                switch (option) {
+                case 'a':
+                        action = optarg;
+                        break;
+                case 'N':
+                        if (strcmp (optarg, "early") == 0) {
+                                resolve_names = 1;
+                        } else if (strcmp (optarg, "late") == 0) {
+                                resolve_names = 0;
+                        } else if (strcmp (optarg, "never") == 0) {
+                                resolve_names = -1;
+                        } else {
+                                fprintf(stderr, "resolve-names must be early, late or never\n");
+                                err(udev, "resolve-names must be early, late or never\n");
+                                exit(EXIT_FAILURE);
+                        }
+                        break;
+                case 'h':
+                        printf("Usage: udevadm test OPTIONS <syspath>\n"
+                               "  --action=<string>     set action string\n"
+                               "  --help\n\n");
+                        exit(EXIT_SUCCESS);
+                default:
+                        exit(EXIT_FAILURE);
+                }
+        }
+        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 (strncmp(syspath, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
+                util_strscpyl(filename, sizeof(filename), udev_get_sys_path(udev), syspath, NULL);
+        else
+                util_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_event_unref(event);
+        udev_device_unref(dev);
+        udev_rules_unref(rules);
+        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 (file)
index 0000000..3cce23d
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2008-2009 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <fnmatch.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "udev.h"
+
+static int verbose;
+static int dry_run;
+
+static void exec_list(struct udev_enumerate *udev_enumerate, const char *action)
+{
+        struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
+        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;
+                util_strscpyl(filename, sizeof(filename), udev_list_entry_get_name(entry), "/uevent", NULL);
+                fd = open(filename, O_WRONLY);
+                if (fd < 0) {
+                        dbg(udev, "error on opening %s: %m\n", filename);
+                        continue;
+                }
+                if (write(fd, action, strlen(action)) < 0)
+                        info(udev, "error writing '%s' to '%s': %m\n", action, filename);
+                close(fd);
+        }
+}
+
+static const char *keyval(const char *str, const char **val, char *buf, size_t size)
+{
+        char *pos;
+
+        util_strscpy(buf, size,str);
+        pos = strchr(buf, '=');
+        if (pos != NULL) {
+                pos[0] = 0;
+                pos++;
+        }
+        *val = pos;
+        return buf;
+}
+
+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";
+        struct udev_enumerate *udev_enumerate;
+        int rc = 0;
+
+        dbg(udev, "version %s\n", VERSION);
+        udev_enumerate = udev_enumerate_new(udev);
+        if (udev_enumerate == NULL) {
+                rc = 1;
+                goto exit;
+        }
+
+        for (;;) {
+                int option;
+                const char *key;
+                const char *val;
+                char buf[UTIL_PATH_SIZE];
+
+                option = getopt_long(argc, argv, "vng:o:t:hc:p:s:S:a:A:y:b:", options, NULL);
+                if (option == -1)
+                        break;
+
+                switch (option) {
+                case 'v':
+                        verbose = 1;
+                        break;
+                case 'n':
+                        dry_run = 1;
+                        break;
+                case 't':
+                        if (strcmp(optarg, "devices") == 0) {
+                                device_type = TYPE_DEVICES;
+                        } else if (strcmp(optarg, "subsystems") == 0) {
+                                device_type = TYPE_SUBSYSTEMS;
+                        } else {
+                                err(udev, "unknown type --type=%s\n", optarg);
+                                rc = 2;
+                                goto exit;
+                        }
+                        break;
+                case 'c':
+                        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 (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
+                                util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), optarg, NULL);
+                        else
+                                util_strscpy(path, sizeof(path), optarg);
+                        util_remove_trailing_chars(path, '/');
+                        dev = udev_device_new_from_syspath(udev, path);
+                        if (dev == NULL) {
+                                err(udev, "unable to open the device '%s'\n", optarg);
+                                rc = 2;
+                                goto exit;
+                        }
+                        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':
+                        printf("Usage: udevadm trigger OPTIONS\n"
+                               "  --verbose                       print the list of devices while running\n"
+                               "  --dry-run                       do not actually trigger the events\n"
+                               "  --type=                         type of events to trigger\n"
+                               "      devices                       sys devices (default)\n"
+                               "      subsystems                    sys subsystems and drivers\n"
+                               "  --action=<action>               event action value, default is \"change\"\n"
+                               "  --subsystem-match=<subsystem>   trigger devices from a matching subsystem\n"
+                               "  --subsystem-nomatch=<subsystem> exclude devices from a matching subsystem\n"
+                               "  --attr-match=<file[=<value>]>   trigger devices with a matching attribute\n"
+                               "  --attr-nomatch=<file[=<value>]> exclude devices with a matching attribute\n"
+                               "  --property-match=<key>=<value>  trigger devices with a matching property\n"
+                               "  --tag-match=<key>=<value>       trigger devices with a matching property\n"
+                               "  --sysname-match=<name>          trigger devices with a matching name\n"
+                               "  --parent-match=<name>           trigger devices with that parent device\n"
+                               "  --help\n\n");
+                        goto exit;
+                default:
+                        rc = 1;
+                        goto exit;
+                }
+        }
+
+        switch (device_type) {
+        case TYPE_SUBSYSTEMS:
+                udev_enumerate_scan_subsystems(udev_enumerate);
+                exec_list(udev_enumerate, action);
+                goto exit;
+        case TYPE_DEVICES:
+                udev_enumerate_scan_devices(udev_enumerate);
+                exec_list(udev_enumerate, action);
+                goto exit;
+        default:
+                goto exit;
+        }
+exit:
+        udev_enumerate_unref(udev_enumerate);
+        return rc;
+}
+
+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 (file)
index 0000000..224ece0
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2007-2009 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+
+#include "udev.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)
+{
+        if (debug) {
+                fprintf(stderr, "%s: ", fn);
+                vfprintf(stderr, format, args);
+        } else {
+                va_list args2;
+
+                va_copy(args2, args);
+                vfprintf(stderr, format, args2);
+                va_end(args2);
+                vsyslog(priority, 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_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 < ARRAY_SIZE(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) {
+                debug = true;
+                if (udev_get_log_priority(udev) < LOG_INFO)
+                        udev_set_log_priority(udev, LOG_INFO);
+        }
+        info(udev, "calling: %s\n", 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;
+
+        udev_log_init("udevadm");
+        udev_set_log_fn(udev, udev_main_log);
+        udev_selinux_init(udev);
+
+        for (;;) {
+                int option;
+
+                option = getopt_long(argc, argv, "+dhV", options, NULL);
+                if (option == -1)
+                        break;
+
+                switch (option) {
+                case 'd':
+                        debug = true;
+                        if (udev_get_log_priority(udev) < LOG_INFO)
+                                udev_set_log_priority(udev, LOG_INFO);
+                        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];
+
+        info(udev, "runtime dir '%s'\n", udev_get_run_path(udev));
+
+        if (command != NULL)
+                for (i = 0; i < ARRAY_SIZE(udevadm_cmds); i++) {
+                        if (strcmp(udevadm_cmds[i]->name, command) == 0) {
+                                argc -= optind;
+                                argv += optind;
+                                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:
+        udev_selinux_exit(udev);
+        udev_unref(udev);
+        udev_log_close();
+        return rc;
+}
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
new file mode 100644 (file)
index 0000000..694e758
--- /dev/null
@@ -0,0 +1,1746 @@
+/*
+ * Copyright (C) 2004-2011 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2004 Chris Friesen <chris_friesen@sympatico.ca>
+ * Copyright (C) 2009 Canonical Ltd.
+ * Copyright (C) 2009 Scott James Remnant <scott@netsplit.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stddef.h>
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <time.h>
+#include <getopt.h>
+#include <dirent.h>
+#include <sys/time.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/signalfd.h>
+#include <sys/epoll.h>
+#include <sys/poll.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/inotify.h>
+#include <sys/utsname.h>
+
+#include "udev.h"
+#include "sd-daemon.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)
+{
+        if (debug) {
+                char buf[1024];
+                struct timespec ts;
+
+                vsnprintf(buf, sizeof(buf), format, args);
+                clock_gettime(CLOCK_MONOTONIC, &ts);
+                fprintf(stderr, "[%llu.%06u] [%u] %s: %s",
+                        (unsigned long long) ts.tv_sec, (unsigned int) ts.tv_nsec/1000,
+                        (int) getpid(), fn, buf);
+        } else {
+                vsyslog(priority, 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 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;
+        bool is_block;
+        int ifindex;
+};
+
+static struct event *node_to_event(struct udev_list_node *node)
+{
+        char *event;
+
+        event = (char *)node;
+        event -= offsetof(struct event, node);
+        return (struct event *)event;
+}
+
+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;
+        unsigned long long event_start_usec;
+};
+
+/* passed from worker to main process */
+struct worker_message {
+        pid_t pid;
+        int exitcode;
+};
+
+static struct worker *node_to_worker(struct udev_list_node *node)
+{
+        char *worker;
+
+        worker = (char *)node;
+        worker -= offsetof(struct worker, node);
+        return (struct worker *)worker;
+}
+
+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);
+                info(event->udev, "seq %llu done with %i\n", 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;
+        info(worker->udev, "worker [%u] cleaned up\n", 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 = calloc(1, sizeof(struct worker));
+        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) {
+                        err(udev, "error creating signalfd %m\n");
+                        rc = 2;
+                        goto out;
+                }
+
+                fd_ep = epoll_create1(EPOLL_CLOEXEC);
+                if (fd_ep < 0) {
+                        err(udev, "error creating epoll fd: %m\n");
+                        rc = 3;
+                        goto out;
+                }
+
+                memset(&ep_signal, 0, sizeof(struct epoll_event));
+                ep_signal.events = EPOLLIN;
+                ep_signal.data.fd = fd_signal;
+
+                fd_monitor = udev_monitor_get_fd(worker_monitor);
+                memset(&ep_monitor, 0, 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) {
+                        err(udev, "fail to add fds to epoll: %m\n");
+                        rc = 4;
+                        goto out;
+                }
+
+                /* request TERM signal if parent exits */
+                prctl(PR_SET_PDEATHSIG, SIGTERM);
+
+                for (;;) {
+                        struct udev_event *udev_event;
+                        struct worker_message msg;
+                        int err;
+
+                        info(udev, "seq %llu running\n", 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 */
+                        memset(&msg, 0, sizeof(struct worker_message));
+                        if (err != 0)
+                                msg.exitcode = err;
+                        msg.pid = getpid();
+                        send(worker_watch[WRITE_END], &msg, sizeof(struct worker_message), 0);
+
+                        info(udev, "seq %llu processed with %i\n", 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, ARRAY_SIZE(ev), -1);
+                                if (fdcount < 0) {
+                                        if (errno == EINTR)
+                                                continue;
+                                        err = -errno;
+                                        err(udev, "failed to poll: %m\n");
+                                        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);
+                udev_log_close();
+                exit(rc);
+        }
+        case -1:
+                udev_monitor_unref(worker_monitor);
+                event->state = EVENT_QUEUED;
+                free(worker);
+                err(udev, "fork of child failed: %m\n");
+                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_usec();
+                worker->event = event;
+                event->state = EVENT_RUNNING;
+                udev_list_node_append(&worker->node, &worker_list);
+                children++;
+                info(udev, "seq %llu forked new worker [%u]\n", 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) {
+                        err(event->udev, "worker [%u] did not accept message %zi (%m), kill it\n", 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_usec();
+                event->state = EVENT_RUNNING;
+                return;
+        }
+
+        if (children >= children_max) {
+                if (children_max > 1)
+                        info(event->udev, "maximum number (%i) of children reached\n", 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 = calloc(1, sizeof(struct event));
+        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 = (strcmp("block", udev_device_get_subsystem(dev)) == 0);
+        event->ifindex = udev_device_get_ifindex(dev);
+
+        udev_queue_export_device_queued(udev_queue_export, dev);
+        info(event->udev, "seq %llu queued, '%s' '%s'\n", 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, int retain)
+{
+        struct udev_list_node *loop;
+        int max;
+
+        if (children <= retain)
+                return;
+
+        max = children - retain;
+
+        udev_list_node_foreach(loop, &worker_list) {
+                struct worker *worker = node_to_worker(loop);
+
+                if (max-- <= 0)
+                        break;
+
+                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 && strcmp(loop_event->devpath, event->devpath_old) == 0) {
+                        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;
+                }
+
+                /* 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)) {
+                        dbg(udev, "delay seq %llu (%s)\n", event->seqnum, event->devpath);
+                        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) {
+                info(udev, "udevd message (SET_LOG_PRIORITY) received, log_priority=%i\n", i);
+                udev_set_log_priority(udev, i);
+                worker_kill(udev, 0);
+        }
+
+        if (udev_ctrl_get_stop_exec_queue(ctrl_msg) > 0) {
+                info(udev, "udevd message (STOP_EXEC_QUEUE) received\n");
+                stop_exec_queue = true;
+        }
+
+        if (udev_ctrl_get_start_exec_queue(ctrl_msg) > 0) {
+                info(udev, "udevd message (START_EXEC_QUEUE) received\n");
+                stop_exec_queue = false;
+        }
+
+        if (udev_ctrl_get_reload(ctrl_msg) > 0) {
+                info(udev, "udevd message (RELOAD) received\n");
+                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') {
+                                        info(udev, "udevd message (ENV) received, unset '%s'\n", key);
+                                        udev_add_property(udev, key, NULL);
+                                } else {
+                                        info(udev, "udevd message (ENV) received, set '%s=%s'\n", key, val);
+                                        udev_add_property(udev, key, val);
+                                }
+                        } else {
+                                err(udev, "wrong key format '%s'\n", key);
+                        }
+                        free(key);
+                }
+                worker_kill(udev, 0);
+        }
+
+        i = udev_ctrl_get_set_children_max(ctrl_msg);
+        if (i >= 0) {
+                info(udev, "udevd message (SET_MAX_CHILDREN) received, children_max=%i\n", i);
+                children_max = i;
+        }
+
+        if (udev_ctrl_get_ping(ctrl_msg) > 0)
+                info(udev, "udevd message (SYNC) received\n");
+
+        if (udev_ctrl_get_exit(ctrl_msg) > 0) {
+                info(udev, "udevd message (EXIT) received\n");
+                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) {
+                err(udev, "error getting buffer for inotify\n");
+                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) {
+                        info(udev, "inotify event: %x for %s\n", ev->mask, udev_device_get_devnode(dev));
+                        if (ev->mask & IN_CLOSE_WRITE) {
+                                char filename[UTIL_PATH_SIZE];
+                                int fd;
+
+                                info(udev, "device %s closed, synthesising 'change'\n", udev_device_get_devnode(dev));
+                                util_strscpyl(filename, sizeof(filename), udev_device_get_syspath(dev), "/uevent", NULL);
+                                fd = open(filename, O_WRONLY);
+                                if (fd >= 0) {
+                                        if (write(fd, "change", 6) < 0)
+                                                info(udev, "error writing uevent: %m\n");
+                                        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;
+                                info(udev, "worker [%u] exit\n", pid);
+
+                                if (WIFEXITED(status)) {
+                                        if (WEXITSTATUS(status) != 0)
+                                                err(udev, "worker [%u] exit with return code %i\n", pid, WEXITSTATUS(status));
+                                } else if (WIFSIGNALED(status)) {
+                                        err(udev, "worker [%u] terminated by signal %i (%s)\n",
+                                            pid, WTERMSIG(status), strsignal(WTERMSIG(status)));
+                                } else if (WIFSTOPPED(status)) {
+                                        err(udev, "worker [%u] stopped\n", pid);
+                                } else if (WIFCONTINUED(status)) {
+                                        err(udev, "worker [%u] continued\n", pid);
+                                } else {
+                                        err(udev, "worker [%u] exit with status 0x%04x\n", pid, status);
+                                }
+
+                                if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+                                        if (worker->event) {
+                                                err(udev, "worker [%u] failed while handling '%s'\n",
+                                                    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 void static_dev_create_from_modules(struct udev *udev)
+{
+        struct utsname kernel;
+        char modules[UTIL_PATH_SIZE];
+        char buf[4096];
+        FILE *f;
+
+        uname(&kernel);
+        util_strscpyl(modules, sizeof(modules), "/lib/modules/", kernel.release, "/modules.devname", NULL);
+        f = fopen(modules, "r");
+        if (f == NULL)
+                return;
+
+        while (fgets(buf, sizeof(buf), f) != NULL) {
+                char *s;
+                const char *modname;
+                const char *devname;
+                const char *devno;
+                int maj, min;
+                char type;
+                mode_t mode;
+                char filename[UTIL_PATH_SIZE];
+
+                if (buf[0] == '#')
+                        continue;
+
+                modname = buf;
+                s = strchr(modname, ' ');
+                if (s == NULL)
+                        continue;
+                s[0] = '\0';
+
+                devname = &s[1];
+                s = strchr(devname, ' ');
+                if (s == NULL)
+                        continue;
+                s[0] = '\0';
+
+                devno = &s[1];
+                s = strchr(devno, ' ');
+                if (s == NULL)
+                        s = strchr(devno, '\n');
+                if (s != NULL)
+                        s[0] = '\0';
+                if (sscanf(devno, "%c%u:%u", &type, &maj, &min) != 3)
+                        continue;
+
+                if (type == 'c')
+                        mode = S_IFCHR;
+                else if (type == 'b')
+                        mode = S_IFBLK;
+                else
+                        continue;
+
+                util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/", devname, NULL);
+                util_create_path_selinux(udev, filename);
+                udev_selinux_setfscreatecon(udev, filename, mode);
+                info(udev, "mknod '%s' %c%u:%u\n", filename, type, maj, min);
+                if (mknod(filename, mode, makedev(maj, min)) < 0 && errno == EEXIST)
+                        utimensat(AT_FDCWD, filename, NULL, 0);
+                udev_selinux_resetfscreatecon(udev);
+        }
+
+        fclose(f);
+}
+
+static int copy_dev_dir(struct udev *udev, DIR *dir_from, DIR *dir_to, int maxdepth)
+{
+        struct dirent *dent;
+
+        for (dent = readdir(dir_from); dent != NULL; dent = readdir(dir_from)) {
+                struct stat stats;
+
+                if (dent->d_name[0] == '.')
+                        continue;
+                if (fstatat(dirfd(dir_from), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) != 0)
+                        continue;
+
+                if (S_ISBLK(stats.st_mode) || S_ISCHR(stats.st_mode)) {
+                        udev_selinux_setfscreateconat(udev, dirfd(dir_to), dent->d_name, stats.st_mode & 0777);
+                        if (mknodat(dirfd(dir_to), dent->d_name, stats.st_mode, stats.st_rdev) == 0) {
+                                fchmodat(dirfd(dir_to), dent->d_name, stats.st_mode & 0777, 0);
+                                fchownat(dirfd(dir_to), dent->d_name, stats.st_uid, stats.st_gid, 0);
+                        } else {
+                                utimensat(dirfd(dir_to), dent->d_name, NULL, 0);
+                        }
+                        udev_selinux_resetfscreatecon(udev);
+                } else if (S_ISLNK(stats.st_mode)) {
+                        char target[UTIL_PATH_SIZE];
+                        ssize_t len;
+
+                        len = readlinkat(dirfd(dir_from), dent->d_name, target, sizeof(target));
+                        if (len <= 0 || len == (ssize_t)sizeof(target))
+                                continue;
+                        target[len] = '\0';
+                        udev_selinux_setfscreateconat(udev, dirfd(dir_to), dent->d_name, S_IFLNK);
+                        if (symlinkat(target, dirfd(dir_to), dent->d_name) < 0 && errno == EEXIST)
+                                utimensat(dirfd(dir_to), dent->d_name, NULL, AT_SYMLINK_NOFOLLOW);
+                        udev_selinux_resetfscreatecon(udev);
+                } else if (S_ISDIR(stats.st_mode)) {
+                        DIR *dir2_from, *dir2_to;
+
+                        if (maxdepth == 0)
+                                continue;
+
+                        udev_selinux_setfscreateconat(udev, dirfd(dir_to), dent->d_name, S_IFDIR|0755);
+                        mkdirat(dirfd(dir_to), dent->d_name, 0755);
+                        udev_selinux_resetfscreatecon(udev);
+
+                        dir2_to = fdopendir(openat(dirfd(dir_to), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
+                        if (dir2_to == NULL)
+                                continue;
+
+                        dir2_from = fdopendir(openat(dirfd(dir_from), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
+                        if (dir2_from == NULL) {
+                                closedir(dir2_to);
+                                continue;
+                        }
+
+                        copy_dev_dir(udev, dir2_from, dir2_to, maxdepth-1);
+
+                        closedir(dir2_to);
+                        closedir(dir2_from);
+                }
+        }
+
+        return 0;
+}
+
+static void static_dev_create_links(struct udev *udev, DIR *dir)
+{
+        struct stdlinks {
+                const char *link;
+                const char *target;
+        };
+        static const struct stdlinks stdlinks[] = {
+                { "core", "/proc/kcore" },
+                { "fd", "/proc/self/fd" },
+                { "stdin", "/proc/self/fd/0" },
+                { "stdout", "/proc/self/fd/1" },
+                { "stderr", "/proc/self/fd/2" },
+        };
+        unsigned int i;
+
+        for (i = 0; i < ARRAY_SIZE(stdlinks); i++) {
+                struct stat sb;
+
+                if (stat(stdlinks[i].target, &sb) == 0) {
+                        udev_selinux_setfscreateconat(udev, dirfd(dir), stdlinks[i].link, S_IFLNK);
+                        if (symlinkat(stdlinks[i].target, dirfd(dir), stdlinks[i].link) < 0 && errno == EEXIST)
+                                utimensat(dirfd(dir), stdlinks[i].link, NULL, AT_SYMLINK_NOFOLLOW);
+                        udev_selinux_resetfscreatecon(udev);
+                }
+        }
+}
+
+static void static_dev_create_from_devices(struct udev *udev, DIR *dir)
+{
+        DIR *dir_from;
+
+        dir_from = opendir(UDEVLIBEXECDIR "/devices");
+        if (dir_from == NULL)
+                return;
+        copy_dev_dir(udev, dir_from, dir, 8);
+        closedir(dir_from);
+}
+
+static void static_dev_create(struct udev *udev)
+{
+        DIR *dir;
+
+        dir = opendir(udev_get_dev_path(udev));
+        if (dir == NULL)
+                return;
+
+        static_dev_create_links(udev, dir);
+        static_dev_create_from_devices(udev, dir);
+
+        closedir(dir);
+}
+
+static int mem_size_mb(void)
+{
+        FILE *f;
+        char buf[4096];
+        long int memsize = -1;
+
+        f = fopen("/proc/meminfo", "r");
+        if (f == NULL)
+                return -1;
+
+        while (fgets(buf, sizeof(buf), f) != NULL) {
+                long int value;
+
+                if (sscanf(buf, "MemTotal: %ld kB", &value) == 1) {
+                        memsize = value / 1024;
+                        break;
+                }
+        }
+
+        fclose(f);
+        return memsize;
+}
+
+static int convert_db(struct udev *udev)
+{
+        char filename[UTIL_PATH_SIZE];
+        FILE *f;
+        struct udev_enumerate *udev_enumerate;
+        struct udev_list_entry *list_entry;
+
+        /* current database */
+        util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/data", NULL);
+        if (access(filename, F_OK) >= 0)
+                return 0;
+
+        /* make sure we do not get here again */
+        util_create_path(udev, filename);
+        mkdir(filename, 0755);
+
+        /* old database */
+        util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev/db", NULL);
+        if (access(filename, F_OK) < 0)
+                return 0;
+
+        f = fopen("/dev/kmsg", "w");
+        if (f != NULL) {
+                fprintf(f, "<30>udevd[%u]: converting old udev database\n", getpid());
+                fclose(f);
+        }
+
+        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)
+                        continue;
+
+                /* try to find the old database for devices without a current one */
+                if (udev_device_read_db(device, NULL) < 0) {
+                        bool have_db;
+                        const char *id;
+                        struct stat stats;
+                        char devpath[UTIL_PATH_SIZE];
+                        char from[UTIL_PATH_SIZE];
+
+                        have_db = false;
+
+                        /* find database in old location */
+                        id = udev_device_get_id_filename(device);
+                        util_strscpyl(from, sizeof(from), udev_get_dev_path(udev), "/.udev/db/", id, NULL);
+                        if (lstat(from, &stats) == 0) {
+                                if (!have_db) {
+                                        udev_device_read_db(device, from);
+                                        have_db = true;
+                                }
+                                unlink(from);
+                        }
+
+                        /* find old database with $subsys:$sysname name */
+                        util_strscpyl(from, sizeof(from), udev_get_dev_path(udev),
+                                     "/.udev/db/", udev_device_get_subsystem(device), ":",
+                                     udev_device_get_sysname(device), NULL);
+                        if (lstat(from, &stats) == 0) {
+                                if (!have_db) {
+                                        udev_device_read_db(device, from);
+                                        have_db = true;
+                                }
+                                unlink(from);
+                        }
+
+                        /* find old database with the encoded devpath name */
+                        util_path_encode(udev_device_get_devpath(device), devpath, sizeof(devpath));
+                        util_strscpyl(from, sizeof(from), udev_get_dev_path(udev), "/.udev/db/", devpath, NULL);
+                        if (lstat(from, &stats) == 0) {
+                                if (!have_db) {
+                                        udev_device_read_db(device, from);
+                                        have_db = true;
+                                }
+                                unlink(from);
+                        }
+
+                        /* write out new database */
+                        if (have_db)
+                                udev_device_update_db(device);
+                }
+                udev_device_unref(device);
+        }
+        udev_enumerate_unref(udev_enumerate);
+        return 0;
+}
+
+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;
+
+        info(udev, "ctrl=%i netlink=%i\n", ctrl, netlink);
+        *rctrl = ctrl;
+        *rnetlink = netlink;
+        return 0;
+}
+
+static bool check_rules_timestamp(struct udev *udev)
+{
+        char **p;
+        unsigned long long *stamp_usec;
+        int i, n;
+        bool changed = false;
+
+        n = udev_get_rules_path(udev, &p, &stamp_usec);
+        for (i = 0; i < n; i++) {
+                struct stat stats;
+
+                if (stat(p[i], &stats) < 0)
+                        continue;
+
+                if (stamp_usec[i] == ts_usec(&stats.st_mtim))
+                        continue;
+
+                /* first check */
+                if (stamp_usec[i] != 0) {
+                        info(udev, "reload - timestamp of '%s' changed\n", p[i]);
+                        changed = true;
+                }
+
+                /* update timestamp */
+                stamp_usec[i] = ts_usec(&stats.st_mtim);
+        }
+
+        return changed;
+}
+
+int main(int argc, char *argv[])
+{
+        struct udev *udev;
+        FILE *f;
+        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;
+        char **s;
+        int rc = 1;
+
+        udev = udev_new();
+        if (udev == NULL)
+                goto exit;
+
+        udev_log_init("udevd");
+        udev_set_log_fn(udev, udev_main_log);
+        info(udev, "version %s\n", VERSION);
+        udev_selinux_init(udev);
+
+        for (;;) {
+                int option;
+
+                option = getopt_long(argc, argv, "c:deDtN: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;
+                        if (udev_get_log_priority(udev) < LOG_INFO)
+                                udev_set_log_priority(udev, LOG_INFO);
+                        break;
+                case 'N':
+                        if (strcmp (optarg, "early") == 0) {
+                                resolve_names = 1;
+                        } else if (strcmp (optarg, "late") == 0) {
+                                resolve_names = 0;
+                        } else if (strcmp (optarg, "never") == 0) {
+                                resolve_names = -1;
+                        } else {
+                                fprintf(stderr, "resolve-names must be early, late or never\n");
+                                err(udev, "resolve-names must be early, late or never\n");
+                                goto exit;
+                        }
+                        break;
+                case 'h':
+                        printf("Usage: udevd OPTIONS\n"
+                               "  --daemon\n"
+                               "  --debug\n"
+                               "  --children-max=<maximum number of workers>\n"
+                               "  --exec-delay=<seconds to wait before executing RUN=>\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;
+                }
+        }
+
+        /*
+         * read the kernel commandline, in case we need to get into debug mode
+         *   udev.log-priority=<level>              syslog priority
+         *   udev.children-max=<number of workers>  events are fully serialized if set to 1
+         *
+         */
+        f = fopen("/proc/cmdline", "r");
+        if (f != NULL) {
+                char cmdline[4096];
+
+                if (fgets(cmdline, sizeof(cmdline), f) != NULL) {
+                        char *pos;
+
+                        pos = strstr(cmdline, "udev.log-priority=");
+                        if (pos != NULL) {
+                                pos += strlen("udev.log-priority=");
+                                udev_set_log_priority(udev, util_log_priority(pos));
+                        }
+
+                        pos = strstr(cmdline, "udev.children-max=");
+                        if (pos != NULL) {
+                                pos += strlen("udev.children-max=");
+                                children_max = strtoul(pos, NULL, 0);
+                        }
+
+                        pos = strstr(cmdline, "udev.exec-delay=");
+                        if (pos != NULL) {
+                                pos += strlen("udev.exec-delay=");
+                                exec_delay = strtoul(pos, NULL, 0);
+                        }
+                }
+                fclose(f);
+        }
+
+        if (getuid() != 0) {
+                fprintf(stderr, "root privileges required\n");
+                err(udev, "root privileges required\n");
+                goto exit;
+        }
+
+        /* set umask before creating any file/directory */
+        chdir("/");
+        umask(022);
+
+        /* /run/udev */
+        mkdir(udev_get_run_path(udev), 0755);
+
+        /* create standard links, copy static nodes, create nodes from modules */
+        static_dev_create(udev);
+        static_dev_create_from_modules(udev);
+
+        /* 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");
+                        err(udev, "cannot open /dev/null\n");
+                }
+        }
+
+        if (systemd_fds(udev, &fd_ctrl, &fd_netlink) >= 0) {
+                /* get control and netlink socket from from systemd */
+                udev_ctrl = udev_ctrl_new_from_fd(udev, fd_ctrl);
+                if (udev_ctrl == NULL) {
+                        err(udev, "error taking over udev control socket");
+                        rc = 1;
+                        goto exit;
+                }
+
+                monitor = udev_monitor_new_from_netlink_fd(udev, "kernel", fd_netlink);
+                if (monitor == NULL) {
+                        err(udev, "error taking over netlink socket\n");
+                        rc = 3;
+                        goto exit;
+                }
+        } else {
+                /* open control and netlink socket */
+                udev_ctrl = udev_ctrl_new(udev);
+                if (udev_ctrl == NULL) {
+                        fprintf(stderr, "error initializing udev control socket");
+                        err(udev, "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");
+                        err(udev, "error initializing netlink socket\n");
+                        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");
+                err(udev, "error binding netlink socket\n");
+                rc = 3;
+                goto exit;
+        }
+
+        if (udev_ctrl_enable_receiving(udev_ctrl) < 0) {
+                fprintf(stderr, "error binding udev control socket\n");
+                err(udev, "error binding udev control socket\n");
+                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) {
+                err(udev, "error creating queue file\n");
+                goto exit;
+        }
+
+        if (daemonize) {
+                pid_t pid;
+                int fd;
+
+                pid = fork();
+                switch (pid) {
+                case 0:
+                        break;
+                case -1:
+                        err(udev, "fork of daemon failed: %m\n");
+                        rc = 4;
+                        goto exit;
+                default:
+                        rc = EXIT_SUCCESS;
+                        goto exit_daemonize;
+                }
+
+                setsid();
+
+                fd = open("/proc/self/oom_score_adj", O_RDWR);
+                if (fd < 0) {
+                        /* Fallback to old interface */
+                        fd = open("/proc/self/oom_adj", O_RDWR);
+                        if (fd < 0) {
+                                err(udev, "error disabling OOM: %m\n");
+                        } else {
+                                /* OOM_DISABLE == -17 */
+                                write(fd, "-17", 3);
+                                close(fd);
+                        }
+                } else {
+                        write(fd, "-1000", 5);
+                        close(fd);
+                }
+        } else {
+                sd_notify(1, "READY=1");
+        }
+
+        f = fopen("/dev/kmsg", "w");
+        if (f != NULL) {
+                fprintf(f, "<30>udevd[%u]: starting version " VERSION "\n", getpid());
+                fclose(f);
+        }
+
+        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");
+                err(udev, "error initializing inotify\n");
+                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");
+                err(udev, "error creating signalfd\n");
+                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");
+                err(udev, "error creating socketpair\n");
+                rc = 6;
+                goto exit;
+        }
+        fd_worker = worker_watch[READ_END];
+
+        udev_builtin_init(udev);
+
+        rules = udev_rules_new(udev, resolve_names);
+        if (rules == NULL) {
+                err(udev, "error reading rules\n");
+                goto exit;
+        }
+
+        memset(&ep_ctrl, 0, sizeof(struct epoll_event));
+        ep_ctrl.events = EPOLLIN;
+        ep_ctrl.data.fd = fd_ctrl;
+
+        memset(&ep_inotify, 0, sizeof(struct epoll_event));
+        ep_inotify.events = EPOLLIN;
+        ep_inotify.data.fd = fd_inotify;
+
+        memset(&ep_signal, 0, sizeof(struct epoll_event));
+        ep_signal.events = EPOLLIN;
+        ep_signal.data.fd = fd_signal;
+
+        memset(&ep_netlink, 0, sizeof(struct epoll_event));
+        ep_netlink.events = EPOLLIN;
+        ep_netlink.data.fd = fd_netlink;
+
+        memset(&ep_worker, 0, sizeof(struct epoll_event));
+        ep_worker.events = EPOLLIN;
+        ep_worker.data.fd = fd_worker;
+
+        fd_ep = epoll_create1(EPOLL_CLOEXEC);
+        if (fd_ep < 0) {
+                err(udev, "error creating epoll fd: %m\n");
+                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) {
+                err(udev, "fail to add fds to epoll: %m\n");
+                goto exit;
+        }
+
+        /* if needed, convert old database from earlier udev version */
+        convert_db(udev);
+
+        if (children_max <= 0) {
+                int memsize = mem_size_mb();
+
+                /* set value depending on the amount of RAM */
+                if (memsize > 0)
+                        children_max = 128 + (memsize / 8);
+                else
+                        children_max = 128;
+        }
+        info(udev, "set children_max to %u\n", children_max);
+
+        udev_rules_apply_static_dev_perms(rules);
+
+        udev_list_node_init(&event_list);
+        udev_list_node_init(&worker_list);
+
+        for (;;) {
+                static unsigned long long 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, 0);
+
+                        /* 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 <= 2) {
+                        /* we are idle */
+                        timeout = -1;
+                } else {
+                        /* kill idle or hanging workers */
+                        timeout = 3 * 1000;
+                }
+                fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), timeout);
+                if (fdcount < 0)
+                        continue;
+
+                if (fdcount == 0) {
+                        struct udev_list_node *loop;
+
+                        /* timeout */
+                        if (udev_exit) {
+                                err(udev, "timeout, giving up waiting for workers to finish\n");
+                                break;
+                        }
+
+                        /* kill idle workers */
+                        if (udev_list_node_is_empty(&event_list)) {
+                                info(udev, "cleanup idle workers\n");
+                                worker_kill(udev, 2);
+                        }
+
+                        /* 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_usec() - worker->event_start_usec) > 30 * 1000 * 1000) {
+                                        err(udev, "worker [%u] timeout, kill it\n", worker->pid,
+                                            worker->event ? worker->event->devpath : "<idle>");
+                                        kill(worker->pid, SIGKILL);
+                                        worker->state = WORKER_KILLED;
+                                        /* drop reference taken for state 'running' */
+                                        worker_unref(worker);
+                                        if (worker->event) {
+                                                err(udev, "seq %llu '%s' killed\n",
+                                                    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_usec() - last_usec) > 3 * 1000 * 1000) {
+                        if (check_rules_timestamp(udev))
+                                reload = true;
+                        if (udev_builtin_validate(udev))
+                                reload = true;
+
+                        last_usec = now_usec();
+                }
+
+                /* reload requested, HUP signal received, rules changed, builtin changed */
+                if (reload) {
+                        worker_kill(udev, 0);
+                        rules = udev_rules_unref(rules);
+                        udev_builtin_exit(udev);
+                        reload = 0;
+                }
+
+                /* 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_usec());
+                                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) {
+                        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);
+        udev_selinux_exit(udev);
+        udev_unref(udev);
+        udev_log_close();
+        return rc;
+}
diff --git a/src/udev/v4l_id/60-persistent-v4l.rules b/src/udev/v4l_id/60-persistent-v4l.rules
new file mode 100644 (file)
index 0000000..93c5ee8
--- /dev/null
@@ -0,0 +1,20 @@
+# 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"
+
+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/src/udev/v4l_id/v4l_id.c b/src/udev/v4l_id/v4l_id.c
new file mode 100644 (file)
index 0000000..a2a80b5
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2009 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (c) 2009 Filippo Argiolas <filippo.argiolas@gmail.com>
+ *
+ * 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 <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <linux/videodev2.h>
+
+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] <device file>\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;
+}
index 94412d52e70bb0fe3ac04709542cfc908f368ecd..f3b3cef133b7f49d17e22afe48105695abc39b38 100644 (file)
@@ -40,3 +40,6 @@ systemd-update-utmp-runlevel.service
 systemd-update-utmp-shutdown.service
 test-env-replace
 systemd-binfmt.service
+/udev-settle.service
+/udev-trigger.service
+/udev.service
diff --git a/units/udev-control.socket b/units/udev-control.socket
new file mode 100644 (file)
index 0000000..f80f774
--- /dev/null
@@ -0,0 +1,10 @@
+[Unit]
+Description=udev Control Socket
+DefaultDependencies=no
+ConditionCapability=CAP_MKNOD
+
+[Socket]
+Service=udev.service
+ListenSequentialPacket=/run/udev/control
+SocketMode=0600
+PassCredentials=yes
diff --git a/units/udev-kernel.socket b/units/udev-kernel.socket
new file mode 100644 (file)
index 0000000..23fa9d5
--- /dev/null
@@ -0,0 +1,10 @@
+[Unit]
+Description=udev Kernel Socket
+DefaultDependencies=no
+ConditionCapability=CAP_MKNOD
+
+[Socket]
+Service=udev.service
+ReceiveBuffer=134217728
+ListenNetlink=kobject-uevent 1
+PassCredentials=yes
diff --git a/units/udev-settle.service.in b/units/udev-settle.service.in
new file mode 100644 (file)
index 0000000..b0a4964
--- /dev/null
@@ -0,0 +1,25 @@
+# This service is usually not enabled by default. If enabled, it
+# acts as a barrier for basic.target -- so all later services will
+# wait for udev completely finishing its coldplug run.
+#
+# If needed, to work around broken or non-hotplug-aware services,
+# it might be enabled unconditionally, or pulled-in on-demand by
+# the services that assume a fully populated /dev at startup. It
+# should not be used or pulled-in ever on systems without such
+# legacy services running.
+
+[Unit]
+Description=udev Wait for Complete Device Initialization
+DefaultDependencies=no
+Wants=udev.service
+After=udev-trigger.service
+Before=basic.target
+
+[Service]
+Type=oneshot
+TimeoutSec=180
+RemainAfterExit=yes
+ExecStart=@bindir@/udevadm settle
+
+[Install]
+WantedBy=basic.target
diff --git a/units/udev-trigger.service.in b/units/udev-trigger.service.in
new file mode 100644 (file)
index 0000000..cd81945
--- /dev/null
@@ -0,0 +1,10 @@
+[Unit]
+Description=udev Coldplug all Devices
+Wants=udev.service
+After=udev-kernel.socket udev-control.socket
+DefaultDependencies=no
+
+[Service]
+Type=oneshot
+RemainAfterExit=yes
+ExecStart=@bindir@/udevadm trigger --type=subsystems --action=add ; @bindir@/udevadm trigger --type=devices --action=add
diff --git a/units/udev.service.in b/units/udev.service.in
new file mode 100644 (file)
index 0000000..c27eb1b
--- /dev/null
@@ -0,0 +1,14 @@
+[Unit]
+Description=udev Kernel Device Manager
+Wants=udev-control.socket udev-kernel.socket
+After=udev-control.socket udev-kernel.socket
+Before=basic.target
+DefaultDependencies=no
+ConditionCapability=CAP_MKNOD
+
+[Service]
+Type=notify
+OOMScoreAdjust=-1000
+Sockets=udev-control.socket udev-kernel.socket
+Restart=on-failure
+ExecStart=@pkglibexecdir@/udevd