From 3e2147858f21943d5f4a781c60f33ac22c6096ed Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Tue, 3 Apr 2012 21:24:46 +0200 Subject: move imported udev into place --- src/udev/.gitignore | 32 +- src/udev/COPYING | 339 -- src/udev/ChangeLog | 6387 -------------------- src/udev/INSTALL | 44 - src/udev/Makefile.am | 712 --- src/udev/NEWS | 1735 ------ src/udev/README | 101 - src/udev/TODO | 22 - src/udev/accelerometer/61-accelerometer.rules | 3 + src/udev/accelerometer/accelerometer.c | 357 ++ src/udev/ata_id/ata_id.c | 721 +++ src/udev/autogen.sh | 44 - src/udev/cdrom_id/60-cdrom_id.rules | 20 + src/udev/cdrom_id/cdrom_id.c | 1099 ++++ src/udev/collect/collect.c | 473 ++ src/udev/configure.ac | 242 - src/udev/docs/.gitignore | 18 + src/udev/docs/Makefile.am | 99 + src/udev/docs/libudev-docs.xml | 32 + src/udev/docs/libudev-sections.txt | 127 + src/udev/docs/libudev.types | 0 src/udev/docs/version.xml.in | 1 + src/udev/gudev/.gitignore | 9 + src/udev/gudev/docs/.gitignore | 17 + src/udev/gudev/docs/Makefile.am | 106 + src/udev/gudev/docs/gudev-docs.xml | 93 + src/udev/gudev/docs/gudev-sections.txt | 113 + src/udev/gudev/docs/gudev.types | 4 + src/udev/gudev/docs/version.xml.in | 1 + src/udev/gudev/gjs-example.js | 75 + src/udev/gudev/gudev-1.0.pc.in | 11 + src/udev/gudev/gudev.h | 33 + src/udev/gudev/gudevclient.c | 527 ++ src/udev/gudev/gudevclient.h | 100 + src/udev/gudev/gudevdevice.c | 963 +++ src/udev/gudev/gudevdevice.h | 128 + src/udev/gudev/gudevenumerator.c | 431 ++ src/udev/gudev/gudevenumerator.h | 107 + src/udev/gudev/gudevenums.h | 49 + src/udev/gudev/gudevenumtypes.c.template | 39 + src/udev/gudev/gudevenumtypes.h.template | 24 + src/udev/gudev/gudevmarshal.list | 1 + src/udev/gudev/gudevprivate.h | 41 + src/udev/gudev/gudevtypes.h | 51 + src/udev/gudev/seed-example-enum.js | 38 + src/udev/gudev/seed-example.js | 72 + src/udev/keymap/.gitignore | 5 + src/udev/keymap/95-keyboard-force-release.rules | 54 + src/udev/keymap/95-keymap.rules | 170 + src/udev/keymap/README.keymap.txt | 101 + src/udev/keymap/check-keymaps.sh | 38 + src/udev/keymap/findkeyboards | 68 + .../keymap/force-release-maps/common-volume-keys | 3 + src/udev/keymap/force-release-maps/dell-touchpad | 1 + src/udev/keymap/force-release-maps/hp-other | 3 + src/udev/keymap/force-release-maps/samsung-90x3a | 6 + src/udev/keymap/force-release-maps/samsung-other | 10 + src/udev/keymap/keyboard-force-release.sh.in | 22 + src/udev/keymap/keymap.c | 447 ++ src/udev/keymap/keymaps/acer | 22 + src/udev/keymap/keymaps/acer-aspire_5720 | 4 + src/udev/keymap/keymaps/acer-aspire_5920g | 5 + src/udev/keymap/keymaps/acer-aspire_6920 | 5 + src/udev/keymap/keymaps/acer-aspire_8930 | 5 + src/udev/keymap/keymaps/acer-travelmate_c300 | 5 + src/udev/keymap/keymaps/asus | 3 + src/udev/keymap/keymaps/compaq-e_evo | 4 + src/udev/keymap/keymaps/dell | 29 + src/udev/keymap/keymaps/dell-latitude-xt2 | 4 + src/udev/keymap/keymaps/everex-xt5000 | 7 + src/udev/keymap/keymaps/fujitsu-amilo_li_2732 | 3 + src/udev/keymap/keymaps/fujitsu-amilo_pa_2548 | 3 + .../keymap/keymaps/fujitsu-amilo_pro_edition_v3505 | 4 + src/udev/keymap/keymaps/fujitsu-amilo_pro_v3205 | 2 + src/udev/keymap/keymaps/fujitsu-amilo_si_1520 | 6 + src/udev/keymap/keymaps/fujitsu-esprimo_mobile_v5 | 4 + src/udev/keymap/keymaps/fujitsu-esprimo_mobile_v6 | 2 + src/udev/keymap/keymaps/genius-slimstar-320 | 35 + src/udev/keymap/keymaps/hewlett-packard | 12 + .../keymap/keymaps/hewlett-packard-2510p_2530p | 2 + .../keymaps/hewlett-packard-compaq_elitebook | 2 + src/udev/keymap/keymaps/hewlett-packard-pavilion | 3 + .../keymap/keymaps/hewlett-packard-presario-2100 | 3 + src/udev/keymap/keymaps/hewlett-packard-tablet | 6 + src/udev/keymap/keymaps/hewlett-packard-tx2 | 3 + .../keymaps/ibm-thinkpad-usb-keyboard-trackpoint | 7 + src/udev/keymap/keymaps/inventec-symphony_6.0_7.0 | 2 + src/udev/keymap/keymaps/lenovo-3000 | 5 + src/udev/keymap/keymaps/lenovo-ideapad | 8 + .../lenovo-thinkpad-usb-keyboard-trackpoint | 13 + .../keymap/keymaps/lenovo-thinkpad_x200_tablet | 6 + src/udev/keymap/keymaps/lenovo-thinkpad_x6_tablet | 8 + src/udev/keymap/keymaps/lg-x110 | 12 + src/udev/keymap/keymaps/logitech-wave | 16 + src/udev/keymap/keymaps/logitech-wave-cordless | 15 + src/udev/keymap/keymaps/logitech-wave-pro-cordless | 12 + src/udev/keymap/keymaps/maxdata-pro_7000 | 9 + src/udev/keymap/keymaps/medion-fid2060 | 2 + src/udev/keymap/keymaps/medionnb-a555 | 4 + src/udev/keymap/keymaps/micro-star | 13 + src/udev/keymap/keymaps/module-asus-w3j | 11 + src/udev/keymap/keymaps/module-ibm | 16 + src/udev/keymap/keymaps/module-lenovo | 17 + src/udev/keymap/keymaps/module-sony | 8 + src/udev/keymap/keymaps/module-sony-old | 2 + src/udev/keymap/keymaps/module-sony-vgn | 8 + src/udev/keymap/keymaps/olpc-xo | 74 + src/udev/keymap/keymaps/onkyo | 14 + src/udev/keymap/keymaps/oqo-model2 | 5 + src/udev/keymap/keymaps/samsung-90x3a | 5 + src/udev/keymap/keymaps/samsung-other | 14 + src/udev/keymap/keymaps/samsung-sq1us | 7 + src/udev/keymap/keymaps/samsung-sx20s | 4 + src/udev/keymap/keymaps/toshiba-satellite_a100 | 2 + src/udev/keymap/keymaps/toshiba-satellite_a110 | 10 + src/udev/keymap/keymaps/toshiba-satellite_m30x | 6 + src/udev/keymap/keymaps/zepto-znote | 11 + src/udev/libudev-device-private.c | 185 + src/udev/libudev-device.c | 1744 ++++++ src/udev/libudev-enumerate.c | 947 +++ src/udev/libudev-list.c | 344 ++ src/udev/libudev-monitor.c | 874 +++ src/udev/libudev-private.h | 213 + src/udev/libudev-queue-private.c | 412 ++ src/udev/libudev-queue.c | 474 ++ src/udev/libudev-selinux-private.c | 109 + src/udev/libudev-util-private.c | 242 + src/udev/libudev-util.c | 570 ++ src/udev/libudev.c | 457 ++ src/udev/libudev.h | 189 + src/udev/libudev.pc.in | 11 + src/udev/m4/.gitignore | 4 - src/udev/mtd_probe/75-probe_mtd.rules | 8 + src/udev/mtd_probe/mtd_probe.c | 51 + src/udev/mtd_probe/mtd_probe.h | 49 + src/udev/mtd_probe/probe_smartmedia.c | 97 + src/udev/rules/42-usb-hid-pm.rules | 49 - src/udev/rules/50-udev-default.rules | 107 - src/udev/rules/60-persistent-alsa.rules | 14 - src/udev/rules/60-persistent-input.rules | 38 - src/udev/rules/60-persistent-serial.rules | 20 - src/udev/rules/60-persistent-storage-tape.rules | 25 - src/udev/rules/60-persistent-storage.rules | 89 - src/udev/rules/75-net-description.rules | 14 - src/udev/rules/75-tty-description.rules | 14 - src/udev/rules/78-sound-card.rules | 89 - src/udev/rules/80-drivers.rules | 12 - src/udev/rules/95-udev-late.rules | 4 - src/udev/scsi_id/.gitignore | 1 + src/udev/scsi_id/README | 4 + src/udev/scsi_id/scsi.h | 97 + src/udev/scsi_id/scsi_id.c | 657 ++ src/udev/scsi_id/scsi_id.h | 73 + src/udev/scsi_id/scsi_serial.c | 990 +++ src/udev/src/.gitignore | 5 - src/udev/src/COPYING | 502 -- src/udev/src/accelerometer/61-accelerometer.rules | 3 - src/udev/src/accelerometer/accelerometer.c | 357 -- src/udev/src/ata_id/ata_id.c | 721 --- src/udev/src/cdrom_id/60-cdrom_id.rules | 20 - src/udev/src/cdrom_id/cdrom_id.c | 1099 ---- src/udev/src/collect/collect.c | 473 -- src/udev/src/docs/.gitignore | 17 - src/udev/src/docs/Makefile.am | 99 - src/udev/src/docs/libudev-docs.xml | 32 - src/udev/src/docs/libudev-sections.txt | 127 - src/udev/src/docs/libudev.types | 0 src/udev/src/docs/version.xml.in | 1 - src/udev/src/floppy/60-floppy.rules | 4 - src/udev/src/floppy/create_floppy_devices.c | 177 - src/udev/src/gudev/.gitignore | 9 - src/udev/src/gudev/COPYING | 502 -- src/udev/src/gudev/docs/.gitignore | 16 - src/udev/src/gudev/docs/Makefile.am | 106 - src/udev/src/gudev/docs/gudev-docs.xml | 93 - src/udev/src/gudev/docs/gudev-sections.txt | 113 - src/udev/src/gudev/docs/gudev.types | 4 - src/udev/src/gudev/docs/version.xml.in | 1 - src/udev/src/gudev/gjs-example.js | 75 - src/udev/src/gudev/gudev-1.0.pc.in | 11 - src/udev/src/gudev/gudev.h | 33 - src/udev/src/gudev/gudevclient.c | 527 -- src/udev/src/gudev/gudevclient.h | 100 - src/udev/src/gudev/gudevdevice.c | 963 --- src/udev/src/gudev/gudevdevice.h | 128 - src/udev/src/gudev/gudevenumerator.c | 431 -- src/udev/src/gudev/gudevenumerator.h | 107 - src/udev/src/gudev/gudevenums.h | 49 - src/udev/src/gudev/gudevenumtypes.c.template | 39 - src/udev/src/gudev/gudevenumtypes.h.template | 24 - src/udev/src/gudev/gudevmarshal.list | 1 - src/udev/src/gudev/gudevprivate.h | 41 - src/udev/src/gudev/gudevtypes.h | 51 - src/udev/src/gudev/seed-example-enum.js | 38 - src/udev/src/gudev/seed-example.js | 72 - src/udev/src/keymap/.gitignore | 5 - .../src/keymap/95-keyboard-force-release.rules | 54 - src/udev/src/keymap/95-keymap.rules | 170 - src/udev/src/keymap/README.keymap.txt | 101 - src/udev/src/keymap/check-keymaps.sh | 38 - src/udev/src/keymap/findkeyboards | 68 - .../keymap/force-release-maps/common-volume-keys | 3 - .../src/keymap/force-release-maps/dell-touchpad | 1 - src/udev/src/keymap/force-release-maps/hp-other | 3 - .../src/keymap/force-release-maps/samsung-90x3a | 6 - .../src/keymap/force-release-maps/samsung-other | 10 - src/udev/src/keymap/keyboard-force-release.sh.in | 22 - src/udev/src/keymap/keymap.c | 447 -- src/udev/src/keymap/keymaps/acer | 22 - src/udev/src/keymap/keymaps/acer-aspire_5720 | 4 - src/udev/src/keymap/keymaps/acer-aspire_5920g | 5 - src/udev/src/keymap/keymaps/acer-aspire_6920 | 5 - src/udev/src/keymap/keymaps/acer-aspire_8930 | 5 - src/udev/src/keymap/keymaps/acer-travelmate_c300 | 5 - src/udev/src/keymap/keymaps/asus | 3 - src/udev/src/keymap/keymaps/compaq-e_evo | 4 - src/udev/src/keymap/keymaps/dell | 29 - src/udev/src/keymap/keymaps/dell-latitude-xt2 | 4 - src/udev/src/keymap/keymaps/everex-xt5000 | 7 - src/udev/src/keymap/keymaps/fujitsu-amilo_li_2732 | 3 - src/udev/src/keymap/keymaps/fujitsu-amilo_pa_2548 | 3 - .../keymap/keymaps/fujitsu-amilo_pro_edition_v3505 | 4 - .../src/keymap/keymaps/fujitsu-amilo_pro_v3205 | 2 - src/udev/src/keymap/keymaps/fujitsu-amilo_si_1520 | 6 - .../src/keymap/keymaps/fujitsu-esprimo_mobile_v5 | 4 - .../src/keymap/keymaps/fujitsu-esprimo_mobile_v6 | 2 - src/udev/src/keymap/keymaps/genius-slimstar-320 | 35 - src/udev/src/keymap/keymaps/hewlett-packard | 12 - .../src/keymap/keymaps/hewlett-packard-2510p_2530p | 2 - .../keymaps/hewlett-packard-compaq_elitebook | 2 - .../src/keymap/keymaps/hewlett-packard-pavilion | 3 - .../keymap/keymaps/hewlett-packard-presario-2100 | 3 - src/udev/src/keymap/keymaps/hewlett-packard-tablet | 6 - src/udev/src/keymap/keymaps/hewlett-packard-tx2 | 3 - .../keymaps/ibm-thinkpad-usb-keyboard-trackpoint | 7 - .../src/keymap/keymaps/inventec-symphony_6.0_7.0 | 2 - src/udev/src/keymap/keymaps/lenovo-3000 | 5 - src/udev/src/keymap/keymaps/lenovo-ideapad | 8 - .../lenovo-thinkpad-usb-keyboard-trackpoint | 13 - .../src/keymap/keymaps/lenovo-thinkpad_x200_tablet | 6 - .../src/keymap/keymaps/lenovo-thinkpad_x6_tablet | 8 - src/udev/src/keymap/keymaps/lg-x110 | 12 - src/udev/src/keymap/keymaps/logitech-wave | 16 - src/udev/src/keymap/keymaps/logitech-wave-cordless | 15 - .../src/keymap/keymaps/logitech-wave-pro-cordless | 12 - src/udev/src/keymap/keymaps/maxdata-pro_7000 | 9 - src/udev/src/keymap/keymaps/medion-fid2060 | 2 - src/udev/src/keymap/keymaps/medionnb-a555 | 4 - src/udev/src/keymap/keymaps/micro-star | 13 - src/udev/src/keymap/keymaps/module-asus-w3j | 11 - src/udev/src/keymap/keymaps/module-ibm | 16 - src/udev/src/keymap/keymaps/module-lenovo | 17 - src/udev/src/keymap/keymaps/module-sony | 8 - src/udev/src/keymap/keymaps/module-sony-old | 2 - src/udev/src/keymap/keymaps/module-sony-vgn | 8 - src/udev/src/keymap/keymaps/olpc-xo | 74 - src/udev/src/keymap/keymaps/onkyo | 14 - src/udev/src/keymap/keymaps/oqo-model2 | 5 - src/udev/src/keymap/keymaps/samsung-90x3a | 5 - src/udev/src/keymap/keymaps/samsung-other | 14 - src/udev/src/keymap/keymaps/samsung-sq1us | 7 - src/udev/src/keymap/keymaps/samsung-sx20s | 4 - src/udev/src/keymap/keymaps/toshiba-satellite_a100 | 2 - src/udev/src/keymap/keymaps/toshiba-satellite_a110 | 10 - src/udev/src/keymap/keymaps/toshiba-satellite_m30x | 6 - src/udev/src/keymap/keymaps/zepto-znote | 11 - src/udev/src/libudev-device-private.c | 185 - src/udev/src/libudev-device.c | 1744 ------ src/udev/src/libudev-enumerate.c | 947 --- src/udev/src/libudev-list.c | 344 -- src/udev/src/libudev-monitor.c | 874 --- src/udev/src/libudev-private.h | 213 - src/udev/src/libudev-queue-private.c | 412 -- src/udev/src/libudev-queue.c | 474 -- src/udev/src/libudev-selinux-private.c | 109 - src/udev/src/libudev-util-private.c | 242 - src/udev/src/libudev-util.c | 570 -- src/udev/src/libudev.c | 457 -- src/udev/src/libudev.h | 189 - src/udev/src/libudev.pc.in | 11 - src/udev/src/mtd_probe/75-probe_mtd.rules | 8 - src/udev/src/mtd_probe/mtd_probe.c | 51 - src/udev/src/mtd_probe/mtd_probe.h | 49 - src/udev/src/mtd_probe/probe_smartmedia.c | 97 - .../rule_generator/75-cd-aliases-generator.rules | 9 - .../75-persistent-net-generator.rules | 102 - .../src/rule_generator/rule_generator.functions | 113 - src/udev/src/rule_generator/write_cd_rules | 126 - src/udev/src/rule_generator/write_net_rules | 141 - src/udev/src/scsi_id/.gitignore | 1 - src/udev/src/scsi_id/README | 4 - src/udev/src/scsi_id/scsi.h | 97 - src/udev/src/scsi_id/scsi_id.8 | 119 - src/udev/src/scsi_id/scsi_id.c | 657 -- src/udev/src/scsi_id/scsi_id.h | 73 - src/udev/src/scsi_id/scsi_serial.c | 990 --- src/udev/src/sd-daemon.c | 530 -- src/udev/src/sd-daemon.h | 282 - src/udev/src/test-libudev.c | 501 -- src/udev/src/test-udev.c | 121 - src/udev/src/udev-builtin-blkid.c | 207 - src/udev/src/udev-builtin-firmware.c | 168 - src/udev/src/udev-builtin-hwdb.c | 247 - src/udev/src/udev-builtin-input_id.c | 218 - src/udev/src/udev-builtin-kmod.c | 142 - src/udev/src/udev-builtin-path_id.c | 498 -- src/udev/src/udev-builtin-usb_id.c | 482 -- src/udev/src/udev-builtin.c | 134 - src/udev/src/udev-control.socket | 10 - src/udev/src/udev-ctrl.c | 494 -- src/udev/src/udev-event.c | 1011 ---- src/udev/src/udev-kernel.socket | 10 - src/udev/src/udev-node.c | 379 -- src/udev/src/udev-rules.c | 2767 --------- src/udev/src/udev-settle.service.in | 25 - src/udev/src/udev-trigger.service.in | 10 - src/udev/src/udev-watch.c | 170 - src/udev/src/udev.conf | 3 - src/udev/src/udev.h | 188 - src/udev/src/udev.pc.in | 5 - src/udev/src/udev.service.in | 14 - src/udev/src/udev.xml | 695 --- src/udev/src/udevadm-control.c | 175 - src/udev/src/udevadm-info.c | 568 -- src/udev/src/udevadm-monitor.c | 297 - src/udev/src/udevadm-settle.c | 235 - src/udev/src/udevadm-test-builtin.c | 128 - src/udev/src/udevadm-test.c | 173 - src/udev/src/udevadm-trigger.c | 232 - src/udev/src/udevadm.c | 165 - src/udev/src/udevadm.xml | 472 -- src/udev/src/udevd.c | 1746 ------ src/udev/src/udevd.xml | 151 - src/udev/src/v4l_id/60-persistent-v4l.rules | 20 - src/udev/src/v4l_id/v4l_id.c | 87 - src/udev/test-libudev.c | 501 ++ src/udev/test-udev.c | 121 + src/udev/test/rules-test.sh | 2 +- src/udev/udev-builtin-blkid.c | 207 + src/udev/udev-builtin-firmware.c | 168 + src/udev/udev-builtin-hwdb.c | 247 + src/udev/udev-builtin-input_id.c | 218 + src/udev/udev-builtin-kmod.c | 142 + src/udev/udev-builtin-path_id.c | 498 ++ src/udev/udev-builtin-usb_id.c | 482 ++ src/udev/udev-builtin.c | 134 + src/udev/udev-ctrl.c | 494 ++ src/udev/udev-event.c | 1011 ++++ src/udev/udev-node.c | 379 ++ src/udev/udev-rules.c | 2767 +++++++++ src/udev/udev-watch.c | 170 + src/udev/udev.conf | 3 + src/udev/udev.h | 188 + src/udev/udev.pc.in | 5 + src/udev/udevadm-control.c | 175 + src/udev/udevadm-info.c | 568 ++ src/udev/udevadm-monitor.c | 297 + src/udev/udevadm-settle.c | 235 + src/udev/udevadm-test-builtin.c | 128 + src/udev/udevadm-test.c | 173 + src/udev/udevadm-trigger.c | 232 + src/udev/udevadm.c | 165 + src/udev/udevd.c | 1746 ++++++ src/udev/v4l_id/60-persistent-v4l.rules | 20 + src/udev/v4l_id/v4l_id.c | 87 + 365 files changed, 27805 insertions(+), 41929 deletions(-) delete mode 100644 src/udev/COPYING delete mode 100644 src/udev/ChangeLog delete mode 100644 src/udev/INSTALL delete mode 100644 src/udev/Makefile.am delete mode 100644 src/udev/NEWS delete mode 100644 src/udev/README delete mode 100644 src/udev/TODO create mode 100644 src/udev/accelerometer/61-accelerometer.rules create mode 100644 src/udev/accelerometer/accelerometer.c create mode 100644 src/udev/ata_id/ata_id.c delete mode 100755 src/udev/autogen.sh create mode 100644 src/udev/cdrom_id/60-cdrom_id.rules create mode 100644 src/udev/cdrom_id/cdrom_id.c create mode 100644 src/udev/collect/collect.c delete mode 100644 src/udev/configure.ac create mode 100644 src/udev/docs/.gitignore create mode 100644 src/udev/docs/Makefile.am create mode 100644 src/udev/docs/libudev-docs.xml create mode 100644 src/udev/docs/libudev-sections.txt create mode 100644 src/udev/docs/libudev.types create mode 100644 src/udev/docs/version.xml.in create mode 100644 src/udev/gudev/.gitignore create mode 100644 src/udev/gudev/docs/.gitignore create mode 100644 src/udev/gudev/docs/Makefile.am create mode 100644 src/udev/gudev/docs/gudev-docs.xml create mode 100644 src/udev/gudev/docs/gudev-sections.txt create mode 100644 src/udev/gudev/docs/gudev.types create mode 100644 src/udev/gudev/docs/version.xml.in create mode 100755 src/udev/gudev/gjs-example.js create mode 100644 src/udev/gudev/gudev-1.0.pc.in create mode 100644 src/udev/gudev/gudev.h create mode 100644 src/udev/gudev/gudevclient.c create mode 100644 src/udev/gudev/gudevclient.h create mode 100644 src/udev/gudev/gudevdevice.c create mode 100644 src/udev/gudev/gudevdevice.h create mode 100644 src/udev/gudev/gudevenumerator.c create mode 100644 src/udev/gudev/gudevenumerator.h create mode 100644 src/udev/gudev/gudevenums.h create mode 100644 src/udev/gudev/gudevenumtypes.c.template create mode 100644 src/udev/gudev/gudevenumtypes.h.template create mode 100644 src/udev/gudev/gudevmarshal.list create mode 100644 src/udev/gudev/gudevprivate.h create mode 100644 src/udev/gudev/gudevtypes.h create mode 100755 src/udev/gudev/seed-example-enum.js create mode 100755 src/udev/gudev/seed-example.js create mode 100644 src/udev/keymap/.gitignore create mode 100644 src/udev/keymap/95-keyboard-force-release.rules create mode 100644 src/udev/keymap/95-keymap.rules create mode 100644 src/udev/keymap/README.keymap.txt create mode 100755 src/udev/keymap/check-keymaps.sh create mode 100755 src/udev/keymap/findkeyboards create mode 100644 src/udev/keymap/force-release-maps/common-volume-keys create mode 100644 src/udev/keymap/force-release-maps/dell-touchpad create mode 100644 src/udev/keymap/force-release-maps/hp-other create mode 100644 src/udev/keymap/force-release-maps/samsung-90x3a create mode 100644 src/udev/keymap/force-release-maps/samsung-other create mode 100755 src/udev/keymap/keyboard-force-release.sh.in create mode 100644 src/udev/keymap/keymap.c create mode 100644 src/udev/keymap/keymaps/acer create mode 100644 src/udev/keymap/keymaps/acer-aspire_5720 create mode 100644 src/udev/keymap/keymaps/acer-aspire_5920g create mode 100644 src/udev/keymap/keymaps/acer-aspire_6920 create mode 100644 src/udev/keymap/keymaps/acer-aspire_8930 create mode 100644 src/udev/keymap/keymaps/acer-travelmate_c300 create mode 100644 src/udev/keymap/keymaps/asus create mode 100644 src/udev/keymap/keymaps/compaq-e_evo create mode 100644 src/udev/keymap/keymaps/dell create mode 100644 src/udev/keymap/keymaps/dell-latitude-xt2 create mode 100644 src/udev/keymap/keymaps/everex-xt5000 create mode 100644 src/udev/keymap/keymaps/fujitsu-amilo_li_2732 create mode 100644 src/udev/keymap/keymaps/fujitsu-amilo_pa_2548 create mode 100644 src/udev/keymap/keymaps/fujitsu-amilo_pro_edition_v3505 create mode 100644 src/udev/keymap/keymaps/fujitsu-amilo_pro_v3205 create mode 100644 src/udev/keymap/keymaps/fujitsu-amilo_si_1520 create mode 100644 src/udev/keymap/keymaps/fujitsu-esprimo_mobile_v5 create mode 100644 src/udev/keymap/keymaps/fujitsu-esprimo_mobile_v6 create mode 100644 src/udev/keymap/keymaps/genius-slimstar-320 create mode 100644 src/udev/keymap/keymaps/hewlett-packard create mode 100644 src/udev/keymap/keymaps/hewlett-packard-2510p_2530p create mode 100644 src/udev/keymap/keymaps/hewlett-packard-compaq_elitebook create mode 100644 src/udev/keymap/keymaps/hewlett-packard-pavilion create mode 100644 src/udev/keymap/keymaps/hewlett-packard-presario-2100 create mode 100644 src/udev/keymap/keymaps/hewlett-packard-tablet create mode 100644 src/udev/keymap/keymaps/hewlett-packard-tx2 create mode 100644 src/udev/keymap/keymaps/ibm-thinkpad-usb-keyboard-trackpoint create mode 100644 src/udev/keymap/keymaps/inventec-symphony_6.0_7.0 create mode 100644 src/udev/keymap/keymaps/lenovo-3000 create mode 100644 src/udev/keymap/keymaps/lenovo-ideapad create mode 100644 src/udev/keymap/keymaps/lenovo-thinkpad-usb-keyboard-trackpoint create mode 100644 src/udev/keymap/keymaps/lenovo-thinkpad_x200_tablet create mode 100644 src/udev/keymap/keymaps/lenovo-thinkpad_x6_tablet create mode 100644 src/udev/keymap/keymaps/lg-x110 create mode 100644 src/udev/keymap/keymaps/logitech-wave create mode 100644 src/udev/keymap/keymaps/logitech-wave-cordless create mode 100644 src/udev/keymap/keymaps/logitech-wave-pro-cordless create mode 100644 src/udev/keymap/keymaps/maxdata-pro_7000 create mode 100644 src/udev/keymap/keymaps/medion-fid2060 create mode 100644 src/udev/keymap/keymaps/medionnb-a555 create mode 100644 src/udev/keymap/keymaps/micro-star create mode 100644 src/udev/keymap/keymaps/module-asus-w3j create mode 100644 src/udev/keymap/keymaps/module-ibm create mode 100644 src/udev/keymap/keymaps/module-lenovo create mode 100644 src/udev/keymap/keymaps/module-sony create mode 100644 src/udev/keymap/keymaps/module-sony-old create mode 100644 src/udev/keymap/keymaps/module-sony-vgn create mode 100644 src/udev/keymap/keymaps/olpc-xo create mode 100644 src/udev/keymap/keymaps/onkyo create mode 100644 src/udev/keymap/keymaps/oqo-model2 create mode 100644 src/udev/keymap/keymaps/samsung-90x3a create mode 100644 src/udev/keymap/keymaps/samsung-other create mode 100644 src/udev/keymap/keymaps/samsung-sq1us create mode 100644 src/udev/keymap/keymaps/samsung-sx20s create mode 100644 src/udev/keymap/keymaps/toshiba-satellite_a100 create mode 100644 src/udev/keymap/keymaps/toshiba-satellite_a110 create mode 100644 src/udev/keymap/keymaps/toshiba-satellite_m30x create mode 100644 src/udev/keymap/keymaps/zepto-znote create mode 100644 src/udev/libudev-device-private.c create mode 100644 src/udev/libudev-device.c create mode 100644 src/udev/libudev-enumerate.c create mode 100644 src/udev/libudev-list.c create mode 100644 src/udev/libudev-monitor.c create mode 100644 src/udev/libudev-private.h create mode 100644 src/udev/libudev-queue-private.c create mode 100644 src/udev/libudev-queue.c create mode 100644 src/udev/libudev-selinux-private.c create mode 100644 src/udev/libudev-util-private.c create mode 100644 src/udev/libudev-util.c create mode 100644 src/udev/libudev.c create mode 100644 src/udev/libudev.h create mode 100644 src/udev/libudev.pc.in delete mode 100644 src/udev/m4/.gitignore create mode 100644 src/udev/mtd_probe/75-probe_mtd.rules create mode 100644 src/udev/mtd_probe/mtd_probe.c create mode 100644 src/udev/mtd_probe/mtd_probe.h create mode 100644 src/udev/mtd_probe/probe_smartmedia.c delete mode 100644 src/udev/rules/42-usb-hid-pm.rules delete mode 100644 src/udev/rules/50-udev-default.rules delete mode 100644 src/udev/rules/60-persistent-alsa.rules delete mode 100644 src/udev/rules/60-persistent-input.rules delete mode 100644 src/udev/rules/60-persistent-serial.rules delete mode 100644 src/udev/rules/60-persistent-storage-tape.rules delete mode 100644 src/udev/rules/60-persistent-storage.rules delete mode 100644 src/udev/rules/75-net-description.rules delete mode 100644 src/udev/rules/75-tty-description.rules delete mode 100644 src/udev/rules/78-sound-card.rules delete mode 100644 src/udev/rules/80-drivers.rules delete mode 100644 src/udev/rules/95-udev-late.rules create mode 100644 src/udev/scsi_id/.gitignore create mode 100644 src/udev/scsi_id/README create mode 100644 src/udev/scsi_id/scsi.h create mode 100644 src/udev/scsi_id/scsi_id.c create mode 100644 src/udev/scsi_id/scsi_id.h create mode 100644 src/udev/scsi_id/scsi_serial.c delete mode 100644 src/udev/src/.gitignore delete mode 100644 src/udev/src/COPYING delete mode 100644 src/udev/src/accelerometer/61-accelerometer.rules delete mode 100644 src/udev/src/accelerometer/accelerometer.c delete mode 100644 src/udev/src/ata_id/ata_id.c delete mode 100644 src/udev/src/cdrom_id/60-cdrom_id.rules delete mode 100644 src/udev/src/cdrom_id/cdrom_id.c delete mode 100644 src/udev/src/collect/collect.c delete mode 100644 src/udev/src/docs/.gitignore delete mode 100644 src/udev/src/docs/Makefile.am delete mode 100644 src/udev/src/docs/libudev-docs.xml delete mode 100644 src/udev/src/docs/libudev-sections.txt delete mode 100644 src/udev/src/docs/libudev.types delete mode 100644 src/udev/src/docs/version.xml.in delete mode 100644 src/udev/src/floppy/60-floppy.rules delete mode 100644 src/udev/src/floppy/create_floppy_devices.c delete mode 100644 src/udev/src/gudev/.gitignore delete mode 100644 src/udev/src/gudev/COPYING delete mode 100644 src/udev/src/gudev/docs/.gitignore delete mode 100644 src/udev/src/gudev/docs/Makefile.am delete mode 100644 src/udev/src/gudev/docs/gudev-docs.xml delete mode 100644 src/udev/src/gudev/docs/gudev-sections.txt delete mode 100644 src/udev/src/gudev/docs/gudev.types delete mode 100644 src/udev/src/gudev/docs/version.xml.in delete mode 100755 src/udev/src/gudev/gjs-example.js delete mode 100644 src/udev/src/gudev/gudev-1.0.pc.in delete mode 100644 src/udev/src/gudev/gudev.h delete mode 100644 src/udev/src/gudev/gudevclient.c delete mode 100644 src/udev/src/gudev/gudevclient.h delete mode 100644 src/udev/src/gudev/gudevdevice.c delete mode 100644 src/udev/src/gudev/gudevdevice.h delete mode 100644 src/udev/src/gudev/gudevenumerator.c delete mode 100644 src/udev/src/gudev/gudevenumerator.h delete mode 100644 src/udev/src/gudev/gudevenums.h delete mode 100644 src/udev/src/gudev/gudevenumtypes.c.template delete mode 100644 src/udev/src/gudev/gudevenumtypes.h.template delete mode 100644 src/udev/src/gudev/gudevmarshal.list delete mode 100644 src/udev/src/gudev/gudevprivate.h delete mode 100644 src/udev/src/gudev/gudevtypes.h delete mode 100755 src/udev/src/gudev/seed-example-enum.js delete mode 100755 src/udev/src/gudev/seed-example.js delete mode 100644 src/udev/src/keymap/.gitignore delete mode 100644 src/udev/src/keymap/95-keyboard-force-release.rules delete mode 100644 src/udev/src/keymap/95-keymap.rules delete mode 100644 src/udev/src/keymap/README.keymap.txt delete mode 100755 src/udev/src/keymap/check-keymaps.sh delete mode 100755 src/udev/src/keymap/findkeyboards delete mode 100644 src/udev/src/keymap/force-release-maps/common-volume-keys delete mode 100644 src/udev/src/keymap/force-release-maps/dell-touchpad delete mode 100644 src/udev/src/keymap/force-release-maps/hp-other delete mode 100644 src/udev/src/keymap/force-release-maps/samsung-90x3a delete mode 100644 src/udev/src/keymap/force-release-maps/samsung-other delete mode 100755 src/udev/src/keymap/keyboard-force-release.sh.in delete mode 100644 src/udev/src/keymap/keymap.c delete mode 100644 src/udev/src/keymap/keymaps/acer delete mode 100644 src/udev/src/keymap/keymaps/acer-aspire_5720 delete mode 100644 src/udev/src/keymap/keymaps/acer-aspire_5920g delete mode 100644 src/udev/src/keymap/keymaps/acer-aspire_6920 delete mode 100644 src/udev/src/keymap/keymaps/acer-aspire_8930 delete mode 100644 src/udev/src/keymap/keymaps/acer-travelmate_c300 delete mode 100644 src/udev/src/keymap/keymaps/asus delete mode 100644 src/udev/src/keymap/keymaps/compaq-e_evo delete mode 100644 src/udev/src/keymap/keymaps/dell delete mode 100644 src/udev/src/keymap/keymaps/dell-latitude-xt2 delete mode 100644 src/udev/src/keymap/keymaps/everex-xt5000 delete mode 100644 src/udev/src/keymap/keymaps/fujitsu-amilo_li_2732 delete mode 100644 src/udev/src/keymap/keymaps/fujitsu-amilo_pa_2548 delete mode 100644 src/udev/src/keymap/keymaps/fujitsu-amilo_pro_edition_v3505 delete mode 100644 src/udev/src/keymap/keymaps/fujitsu-amilo_pro_v3205 delete mode 100644 src/udev/src/keymap/keymaps/fujitsu-amilo_si_1520 delete mode 100644 src/udev/src/keymap/keymaps/fujitsu-esprimo_mobile_v5 delete mode 100644 src/udev/src/keymap/keymaps/fujitsu-esprimo_mobile_v6 delete mode 100644 src/udev/src/keymap/keymaps/genius-slimstar-320 delete mode 100644 src/udev/src/keymap/keymaps/hewlett-packard delete mode 100644 src/udev/src/keymap/keymaps/hewlett-packard-2510p_2530p delete mode 100644 src/udev/src/keymap/keymaps/hewlett-packard-compaq_elitebook delete mode 100644 src/udev/src/keymap/keymaps/hewlett-packard-pavilion delete mode 100644 src/udev/src/keymap/keymaps/hewlett-packard-presario-2100 delete mode 100644 src/udev/src/keymap/keymaps/hewlett-packard-tablet delete mode 100644 src/udev/src/keymap/keymaps/hewlett-packard-tx2 delete mode 100644 src/udev/src/keymap/keymaps/ibm-thinkpad-usb-keyboard-trackpoint delete mode 100644 src/udev/src/keymap/keymaps/inventec-symphony_6.0_7.0 delete mode 100644 src/udev/src/keymap/keymaps/lenovo-3000 delete mode 100644 src/udev/src/keymap/keymaps/lenovo-ideapad delete mode 100644 src/udev/src/keymap/keymaps/lenovo-thinkpad-usb-keyboard-trackpoint delete mode 100644 src/udev/src/keymap/keymaps/lenovo-thinkpad_x200_tablet delete mode 100644 src/udev/src/keymap/keymaps/lenovo-thinkpad_x6_tablet delete mode 100644 src/udev/src/keymap/keymaps/lg-x110 delete mode 100644 src/udev/src/keymap/keymaps/logitech-wave delete mode 100644 src/udev/src/keymap/keymaps/logitech-wave-cordless delete mode 100644 src/udev/src/keymap/keymaps/logitech-wave-pro-cordless delete mode 100644 src/udev/src/keymap/keymaps/maxdata-pro_7000 delete mode 100644 src/udev/src/keymap/keymaps/medion-fid2060 delete mode 100644 src/udev/src/keymap/keymaps/medionnb-a555 delete mode 100644 src/udev/src/keymap/keymaps/micro-star delete mode 100644 src/udev/src/keymap/keymaps/module-asus-w3j delete mode 100644 src/udev/src/keymap/keymaps/module-ibm delete mode 100644 src/udev/src/keymap/keymaps/module-lenovo delete mode 100644 src/udev/src/keymap/keymaps/module-sony delete mode 100644 src/udev/src/keymap/keymaps/module-sony-old delete mode 100644 src/udev/src/keymap/keymaps/module-sony-vgn delete mode 100644 src/udev/src/keymap/keymaps/olpc-xo delete mode 100644 src/udev/src/keymap/keymaps/onkyo delete mode 100644 src/udev/src/keymap/keymaps/oqo-model2 delete mode 100644 src/udev/src/keymap/keymaps/samsung-90x3a delete mode 100644 src/udev/src/keymap/keymaps/samsung-other delete mode 100644 src/udev/src/keymap/keymaps/samsung-sq1us delete mode 100644 src/udev/src/keymap/keymaps/samsung-sx20s delete mode 100644 src/udev/src/keymap/keymaps/toshiba-satellite_a100 delete mode 100644 src/udev/src/keymap/keymaps/toshiba-satellite_a110 delete mode 100644 src/udev/src/keymap/keymaps/toshiba-satellite_m30x delete mode 100644 src/udev/src/keymap/keymaps/zepto-znote delete mode 100644 src/udev/src/libudev-device-private.c delete mode 100644 src/udev/src/libudev-device.c delete mode 100644 src/udev/src/libudev-enumerate.c delete mode 100644 src/udev/src/libudev-list.c delete mode 100644 src/udev/src/libudev-monitor.c delete mode 100644 src/udev/src/libudev-private.h delete mode 100644 src/udev/src/libudev-queue-private.c delete mode 100644 src/udev/src/libudev-queue.c delete mode 100644 src/udev/src/libudev-selinux-private.c delete mode 100644 src/udev/src/libudev-util-private.c delete mode 100644 src/udev/src/libudev-util.c delete mode 100644 src/udev/src/libudev.c delete mode 100644 src/udev/src/libudev.h delete mode 100644 src/udev/src/libudev.pc.in delete mode 100644 src/udev/src/mtd_probe/75-probe_mtd.rules delete mode 100644 src/udev/src/mtd_probe/mtd_probe.c delete mode 100644 src/udev/src/mtd_probe/mtd_probe.h delete mode 100644 src/udev/src/mtd_probe/probe_smartmedia.c delete mode 100644 src/udev/src/rule_generator/75-cd-aliases-generator.rules delete mode 100644 src/udev/src/rule_generator/75-persistent-net-generator.rules delete mode 100644 src/udev/src/rule_generator/rule_generator.functions delete mode 100644 src/udev/src/rule_generator/write_cd_rules delete mode 100644 src/udev/src/rule_generator/write_net_rules delete mode 100644 src/udev/src/scsi_id/.gitignore delete mode 100644 src/udev/src/scsi_id/README delete mode 100644 src/udev/src/scsi_id/scsi.h delete mode 100644 src/udev/src/scsi_id/scsi_id.8 delete mode 100644 src/udev/src/scsi_id/scsi_id.c delete mode 100644 src/udev/src/scsi_id/scsi_id.h delete mode 100644 src/udev/src/scsi_id/scsi_serial.c delete mode 100644 src/udev/src/sd-daemon.c delete mode 100644 src/udev/src/sd-daemon.h delete mode 100644 src/udev/src/test-libudev.c delete mode 100644 src/udev/src/test-udev.c delete mode 100644 src/udev/src/udev-builtin-blkid.c delete mode 100644 src/udev/src/udev-builtin-firmware.c delete mode 100644 src/udev/src/udev-builtin-hwdb.c delete mode 100644 src/udev/src/udev-builtin-input_id.c delete mode 100644 src/udev/src/udev-builtin-kmod.c delete mode 100644 src/udev/src/udev-builtin-path_id.c delete mode 100644 src/udev/src/udev-builtin-usb_id.c delete mode 100644 src/udev/src/udev-builtin.c delete mode 100644 src/udev/src/udev-control.socket delete mode 100644 src/udev/src/udev-ctrl.c delete mode 100644 src/udev/src/udev-event.c delete mode 100644 src/udev/src/udev-kernel.socket delete mode 100644 src/udev/src/udev-node.c delete mode 100644 src/udev/src/udev-rules.c delete mode 100644 src/udev/src/udev-settle.service.in delete mode 100644 src/udev/src/udev-trigger.service.in delete mode 100644 src/udev/src/udev-watch.c delete mode 100644 src/udev/src/udev.conf delete mode 100644 src/udev/src/udev.h delete mode 100644 src/udev/src/udev.pc.in delete mode 100644 src/udev/src/udev.service.in delete mode 100644 src/udev/src/udev.xml delete mode 100644 src/udev/src/udevadm-control.c delete mode 100644 src/udev/src/udevadm-info.c delete mode 100644 src/udev/src/udevadm-monitor.c delete mode 100644 src/udev/src/udevadm-settle.c delete mode 100644 src/udev/src/udevadm-test-builtin.c delete mode 100644 src/udev/src/udevadm-test.c delete mode 100644 src/udev/src/udevadm-trigger.c delete mode 100644 src/udev/src/udevadm.c delete mode 100644 src/udev/src/udevadm.xml delete mode 100644 src/udev/src/udevd.c delete mode 100644 src/udev/src/udevd.xml delete mode 100644 src/udev/src/v4l_id/60-persistent-v4l.rules delete mode 100644 src/udev/src/v4l_id/v4l_id.c create mode 100644 src/udev/test-libudev.c create mode 100644 src/udev/test-udev.c create mode 100644 src/udev/udev-builtin-blkid.c create mode 100644 src/udev/udev-builtin-firmware.c create mode 100644 src/udev/udev-builtin-hwdb.c create mode 100644 src/udev/udev-builtin-input_id.c create mode 100644 src/udev/udev-builtin-kmod.c create mode 100644 src/udev/udev-builtin-path_id.c create mode 100644 src/udev/udev-builtin-usb_id.c create mode 100644 src/udev/udev-builtin.c create mode 100644 src/udev/udev-ctrl.c create mode 100644 src/udev/udev-event.c create mode 100644 src/udev/udev-node.c create mode 100644 src/udev/udev-rules.c create mode 100644 src/udev/udev-watch.c create mode 100644 src/udev/udev.conf create mode 100644 src/udev/udev.h create mode 100644 src/udev/udev.pc.in create mode 100644 src/udev/udevadm-control.c create mode 100644 src/udev/udevadm-info.c create mode 100644 src/udev/udevadm-monitor.c create mode 100644 src/udev/udevadm-settle.c create mode 100644 src/udev/udevadm-test-builtin.c create mode 100644 src/udev/udevadm-test.c create mode 100644 src/udev/udevadm-trigger.c create mode 100644 src/udev/udevadm.c create mode 100644 src/udev/udevd.c create mode 100644 src/udev/v4l_id/60-persistent-v4l.rules create mode 100644 src/udev/v4l_id/v4l_id.c (limited to 'src/udev') diff --git a/src/udev/.gitignore b/src/udev/.gitignore index fa3500ba96..e697a57ec3 100644 --- a/src/udev/.gitignore +++ b/src/udev/.gitignore @@ -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 index d159169d10..0000000000 --- a/src/udev/COPYING +++ /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. - - - Copyright (C) - - 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. - - , 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 index dd58138263..0000000000 --- a/src/udev/ChangeLog +++ /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 -, if 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 _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= - 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{}=="" - 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=: - 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//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 : 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 - 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() 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{[/]} 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}/: and /dev/{block,char}/: - 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// - 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=" - write "event_timeout" to db - udevadm: trigger - add --env= option - udevadm: control - fix --env key to accept --env== - 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:" - 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=="*" 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= - 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]}="" 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=="" key - add "[$SUBSYSTEM/$KERNEL]" 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 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 - 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 - 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 ) - 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= 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 -============================================ - -: - 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 -============================================ - -: - 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 -============================================ - -: - 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. - -: - o udev selinux fix - -: - 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 -============================================ - -: - 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 -============================================ - -: - 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 - -: - 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 -============================================ - -: - 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" ;) - -: - 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 -============================================ - -: - o selinux patch - -: - 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 -============================================ - -: - o Various typos and other litte errors in udev.8.in - -: - o DEVNAME on device removal - -: - 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 - 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 - 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 -============================================ - -: - 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 -============================================ - -: - 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 -============================================ - -: - 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 -============================================ - -: - 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 - -: - 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 -============================================ - -: - 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 -============================================ - -: - o udev - read long lines from config files overflow fix - -: - o Update the FAQ with info about hardlink security - -: - 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 -============================================ - -: - 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 -============================================ - -: - 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 -============================================ - -: - o devfs.sh-ide-floppy - -: - 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 - o add scripts to run gcov for udev from Leann Ogasawara - 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 - o added execelent "writing udev rules" document from Daniel Drake - 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 -============================================ - -: - o Add README for chassis_id - o Add chassis_id program to extras directory - -: - o udevd race conditions and performance, assorted cleanups - -: - o fix SEGV in libsysfs/dlist.c - -: - o add OSDL documentation for persistent naming - -: - 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 - 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 -============================================ - -: - o more Libsysfs updates - o Libsysfs updates - -: - 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 - -: - 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 - -: - 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 -============================================ - -: - 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 - -: - o no error on enoent - o escape dashes in man pages - o remove usage of expr in ide-devfs.sh - -: - 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 - 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 -============================================ - -: - o [PATCH] symlink dm-[0-9]* rule - o update extras/multipath - -: - 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 -============================================ - -: - o make logging a config option - -: - 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 -============================================ - -: - o get_dev_number() in extras/ide-devfs.sh - -: - 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 -============================================ - -: - 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 -============================================ - -: - o libsysfs update for refresh + namedev.c changes - -: - o udev-013/extras/multipath update - -: - 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 -============================================ - -: - o LSB init script and other stuff - -: - o fix udev directory for Debian init script - -: - 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 -============================================ - -: - o make symlink work properly if there is already a file in its place - o Fix udev gcc-2.95.4 compat - -: - 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 - -: - o introduce signal handler - -: - 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 -============================================ - -: - o proper cleanup on udevdb_init() failure - -: - o patch udev 009-010 rpm spec file - -: - 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 -============================================ - -: - o change pgsize - -: - 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 - -: - 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 -============================================ - -: - 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 - -: - o D-BUS patch for udev-008 - -: - 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 - -: - 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 - 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 -============================================ - -: - o more config file parsing robustness - -: - 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 -============================================ - -: - 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 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 -============================================ - -: - 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 - o Add multipath "extra" program from Christophe Varoqui, - 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 -============================================ - -: - 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 index 0a34e77df2..0000000000 --- a/src/udev/INSTALL +++ /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 index 1c7f86b081..0000000000 --- a/src/udev/Makefile.am +++ /dev/null @@ -1,712 +0,0 @@ -# Copyright (C) 2008-2012 Kay Sievers -# Copyright (C) 2009 Diego Elio 'Flameeyes' Pettenò - -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 index f4f6f4e327..0000000000 --- a/src/udev/NEWS +++ /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 '. - -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= - udev.children-max= - udev.exec-delay= -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 : 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:="". - -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}/: -and the device node of the same device by looking up: - /dev/{block,char}/: - -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:@" 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=="" 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}+="" 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=="" and TEST!="" -can be specified now. The TEST key accepts an optional mode mask -TEST{0100}=="". - -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="" 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="" 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 index 38459c6b22..0000000000 --- a/src/udev/README +++ /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 index 8b8b9c8f8c..0000000000 --- a/src/udev/TODO +++ /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 index 0000000000..a6a2bfd088 --- /dev/null +++ b/src/udev/accelerometer/61-accelerometer.rules @@ -0,0 +1,3 @@ +# do not edit this file, it will be overwritten on update + +SUBSYSTEM=="input", ACTION!="remove", ENV{ID_INPUT_ACCELEROMETER}=="1", IMPORT{program}="accelerometer %p" diff --git a/src/udev/accelerometer/accelerometer.c b/src/udev/accelerometer/accelerometer.c new file mode 100644 index 0000000000..bc9715b264 --- /dev/null +++ b/src/udev/accelerometer/accelerometer.c @@ -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 + * + * orientation_calc() from the sensorfw package + * Copyright (C) 2009-2010 Nokia Corporation + * Authors: + * Üstün Ergenoglu + * Timo Rongas + * Lihan Guo + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with keymap; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libudev.h" +#include "libudev-private.h" + +/* we must use this kernel-compatible implementation */ +#define BITS_PER_LONG (sizeof(unsigned long) * 8) +#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) +#define OFF(x) ((x)%BITS_PER_LONG) +#define BIT(x) (1UL<> OFF(bit)) & 1) + +static int debug = 0; + +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] \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 index 0000000000..846a73b547 --- /dev/null +++ b/src/udev/ata_id/ata_id.c @@ -0,0 +1,721 @@ +/* + * ata_id - reads product/serial number from ATA drives + * + * Copyright (C) 2005-2008 Kay Sievers + * Copyright (C) 2009 Lennart Poettering + * Copyright (C) 2009-2010 David Zeuthen + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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] \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 index 55ee03afd1..0000000000 --- a/src/udev/autogen.sh +++ /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 index 0000000000..6eaf76a72c --- /dev/null +++ b/src/udev/cdrom_id/60-cdrom_id.rules @@ -0,0 +1,20 @@ +# do not edit this file, it will be overwritten on update + +ACTION=="remove", GOTO="cdrom_end" +SUBSYSTEM!="block", GOTO="cdrom_end" +KERNEL!="sr[0-9]*|xvd*", GOTO="cdrom_end" +ENV{DEVTYPE}!="disk", GOTO="cdrom_end" + +# unconditionally tag device as CDROM +KERNEL=="sr[0-9]*", ENV{ID_CDROM}="1" + +# media eject button pressed +ENV{DISK_EJECT_REQUEST}=="?*", RUN+="cdrom_id --eject-media $devnode", GOTO="cdrom_end" + +# import device and media properties and lock tray to +# enable the receiving of media eject button events +IMPORT{program}="cdrom_id --lock-media $devnode" + +KERNEL=="sr0", SYMLINK+="cdrom", OPTIONS+="link_priority=-100" + +LABEL="cdrom_end" diff --git a/src/udev/cdrom_id/cdrom_id.c b/src/udev/cdrom_id/cdrom_id.c new file mode 100644 index 0000000000..f90d52ec9c --- /dev/null +++ b/src/udev/cdrom_id/cdrom_id.c @@ -0,0 +1,1099 @@ +/* + * cdrom_id - optical drive and media information prober + * + * Copyright (C) 2008-2010 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libudev.h" +#include "libudev-private.h" + +static bool debug; + +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 \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 \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 , 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] \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 index 0000000000..076fe479e2 --- /dev/null +++ b/src/udev/collect/collect.c @@ -0,0 +1,473 @@ +/* + * Collect variables across events. + * + * usage: collect [--add|--remove] + * + * Adds ID to the list governed by . + * must be part of the ID list . + * If all IDs given by are listed (ie collect has been + * invoked for each ID in ) collect returns 0, the + * number of missing IDs otherwise. + * A negative number is returned on error. + * + * Copyright(C) 2007, Hannes Reinecke + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libudev.h" +#include "libudev-private.h" + +#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] \n" + "\n" + " Adds ID to the list governed by .\n" + " must be part of the list .\n" + " If all IDs given by are listed (ie collect has been\n" + " invoked for each ID in ) collect returns 0, the\n" + " number of missing IDs otherwise.\n" + " On error a negative number is returned.\n" + "\n"); +} + +/* + * prepare + * + * Prepares the database file + */ +static int prepare(char *dir, char *filename) +{ + struct stat statbuf; + char buf[512]; + int fd; + + if (stat(dir, &statbuf) < 0) + mkdir(dir, 0700); + + 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 index b31b62f289..0000000000 --- a/src/udev/configure.ac +++ /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 ' | 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 index 0000000000..1fb9c51424 --- /dev/null +++ b/src/udev/docs/.gitignore @@ -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 index 0000000000..7cd4f9742c --- /dev/null +++ b/src/udev/docs/Makefile.am @@ -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 index 0000000000..b7feb45529 --- /dev/null +++ b/src/udev/docs/libudev-docs.xml @@ -0,0 +1,32 @@ + + +]> + + + libudev Reference Manual + for libudev version &version; + + 2009-2011 + Kay Sievers <kay.sievers@vrfy.org> + + + + + libudev + + + + + + + + + + + API Index + + + diff --git a/src/udev/docs/libudev-sections.txt b/src/udev/docs/libudev-sections.txt new file mode 100644 index 0000000000..15c3e934b5 --- /dev/null +++ b/src/udev/docs/libudev-sections.txt @@ -0,0 +1,127 @@ +
+libudev +udev +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 +
+ +
+libudev-list +udev_list +udev_list_entry +udev_list_entry_get_next +udev_list_entry_get_by_name +udev_list_entry_get_name +udev_list_entry_get_value +udev_list_entry_foreach +
+ +
+libudev-device +udev_device +udev_device +udev_device_ref +udev_device_unref +udev_device_get_udev +udev_device_new_from_syspath +udev_device_new_from_devnum +udev_device_new_from_subsystem_sysname +udev_device_new_from_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 +
+ +
+libudev-monitor +udev_monitor +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 +
+ +
+libudev-enumerate +udev_enumerate +udev_enumerate +udev_enumerate_ref +udev_enumerate_unref +udev_enumerate_get_udev +udev_enumerate_new +udev_enumerate_add_match_subsystem +udev_enumerate_add_nomatch_subsystem +udev_enumerate_add_match_sysattr +udev_enumerate_add_nomatch_sysattr +udev_enumerate_add_match_property +udev_enumerate_add_match_tag +udev_enumerate_add_match_parent +udev_enumerate_add_match_is_initialized +udev_enumerate_add_match_sysname +udev_enumerate_add_syspath +udev_enumerate_scan_devices +udev_enumerate_scan_subsystems +udev_enumerate_get_list_entry +
+ +
+libudev-queue +udev_queue +udev_queue +udev_queue_ref +udev_queue_unref +udev_queue_get_udev +udev_queue_new +udev_queue_get_udev_is_active +udev_queue_get_queue_is_empty +udev_queue_get_seqnum_is_finished +udev_queue_get_seqnum_sequence_is_finished +udev_queue_get_queued_list_entry +udev_queue_get_kernel_seqnum +udev_queue_get_udev_seqnum +
+ +
+libudev-util +udev_util +udev_util_encode_string +
diff --git a/src/udev/docs/libudev.types b/src/udev/docs/libudev.types new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/udev/docs/version.xml.in b/src/udev/docs/version.xml.in new file mode 100644 index 0000000000..d78bda9342 --- /dev/null +++ b/src/udev/docs/version.xml.in @@ -0,0 +1 @@ +@VERSION@ diff --git a/src/udev/gudev/.gitignore b/src/udev/gudev/.gitignore new file mode 100644 index 0000000000..d20fa523e4 --- /dev/null +++ b/src/udev/gudev/.gitignore @@ -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 index 0000000000..5d7d73d9a6 --- /dev/null +++ b/src/udev/gudev/docs/.gitignore @@ -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 index 0000000000..036ef43026 --- /dev/null +++ b/src/udev/gudev/docs/Makefile.am @@ -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 index 0000000000..f876c3bc05 --- /dev/null +++ b/src/udev/gudev/docs/gudev-docs.xml @@ -0,0 +1,93 @@ + + +]> + + + GUDev Reference Manual + For GUdev version &version; + + + David + Zeuthen + +
+ davidz@redhat.com +
+
+
+ + Bastien + Nocera + +
+ hadess@hadess.net +
+
+
+
+ + + 2011 + The GUDev Authors + + + + + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU Free + Documentation License, 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 GNU Free + Documentation License from the Free Software + Foundation by visiting their Web site or by writing + to: + +
+ The Free Software Foundation, Inc., + 59 Temple Place - Suite 330, + Boston, MA 02111-1307, + USA +
+
+ + + 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. + +
+
+ + + API Reference + + + This part presents the class and function reference for the + libgudev library. + + + + + + + + + Object Hierarchy + + + + Index + + + Index of new symbols in 165 + + + +
diff --git a/src/udev/gudev/docs/gudev-sections.txt b/src/udev/gudev/docs/gudev-sections.txt new file mode 100644 index 0000000000..213e1a7465 --- /dev/null +++ b/src/udev/gudev/docs/gudev-sections.txt @@ -0,0 +1,113 @@ +
+gudevclient +GUdevClient +GUdevClient +GUdevClientClass +GUdevDeviceType +GUdevDeviceNumber +g_udev_client_new +g_udev_client_query_by_subsystem +g_udev_client_query_by_device_number +g_udev_client_query_by_device_file +g_udev_client_query_by_sysfs_path +g_udev_client_query_by_subsystem_and_name + +G_UDEV_CLIENT +G_UDEV_IS_CLIENT +G_UDEV_TYPE_CLIENT +g_udev_client_get_type +G_UDEV_CLIENT_CLASS +G_UDEV_IS_CLIENT_CLASS +G_UDEV_CLIENT_GET_CLASS + +GUdevClientPrivate +
+ +
+gudevdevice +GUdevDevice +GUdevDevice +GUdevDeviceClass +g_udev_device_get_subsystem +g_udev_device_get_devtype +g_udev_device_get_name +g_udev_device_get_number +g_udev_device_get_sysfs_path +g_udev_device_get_driver +g_udev_device_get_action +g_udev_device_get_seqnum +g_udev_device_get_device_type +g_udev_device_get_device_number +g_udev_device_get_device_file +g_udev_device_get_device_file_symlinks +g_udev_device_get_parent +g_udev_device_get_parent_with_subsystem +g_udev_device_get_tags +g_udev_device_get_is_initialized +g_udev_device_get_usec_since_initialized +g_udev_device_get_property_keys +g_udev_device_has_property +g_udev_device_get_property +g_udev_device_get_property_as_int +g_udev_device_get_property_as_uint64 +g_udev_device_get_property_as_double +g_udev_device_get_property_as_boolean +g_udev_device_get_property_as_strv +g_udev_device_get_sysfs_attr +g_udev_device_get_sysfs_attr_as_int +g_udev_device_get_sysfs_attr_as_uint64 +g_udev_device_get_sysfs_attr_as_double +g_udev_device_get_sysfs_attr_as_boolean +g_udev_device_get_sysfs_attr_as_strv + +G_UDEV_DEVICE +G_UDEV_IS_DEVICE +G_UDEV_TYPE_DEVICE +g_udev_device_get_type +G_UDEV_DEVICE_CLASS +G_UDEV_IS_DEVICE_CLASS +G_UDEV_DEVICE_GET_CLASS + +GUdevDevicePrivate +
+ +
+gudevenumerator +GUdevEnumerator +GUdevEnumerator +GUdevEnumeratorClass +g_udev_enumerator_new +g_udev_enumerator_add_match_subsystem +g_udev_enumerator_add_nomatch_subsystem +g_udev_enumerator_add_match_sysfs_attr +g_udev_enumerator_add_nomatch_sysfs_attr +g_udev_enumerator_add_match_property +g_udev_enumerator_add_match_name +g_udev_enumerator_add_match_tag +g_udev_enumerator_add_match_is_initialized +g_udev_enumerator_add_sysfs_path +g_udev_enumerator_execute + +G_UDEV_ENUMERATOR +G_UDEV_IS_ENUMERATOR +G_UDEV_TYPE_ENUMERATOR +g_udev_enumerator_get_type +G_UDEV_ENUMERATOR_CLASS +G_UDEV_IS_ENUMERATOR_CLASS +G_UDEV_ENUMERATOR_GET_CLASS + +GUdevEnumeratorPrivate +
+ +
+gudevmarshal + +g_udev_marshal_VOID__STRING_OBJECT +
+ +
+gudevenumtypes + +G_TYPE_UDEV_DEVICE_TYPE +g_udev_device_type_get_type +
diff --git a/src/udev/gudev/docs/gudev.types b/src/udev/gudev/docs/gudev.types new file mode 100644 index 0000000000..a89857a04d --- /dev/null +++ b/src/udev/gudev/docs/gudev.types @@ -0,0 +1,4 @@ +g_udev_device_type_get_type +g_udev_device_get_type +g_udev_client_get_type +g_udev_enumerator_get_type diff --git a/src/udev/gudev/docs/version.xml.in b/src/udev/gudev/docs/version.xml.in new file mode 100644 index 0000000000..d78bda9342 --- /dev/null +++ b/src/udev/gudev/docs/version.xml.in @@ -0,0 +1 @@ +@VERSION@ diff --git a/src/udev/gudev/gjs-example.js b/src/udev/gudev/gjs-example.js new file mode 100755 index 0000000000..5586fd6a61 --- /dev/null +++ b/src/udev/gudev/gjs-example.js @@ -0,0 +1,75 @@ +#!/usr/bin/env gjs-console + +// This currently depends on the following patches to gjs +// +// http://bugzilla.gnome.org/show_bug.cgi?id=584558 +// http://bugzilla.gnome.org/show_bug.cgi?id=584560 +// http://bugzilla.gnome.org/show_bug.cgi?id=584568 + +const GUdev = imports.gi.GUdev; +const Mainloop = imports.mainloop; + +function print_device (device) { + print (" subsystem: " + device.get_subsystem ()); + print (" devtype: " + device.get_devtype ()); + print (" name: " + device.get_name ()); + print (" number: " + device.get_number ()); + print (" sysfs_path: " + device.get_sysfs_path ()); + print (" driver: " + device.get_driver ()); + print (" action: " + device.get_action ()); + print (" seqnum: " + device.get_seqnum ()); + print (" device type: " + device.get_device_type ()); + print (" device number: " + device.get_device_number ()); + print (" device file: " + device.get_device_file ()); + print (" device file symlinks: " + device.get_device_file_symlinks ()); + print (" foo: " + device.get_sysfs_attr_as_strv ("stat")); + var keys = device.get_property_keys (); + for (var n = 0; n < keys.length; n++) { + print (" " + keys[n] + "=" + device.get_property (keys[n])); + } +} + +function on_uevent (client, action, device) { + print ("action " + action + " on device " + device.get_sysfs_path()); + print_device (device); + print (""); +} + +var client = new GUdev.Client ({subsystems: ["block", "usb/usb_interface"]}); +client.connect ("uevent", on_uevent); + +var block_devices = client.query_by_subsystem ("block"); +for (var n = 0; n < block_devices.length; n++) { + print ("block device: " + block_devices[n].get_device_file ()); +} + +var d; + +d = client.query_by_device_number (GUdev.DeviceType.BLOCK, 0x0810); +if (d == null) { + print ("query_by_device_number 0x810 -> null"); +} else { + print ("query_by_device_number 0x810 -> " + d.get_device_file ()); + var dd = d.get_parent_with_subsystem ("usb", null); + print_device (dd); + print ("--------------------------------------------------------------------------"); + while (d != null) { + print_device (d); + print (""); + d = d.get_parent (); + } +} + +d = client.query_by_sysfs_path ("/sys/block/sda/sda1"); +print ("query_by_sysfs_path (\"/sys/block/sda1\") -> " + d.get_device_file ()); + +d = client.query_by_subsystem_and_name ("block", "sda2"); +print ("query_by_subsystem_and_name (\"block\", \"sda2\") -> " + d.get_device_file ()); + +d = client.query_by_device_file ("/dev/sda"); +print ("query_by_device_file (\"/dev/sda\") -> " + d.get_device_file ()); + +d = client.query_by_device_file ("/dev/block/8:0"); +print ("query_by_device_file (\"/dev/block/8:0\") -> " + d.get_device_file ()); + +Mainloop.run('udev-example'); diff --git a/src/udev/gudev/gudev-1.0.pc.in b/src/udev/gudev/gudev-1.0.pc.in new file mode 100644 index 0000000000..058262d767 --- /dev/null +++ b/src/udev/gudev/gudev-1.0.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: gudev-1.0 +Description: GObject bindings for libudev +Version: @VERSION@ +Requires: glib-2.0, gobject-2.0 +Libs: -L${libdir} -lgudev-1.0 +Cflags: -I${includedir}/gudev-1.0 diff --git a/src/udev/gudev/gudev.h b/src/udev/gudev/gudev.h new file mode 100644 index 0000000000..a313460817 --- /dev/null +++ b/src/udev/gudev/gudev.h @@ -0,0 +1,33 @@ +/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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 +#include +#include +#include +#include +#include +#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 index 0000000000..2b94102ac5 --- /dev/null +++ b/src/udev/gudev/gudevclient.c @@ -0,0 +1,527 @@ +/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2008-2010 David Zeuthen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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 +#include + +#include "gudevclient.h" +#include "gudevdevice.h" +#include "gudevmarshal.h" +#include "gudevprivate.h" + +/** + * SECTION:gudevclient + * @short_description: Query devices and listen to uevents + * + * #GUdevClient is used to query information about devices on a Linux + * system from the Linux kernel and the udev device + * manager. + * + * Device information is retrieved from the kernel (through the + * sysfs filesystem) and the udev daemon (through a + * tmpfs filesystem) and presented through + * #GUdevDevice objects. This means that no blocking IO ever happens + * (in both cases, we are essentially just reading data from kernel + * memory) and as such there are no asynchronous versions of the + * provided methods. + * + * To get #GUdevDevice objects, use + * g_udev_client_query_by_subsystem(), + * g_udev_client_query_by_device_number(), + * g_udev_client_query_by_device_file(), + * g_udev_client_query_by_sysfs_path(), + * g_udev_client_query_by_subsystem_and_name() + * or the #GUdevEnumerator type. + * + * To listen to uevents, connect to the #GUdevClient::uevent signal. + */ + +struct _GUdevClientPrivate +{ + GSource *watch_source; + struct udev *udev; + struct udev_monitor *monitor; + + gchar **subsystems; +}; + +enum +{ + PROP_0, + PROP_SUBSYSTEMS, +}; + +enum +{ + UEVENT_SIGNAL, + LAST_SIGNAL, +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE (GUdevClient, g_udev_client, G_TYPE_OBJECT) + +/* ---------------------------------------------------------------------------------------------------- */ + +static gboolean +monitor_event (GIOChannel *source, + GIOCondition condition, + gpointer data) +{ + GUdevClient *client = (GUdevClient *) data; + GUdevDevice *device; + struct udev_device *udevice; + + if (client->priv->monitor == NULL) + goto out; + udevice = udev_monitor_receive_device (client->priv->monitor); + if (udevice == NULL) + goto out; + + device = _g_udev_device_new (udevice); + udev_device_unref (udevice); + g_signal_emit (client, + signals[UEVENT_SIGNAL], + 0, + g_udev_device_get_action (device), + device); + g_object_unref (device); + + out: + return TRUE; +} + +static void +g_udev_client_finalize (GObject *object) +{ + GUdevClient *client = G_UDEV_CLIENT (object); + + if (client->priv->watch_source != NULL) + { + g_source_destroy (client->priv->watch_source); + client->priv->watch_source = NULL; + } + + if (client->priv->monitor != NULL) + { + udev_monitor_unref (client->priv->monitor); + client->priv->monitor = NULL; + } + + if (client->priv->udev != NULL) + { + udev_unref (client->priv->udev); + client->priv->udev = NULL; + } + + g_strfreev (client->priv->subsystems); + + if (G_OBJECT_CLASS (g_udev_client_parent_class)->finalize != NULL) + G_OBJECT_CLASS (g_udev_client_parent_class)->finalize (object); +} + +static void +g_udev_client_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GUdevClient *client = G_UDEV_CLIENT (object); + + switch (prop_id) + { + case PROP_SUBSYSTEMS: + if (client->priv->subsystems != NULL) + g_strfreev (client->priv->subsystems); + client->priv->subsystems = g_strdupv (g_value_get_boxed (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +g_udev_client_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GUdevClient *client = G_UDEV_CLIENT (object); + + switch (prop_id) + { + case PROP_SUBSYSTEMS: + g_value_set_boxed (value, client->priv->subsystems); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +g_udev_client_constructed (GObject *object) +{ + GUdevClient *client = G_UDEV_CLIENT (object); + GIOChannel *channel; + guint n; + + client->priv->udev = udev_new (); + + /* connect to event source */ + client->priv->monitor = udev_monitor_new_from_netlink (client->priv->udev, "udev"); + + //g_debug ("ss = %p", client->priv->subsystems); + + if (client->priv->subsystems != NULL) + { + /* install subsystem filters to only wake up for certain events */ + for (n = 0; client->priv->subsystems[n] != NULL; n++) + { + gchar *subsystem; + gchar *devtype; + gchar *s; + + subsystem = g_strdup (client->priv->subsystems[n]); + devtype = NULL; + + //g_debug ("s = '%s'", subsystem); + + s = strstr (subsystem, "/"); + if (s != NULL) + { + devtype = s + 1; + *s = '\0'; + } + + if (client->priv->monitor != NULL) + udev_monitor_filter_add_match_subsystem_devtype (client->priv->monitor, subsystem, devtype); + + g_free (subsystem); + } + + /* listen to events, and buffer them */ + if (client->priv->monitor != NULL) + { + udev_monitor_enable_receiving (client->priv->monitor); + channel = g_io_channel_unix_new (udev_monitor_get_fd (client->priv->monitor)); + client->priv->watch_source = g_io_create_watch (channel, G_IO_IN); + g_io_channel_unref (channel); + g_source_set_callback (client->priv->watch_source, (GSourceFunc) monitor_event, client, NULL); + g_source_attach (client->priv->watch_source, g_main_context_get_thread_default ()); + g_source_unref (client->priv->watch_source); + } + else + { + client->priv->watch_source = NULL; + } + } + + if (G_OBJECT_CLASS (g_udev_client_parent_class)->constructed != NULL) + G_OBJECT_CLASS (g_udev_client_parent_class)->constructed (object); +} + + +static void +g_udev_client_class_init (GUdevClientClass *klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + + gobject_class->constructed = g_udev_client_constructed; + gobject_class->set_property = g_udev_client_set_property; + gobject_class->get_property = g_udev_client_get_property; + gobject_class->finalize = g_udev_client_finalize; + + /** + * GUdevClient:subsystems: + * + * The subsystems to listen for uevents on. + * + * To listen for only a specific DEVTYPE for a given SUBSYSTEM, use + * "subsystem/devtype". For example, to only listen for uevents + * where SUBSYSTEM is usb and DEVTYPE is usb_interface, use + * "usb/usb_interface". + * + * If this property is %NULL, then no events will be reported. If + * it's the empty array, events from all subsystems will be + * reported. + */ + g_object_class_install_property (gobject_class, + PROP_SUBSYSTEMS, + g_param_spec_boxed ("subsystems", + "The subsystems to listen for changes on", + "The subsystems to listen for changes on", + G_TYPE_STRV, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE)); + + /** + * GUdevClient::uevent: + * @client: The #GUdevClient receiving the event. + * @action: The action for the uevent e.g. "add", "remove", "change", "move", etc. + * @device: Details about the #GUdevDevice the event is for. + * + * Emitted when @client receives an uevent. + * + * This signal is emitted in the + * thread-default main loop + * of the thread that @client was created in. + */ + signals[UEVENT_SIGNAL] = g_signal_new ("uevent", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GUdevClientClass, uevent), + NULL, + NULL, + g_udev_marshal_VOID__STRING_OBJECT, + G_TYPE_NONE, + 2, + G_TYPE_STRING, + G_UDEV_TYPE_DEVICE); + + g_type_class_add_private (klass, sizeof (GUdevClientPrivate)); +} + +static void +g_udev_client_init (GUdevClient *client) +{ + client->priv = G_TYPE_INSTANCE_GET_PRIVATE (client, + G_UDEV_TYPE_CLIENT, + GUdevClientPrivate); +} + +/** + * g_udev_client_new: + * @subsystems: (array zero-terminated=1) (element-type utf8) (transfer none) (allow-none): A %NULL terminated string array of subsystems to listen for uevents on, %NULL to not listen on uevents at all, or an empty array to listen to uevents on all subsystems. See the documentation for the #GUdevClient:subsystems property for details on this parameter. + * + * Constructs a #GUdevClient object that can be used to query + * information about devices. Connect to the #GUdevClient::uevent + * signal to listen for uevents. Note that signals are emitted in the + * thread-default main loop + * of the thread that you call this constructor from. + * + * Returns: A new #GUdevClient object. Free with g_object_unref(). + */ +GUdevClient * +g_udev_client_new (const gchar * const *subsystems) +{ + return G_UDEV_CLIENT (g_object_new (G_UDEV_TYPE_CLIENT, "subsystems", subsystems, NULL)); +} + +/** + * g_udev_client_query_by_subsystem: + * @client: A #GUdevClient. + * @subsystem: (allow-none): The subsystem to get devices for or %NULL to get all devices. + * + * Gets all devices belonging to @subsystem. + * + * Returns: (element-type GUdevDevice) (transfer full): A list of #GUdevDevice objects. The caller should free the result by using g_object_unref() on each element in the list and then g_list_free() on the list. + */ +GList * +g_udev_client_query_by_subsystem (GUdevClient *client, + const gchar *subsystem) +{ + struct udev_enumerate *enumerate; + struct udev_list_entry *l, *devices; + GList *ret; + + g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); + + ret = NULL; + + /* prepare a device scan */ + enumerate = udev_enumerate_new (client->priv->udev); + + /* filter for subsystem */ + if (subsystem != NULL) + udev_enumerate_add_match_subsystem (enumerate, subsystem); + /* retrieve the list */ + udev_enumerate_scan_devices (enumerate); + + /* add devices to the list */ + devices = udev_enumerate_get_list_entry (enumerate); + for (l = devices; l != NULL; l = udev_list_entry_get_next (l)) + { + struct udev_device *udevice; + GUdevDevice *device; + + udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate), + udev_list_entry_get_name (l)); + if (udevice == NULL) + continue; + device = _g_udev_device_new (udevice); + udev_device_unref (udevice); + ret = g_list_prepend (ret, device); + } + udev_enumerate_unref (enumerate); + + ret = g_list_reverse (ret); + + return ret; +} + +/** + * g_udev_client_query_by_device_number: + * @client: A #GUdevClient. + * @type: A value from the #GUdevDeviceType enumeration. + * @number: A device number. + * + * Looks up a device for a type and device number. + * + * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref(). + */ +GUdevDevice * +g_udev_client_query_by_device_number (GUdevClient *client, + GUdevDeviceType type, + GUdevDeviceNumber number) +{ + struct udev_device *udevice; + GUdevDevice *device; + + g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); + + device = NULL; + udevice = udev_device_new_from_devnum (client->priv->udev, type, number); + + if (udevice == NULL) + goto out; + + device = _g_udev_device_new (udevice); + udev_device_unref (udevice); + + out: + return device; +} + +/** + * g_udev_client_query_by_device_file: + * @client: A #GUdevClient. + * @device_file: A device file. + * + * Looks up a device for a device file. + * + * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref(). + */ +GUdevDevice * +g_udev_client_query_by_device_file (GUdevClient *client, + const gchar *device_file) +{ + struct stat stat_buf; + GUdevDevice *device; + + g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); + g_return_val_if_fail (device_file != NULL, NULL); + + device = NULL; + + if (stat (device_file, &stat_buf) != 0) + goto out; + + if (stat_buf.st_rdev == 0) + goto out; + + if (S_ISBLK (stat_buf.st_mode)) + device = g_udev_client_query_by_device_number (client, G_UDEV_DEVICE_TYPE_BLOCK, stat_buf.st_rdev); + else if (S_ISCHR (stat_buf.st_mode)) + device = g_udev_client_query_by_device_number (client, G_UDEV_DEVICE_TYPE_CHAR, stat_buf.st_rdev); + + out: + return device; +} + +/** + * g_udev_client_query_by_sysfs_path: + * @client: A #GUdevClient. + * @sysfs_path: A sysfs path. + * + * Looks up a device for a sysfs path. + * + * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref(). + */ +GUdevDevice * +g_udev_client_query_by_sysfs_path (GUdevClient *client, + const gchar *sysfs_path) +{ + struct udev_device *udevice; + GUdevDevice *device; + + g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); + g_return_val_if_fail (sysfs_path != NULL, NULL); + + device = NULL; + udevice = udev_device_new_from_syspath (client->priv->udev, sysfs_path); + if (udevice == NULL) + goto out; + + device = _g_udev_device_new (udevice); + udev_device_unref (udevice); + + out: + return device; +} + +/** + * g_udev_client_query_by_subsystem_and_name: + * @client: A #GUdevClient. + * @subsystem: A subsystem name. + * @name: The name of the device. + * + * Looks up a device for a subsystem and name. + * + * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref(). + */ +GUdevDevice * +g_udev_client_query_by_subsystem_and_name (GUdevClient *client, + const gchar *subsystem, + const gchar *name) +{ + struct udev_device *udevice; + GUdevDevice *device; + + g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); + g_return_val_if_fail (subsystem != NULL, NULL); + g_return_val_if_fail (name != NULL, NULL); + + device = NULL; + udevice = udev_device_new_from_subsystem_sysname (client->priv->udev, subsystem, name); + if (udevice == NULL) + goto out; + + device = _g_udev_device_new (udevice); + udev_device_unref (udevice); + + out: + return device; +} + +struct udev * +_g_udev_client_get_udev (GUdevClient *client) +{ + g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); + return client->priv->udev; +} diff --git a/src/udev/gudev/gudevclient.h b/src/udev/gudev/gudevclient.h new file mode 100644 index 0000000000..b425d03d48 --- /dev/null +++ b/src/udev/gudev/gudevclient.h @@ -0,0 +1,100 @@ +/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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 can be included directly, this file may disappear or change contents." +#endif + +#ifndef __G_UDEV_CLIENT_H__ +#define __G_UDEV_CLIENT_H__ + +#include + +G_BEGIN_DECLS + +#define G_UDEV_TYPE_CLIENT (g_udev_client_get_type ()) +#define G_UDEV_CLIENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_UDEV_TYPE_CLIENT, GUdevClient)) +#define G_UDEV_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_UDEV_TYPE_CLIENT, GUdevClientClass)) +#define G_UDEV_IS_CLIENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_UDEV_TYPE_CLIENT)) +#define G_UDEV_IS_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_UDEV_TYPE_CLIENT)) +#define G_UDEV_CLIENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_UDEV_TYPE_CLIENT, GUdevClientClass)) + +typedef struct _GUdevClientClass GUdevClientClass; +typedef struct _GUdevClientPrivate GUdevClientPrivate; + +/** + * GUdevClient: + * + * The #GUdevClient struct is opaque and should not be accessed directly. + */ +struct _GUdevClient +{ + GObject parent; + + /*< private >*/ + GUdevClientPrivate *priv; +}; + +/** + * GUdevClientClass: + * @parent_class: Parent class. + * @uevent: Signal class handler for the #GUdevClient::uevent signal. + * + * Class structure for #GUdevClient. + */ +struct _GUdevClientClass +{ + GObjectClass parent_class; + + /* signals */ + void (*uevent) (GUdevClient *client, + const gchar *action, + GUdevDevice *device); + + /*< private >*/ + /* Padding for future expansion */ + void (*reserved1) (void); + void (*reserved2) (void); + void (*reserved3) (void); + void (*reserved4) (void); + void (*reserved5) (void); + void (*reserved6) (void); + void (*reserved7) (void); + void (*reserved8) (void); +}; + +GType g_udev_client_get_type (void) G_GNUC_CONST; +GUdevClient *g_udev_client_new (const gchar* const *subsystems); +GList *g_udev_client_query_by_subsystem (GUdevClient *client, + const gchar *subsystem); +GUdevDevice *g_udev_client_query_by_device_number (GUdevClient *client, + GUdevDeviceType type, + GUdevDeviceNumber number); +GUdevDevice *g_udev_client_query_by_device_file (GUdevClient *client, + const gchar *device_file); +GUdevDevice *g_udev_client_query_by_sysfs_path (GUdevClient *client, + const gchar *sysfs_path); +GUdevDevice *g_udev_client_query_by_subsystem_and_name (GUdevClient *client, + const gchar *subsystem, + const gchar *name); + +G_END_DECLS + +#endif /* __G_UDEV_CLIENT_H__ */ diff --git a/src/udev/gudev/gudevdevice.c b/src/udev/gudev/gudevdevice.c new file mode 100644 index 0000000000..62a26f99b7 --- /dev/null +++ b/src/udev/gudev/gudevdevice.c @@ -0,0 +1,963 @@ +/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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 +#include + +#include "gudevdevice.h" +#include "gudevprivate.h" + +/** + * SECTION:gudevdevice + * @short_description: Get information about a device + * + * The #GUdevDevice class is used to get information about a specific + * device. Note that you cannot instantiate a #GUdevDevice object + * yourself. Instead you must use #GUdevClient to obtain #GUdevDevice + * objects. + * + * To get basic information about a device, use + * g_udev_device_get_subsystem(), g_udev_device_get_devtype(), + * g_udev_device_get_name(), g_udev_device_get_number(), + * g_udev_device_get_sysfs_path(), g_udev_device_get_driver(), + * g_udev_device_get_action(), g_udev_device_get_seqnum(), + * g_udev_device_get_device_type(), g_udev_device_get_device_number(), + * g_udev_device_get_device_file(), + * g_udev_device_get_device_file_symlinks(). + * + * To navigate the device tree, use g_udev_device_get_parent() and + * g_udev_device_get_parent_with_subsystem(). + * + * To access udev properties for the device, use + * g_udev_device_get_property_keys(), + * g_udev_device_has_property(), + * g_udev_device_get_property(), + * g_udev_device_get_property_as_int(), + * g_udev_device_get_property_as_uint64(), + * g_udev_device_get_property_as_double(), + * g_udev_device_get_property_as_boolean() and + * g_udev_device_get_property_as_strv(). + * + * To access sysfs attributes for the device, use + * g_udev_device_get_sysfs_attr(), + * 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 /dev) that points to + * the device file for @device. + * + * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): A %NULL terminated string array of symlinks. This array is owned by @device and should not be freed by the caller. + */ +const gchar * const * +g_udev_device_get_device_file_symlinks (GUdevDevice *device) +{ + struct udev_list_entry *l; + GPtrArray *p; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); + + if (device->priv->device_file_symlinks != NULL) + goto out; + + p = g_ptr_array_new (); + for (l = udev_device_get_devlinks_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l)) + { + g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l))); + } + g_ptr_array_add (p, NULL); + device->priv->device_file_symlinks = (gchar **) g_ptr_array_free (p, FALSE); + + out: + return (const gchar * const *) device->priv->device_file_symlinks; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +/** + * g_udev_device_get_parent: + * @device: A #GUdevDevice. + * + * Gets the immediate parent of @device, if any. + * + * Returns: (transfer full): A #GUdevDevice or %NULL if @device has no parent. Free with g_object_unref(). + */ +GUdevDevice * +g_udev_device_get_parent (GUdevDevice *device) +{ + GUdevDevice *ret; + struct udev_device *udevice; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); + + ret = NULL; + + udevice = udev_device_get_parent (device->priv->udevice); + if (udevice == NULL) + goto out; + + ret = _g_udev_device_new (udevice); + + out: + return ret; +} + +/** + * g_udev_device_get_parent_with_subsystem: + * @device: A #GUdevDevice. + * @subsystem: The subsystem of the parent to get. + * @devtype: (allow-none): The devtype of the parent to get or %NULL. + * + * Walks up the chain of parents of @device and returns the first + * device encountered where @subsystem and @devtype matches, if any. + * + * Returns: (transfer full): A #GUdevDevice or %NULL if @device has no parent with @subsystem and @devtype. Free with g_object_unref(). + */ +GUdevDevice * +g_udev_device_get_parent_with_subsystem (GUdevDevice *device, + const gchar *subsystem, + const gchar *devtype) +{ + GUdevDevice *ret; + struct udev_device *udevice; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); + g_return_val_if_fail (subsystem != NULL, NULL); + + ret = NULL; + + udevice = udev_device_get_parent_with_subsystem_devtype (device->priv->udevice, + subsystem, + devtype); + if (udevice == NULL) + goto out; + + ret = _g_udev_device_new (udevice); + + out: + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +/** + * g_udev_device_get_property_keys: + * @device: A #GUdevDevice. + * + * Gets all keys for properties on @device. + * + * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): A %NULL terminated string array of property keys. This array is owned by @device and should not be freed by the caller. + */ +const gchar* const * +g_udev_device_get_property_keys (GUdevDevice *device) +{ + struct udev_list_entry *l; + GPtrArray *p; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); + + if (device->priv->property_keys != NULL) + goto out; + + p = g_ptr_array_new (); + for (l = udev_device_get_properties_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l)) + { + g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l))); + } + g_ptr_array_add (p, NULL); + device->priv->property_keys = (gchar **) g_ptr_array_free (p, FALSE); + + out: + return (const gchar * const *) device->priv->property_keys; +} + + +/** + * g_udev_device_has_property: + * @device: A #GUdevDevice. + * @key: Name of property. + * + * Check if a the property with the given key exists. + * + * Returns: %TRUE only if the value for @key exist. + */ +gboolean +g_udev_device_has_property (GUdevDevice *device, + const gchar *key) +{ + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE); + g_return_val_if_fail (key != NULL, FALSE); + return udev_device_get_property_value (device->priv->udevice, key) != NULL; +} + +/** + * g_udev_device_get_property: + * @device: A #GUdevDevice. + * @key: Name of property. + * + * Look up the value for @key on @device. + * + * Returns: The value for @key or %NULL if @key doesn't exist on @device. Do not free this string, it is owned by @device. + */ +const gchar * +g_udev_device_get_property (GUdevDevice *device, + const gchar *key) +{ + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); + g_return_val_if_fail (key != NULL, NULL); + return udev_device_get_property_value (device->priv->udevice, key); +} + +/** + * g_udev_device_get_property_as_int: + * @device: A #GUdevDevice. + * @key: Name of property. + * + * Look up the value for @key on @device and convert it to an integer + * using strtol(). + * + * Returns: The value for @key or 0 if @key doesn't exist or + * isn't an integer. + */ +gint +g_udev_device_get_property_as_int (GUdevDevice *device, + const gchar *key) +{ + gint result; + const gchar *s; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0); + g_return_val_if_fail (key != NULL, 0); + + result = 0; + s = g_udev_device_get_property (device, key); + if (s == NULL) + goto out; + + result = strtol (s, NULL, 0); +out: + return result; +} + +/** + * g_udev_device_get_property_as_uint64: + * @device: A #GUdevDevice. + * @key: Name of property. + * + * Look up the value for @key on @device and convert it to an unsigned + * 64-bit integer using g_ascii_strtoull(). + * + * Returns: The value for @key or 0 if @key doesn't exist or isn't a + * #guint64. + */ +guint64 +g_udev_device_get_property_as_uint64 (GUdevDevice *device, + const gchar *key) +{ + guint64 result; + const gchar *s; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0); + g_return_val_if_fail (key != NULL, 0); + + result = 0; + s = g_udev_device_get_property (device, key); + if (s == NULL) + goto out; + + result = g_ascii_strtoull (s, NULL, 0); +out: + return result; +} + +/** + * g_udev_device_get_property_as_double: + * @device: A #GUdevDevice. + * @key: Name of property. + * + * Look up the value for @key on @device and convert it to a double + * precision floating point number using strtod(). + * + * Returns: The value for @key or 0.0 if @key doesn't exist or isn't a + * #gdouble. + */ +gdouble +g_udev_device_get_property_as_double (GUdevDevice *device, + const gchar *key) +{ + gdouble result; + const gchar *s; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0.0); + g_return_val_if_fail (key != NULL, 0.0); + + result = 0.0; + s = g_udev_device_get_property (device, key); + if (s == NULL) + goto out; + + result = strtod (s, NULL); +out: + return result; +} + +/** + * g_udev_device_get_property_as_boolean: + * @device: A #GUdevDevice. + * @key: Name of property. + * + * Look up the value for @key on @device and convert it to an + * boolean. This is done by doing a case-insensitive string comparison + * on the string value against "1" and "true". + * + * Returns: The value for @key or %FALSE if @key doesn't exist or + * isn't a #gboolean. + */ +gboolean +g_udev_device_get_property_as_boolean (GUdevDevice *device, + const gchar *key) +{ + gboolean result; + const gchar *s; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE); + g_return_val_if_fail (key != NULL, FALSE); + + result = FALSE; + s = g_udev_device_get_property (device, key); + if (s == NULL) + goto out; + + if (strcmp (s, "1") == 0 || g_ascii_strcasecmp (s, "true") == 0) + result = TRUE; + out: + return result; +} + +static gchar ** +split_at_whitespace (const gchar *s) +{ + gchar **result; + guint n; + guint m; + + result = g_strsplit_set (s, " \v\t\r\n", 0); + + /* remove empty strings, thanks GLib */ + for (n = 0; result[n] != NULL; n++) + { + if (strlen (result[n]) == 0) + { + g_free (result[n]); + for (m = n; result[m] != NULL; m++) + result[m] = result[m + 1]; + n--; + } + } + + return result; +} + +/** + * g_udev_device_get_property_as_strv: + * @device: A #GUdevDevice. + * @key: Name of property. + * + * Look up the value for @key on @device and return the result of + * splitting it into non-empty tokens split at white space (only space + * (' '), form-feed ('\f'), newline ('\n'), carriage return ('\r'), + * horizontal tab ('\t'), and vertical tab ('\v') are considered; the + * locale is not taken into account). + * + * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): The value of @key on @device split into tokens or %NULL if @key doesn't exist. This array is owned by @device and should not be freed by the caller. + */ +const gchar* const * +g_udev_device_get_property_as_strv (GUdevDevice *device, + const gchar *key) +{ + gchar **result; + const gchar *s; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); + g_return_val_if_fail (key != NULL, NULL); + + if (device->priv->prop_strvs != NULL) + { + result = g_hash_table_lookup (device->priv->prop_strvs, key); + if (result != NULL) + goto out; + } + + result = NULL; + s = g_udev_device_get_property (device, key); + if (s == NULL) + goto out; + + result = split_at_whitespace (s); + if (result == NULL) + goto out; + + if (device->priv->prop_strvs == NULL) + device->priv->prop_strvs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_strfreev); + g_hash_table_insert (device->priv->prop_strvs, g_strdup (key), result); + +out: + return (const gchar* const *) result; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +/** + * g_udev_device_get_sysfs_attr: + * @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 index 0000000000..d4873bad0f --- /dev/null +++ b/src/udev/gudev/gudevdevice.h @@ -0,0 +1,128 @@ +/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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 can be included directly, this file may disappear or change contents." +#endif + +#ifndef __G_UDEV_DEVICE_H__ +#define __G_UDEV_DEVICE_H__ + +#include + +G_BEGIN_DECLS + +#define G_UDEV_TYPE_DEVICE (g_udev_device_get_type ()) +#define G_UDEV_DEVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_UDEV_TYPE_DEVICE, GUdevDevice)) +#define G_UDEV_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_UDEV_TYPE_DEVICE, GUdevDeviceClass)) +#define G_UDEV_IS_DEVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_UDEV_TYPE_DEVICE)) +#define G_UDEV_IS_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_UDEV_TYPE_DEVICE)) +#define G_UDEV_DEVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_UDEV_TYPE_DEVICE, GUdevDeviceClass)) + +typedef struct _GUdevDeviceClass GUdevDeviceClass; +typedef struct _GUdevDevicePrivate GUdevDevicePrivate; + +/** + * GUdevDevice: + * + * The #GUdevDevice struct is opaque and should not be accessed directly. + */ +struct _GUdevDevice +{ + GObject parent; + + /*< private >*/ + GUdevDevicePrivate *priv; +}; + +/** + * GUdevDeviceClass: + * @parent_class: Parent class. + * + * Class structure for #GUdevDevice. + */ +struct _GUdevDeviceClass +{ + GObjectClass parent_class; + + /*< private >*/ + /* Padding for future expansion */ + void (*reserved1) (void); + void (*reserved2) (void); + void (*reserved3) (void); + void (*reserved4) (void); + void (*reserved5) (void); + void (*reserved6) (void); + void (*reserved7) (void); + void (*reserved8) (void); +}; + +GType g_udev_device_get_type (void) G_GNUC_CONST; +gboolean g_udev_device_get_is_initialized (GUdevDevice *device); +guint64 g_udev_device_get_usec_since_initialized (GUdevDevice *device); +const gchar *g_udev_device_get_subsystem (GUdevDevice *device); +const gchar *g_udev_device_get_devtype (GUdevDevice *device); +const gchar *g_udev_device_get_name (GUdevDevice *device); +const gchar *g_udev_device_get_number (GUdevDevice *device); +const gchar *g_udev_device_get_sysfs_path (GUdevDevice *device); +const gchar *g_udev_device_get_driver (GUdevDevice *device); +const gchar *g_udev_device_get_action (GUdevDevice *device); +guint64 g_udev_device_get_seqnum (GUdevDevice *device); +GUdevDeviceType g_udev_device_get_device_type (GUdevDevice *device); +GUdevDeviceNumber g_udev_device_get_device_number (GUdevDevice *device); +const gchar *g_udev_device_get_device_file (GUdevDevice *device); +const gchar* const *g_udev_device_get_device_file_symlinks (GUdevDevice *device); +GUdevDevice *g_udev_device_get_parent (GUdevDevice *device); +GUdevDevice *g_udev_device_get_parent_with_subsystem (GUdevDevice *device, + const gchar *subsystem, + const gchar *devtype); +const gchar* const *g_udev_device_get_property_keys (GUdevDevice *device); +gboolean g_udev_device_has_property (GUdevDevice *device, + const gchar *key); +const gchar *g_udev_device_get_property (GUdevDevice *device, + const gchar *key); +gint g_udev_device_get_property_as_int (GUdevDevice *device, + const gchar *key); +guint64 g_udev_device_get_property_as_uint64 (GUdevDevice *device, + const gchar *key); +gdouble g_udev_device_get_property_as_double (GUdevDevice *device, + const gchar *key); +gboolean g_udev_device_get_property_as_boolean (GUdevDevice *device, + const gchar *key); +const gchar* const *g_udev_device_get_property_as_strv (GUdevDevice *device, + const gchar *key); + +const gchar *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 index 0000000000..db09074625 --- /dev/null +++ b/src/udev/gudev/gudevenumerator.c @@ -0,0 +1,431 @@ +/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2008-2010 David Zeuthen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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 +#include + +#include "gudevclient.h" +#include "gudevenumerator.h" +#include "gudevdevice.h" +#include "gudevmarshal.h" +#include "gudevprivate.h" + +/** + * SECTION:gudevenumerator + * @short_description: Lookup and sort devices + * + * #GUdevEnumerator is used to lookup and sort devices. + * + * Since: 165 + */ + +struct _GUdevEnumeratorPrivate +{ + GUdevClient *client; + struct udev_enumerate *e; +}; + +enum +{ + PROP_0, + PROP_CLIENT, +}; + +G_DEFINE_TYPE (GUdevEnumerator, g_udev_enumerator, G_TYPE_OBJECT) + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +g_udev_enumerator_finalize (GObject *object) +{ + GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object); + + if (enumerator->priv->client != NULL) + { + g_object_unref (enumerator->priv->client); + enumerator->priv->client = NULL; + } + + if (enumerator->priv->e != NULL) + { + udev_enumerate_unref (enumerator->priv->e); + enumerator->priv->e = NULL; + } + + if (G_OBJECT_CLASS (g_udev_enumerator_parent_class)->finalize != NULL) + G_OBJECT_CLASS (g_udev_enumerator_parent_class)->finalize (object); +} + +static void +g_udev_enumerator_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object); + + switch (prop_id) + { + case PROP_CLIENT: + if (enumerator->priv->client != NULL) + g_object_unref (enumerator->priv->client); + enumerator->priv->client = g_value_dup_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +g_udev_enumerator_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object); + + switch (prop_id) + { + case PROP_CLIENT: + g_value_set_object (value, enumerator->priv->client); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +g_udev_enumerator_constructed (GObject *object) +{ + GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object); + + g_assert (G_UDEV_IS_CLIENT (enumerator->priv->client)); + + enumerator->priv->e = udev_enumerate_new (_g_udev_client_get_udev (enumerator->priv->client)); + + if (G_OBJECT_CLASS (g_udev_enumerator_parent_class)->constructed != NULL) + G_OBJECT_CLASS (g_udev_enumerator_parent_class)->constructed (object); +} + +static void +g_udev_enumerator_class_init (GUdevEnumeratorClass *klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + + gobject_class->finalize = g_udev_enumerator_finalize; + gobject_class->set_property = g_udev_enumerator_set_property; + gobject_class->get_property = g_udev_enumerator_get_property; + gobject_class->constructed = g_udev_enumerator_constructed; + + /** + * GUdevEnumerator:client: + * + * The #GUdevClient to enumerate devices from. + * + * Since: 165 + */ + g_object_class_install_property (gobject_class, + PROP_CLIENT, + g_param_spec_object ("client", + "The client to enumerate devices from", + "The client to enumerate devices from", + G_UDEV_TYPE_CLIENT, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE)); + + g_type_class_add_private (klass, sizeof (GUdevEnumeratorPrivate)); +} + +static void +g_udev_enumerator_init (GUdevEnumerator *enumerator) +{ + enumerator->priv = G_TYPE_INSTANCE_GET_PRIVATE (enumerator, + G_UDEV_TYPE_ENUMERATOR, + GUdevEnumeratorPrivate); +} + +/** + * g_udev_enumerator_new: + * @client: A #GUdevClient to enumerate devices from. + * + * Constructs a #GUdevEnumerator object that can be used to enumerate + * and sort devices. Use the add_match_*() and add_nomatch_*() methods + * and execute the query to get a list of devices with + * g_udev_enumerator_execute(). + * + * Returns: A new #GUdevEnumerator object. Free with g_object_unref(). + * + * Since: 165 + */ +GUdevEnumerator * +g_udev_enumerator_new (GUdevClient *client) +{ + g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); + return G_UDEV_ENUMERATOR (g_object_new (G_UDEV_TYPE_ENUMERATOR, "client", client, NULL)); +} + + +/** + * g_udev_enumerator_add_match_subsystem: + * @enumerator: A #GUdevEnumerator. + * @subsystem: Wildcard for subsystem name e.g. 'scsi' or 'a*'. + * + * All returned devices will match the given @subsystem. + * + * Returns: (transfer none): The passed in @enumerator. + * + * Since: 165 + */ +GUdevEnumerator * +g_udev_enumerator_add_match_subsystem (GUdevEnumerator *enumerator, + const gchar *subsystem) +{ + g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); + g_return_val_if_fail (subsystem != NULL, NULL); + udev_enumerate_add_match_subsystem (enumerator->priv->e, subsystem); + return enumerator; +} + +/** + * g_udev_enumerator_add_nomatch_subsystem: + * @enumerator: A #GUdevEnumerator. + * @subsystem: Wildcard for subsystem name e.g. 'scsi' or 'a*'. + * + * All returned devices will not match the given @subsystem. + * + * Returns: (transfer none): The passed in @enumerator. + * + * Since: 165 + */ +GUdevEnumerator * +g_udev_enumerator_add_nomatch_subsystem (GUdevEnumerator *enumerator, + const gchar *subsystem) +{ + g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); + g_return_val_if_fail (subsystem != NULL, NULL); + udev_enumerate_add_nomatch_subsystem (enumerator->priv->e, subsystem); + return enumerator; +} + +/** + * g_udev_enumerator_add_match_sysfs_attr: + * @enumerator: A #GUdevEnumerator. + * @name: Wildcard filter for sysfs attribute key. + * @value: Wildcard filter for sysfs attribute value. + * + * All returned devices will have a sysfs attribute matching the given @name and @value. + * + * Returns: (transfer none): The passed in @enumerator. + * + * Since: 165 + */ +GUdevEnumerator * +g_udev_enumerator_add_match_sysfs_attr (GUdevEnumerator *enumerator, + const gchar *name, + const gchar *value) +{ + g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (value != NULL, NULL); + udev_enumerate_add_match_sysattr (enumerator->priv->e, name, value); + return enumerator; +} + +/** + * g_udev_enumerator_add_nomatch_sysfs_attr: + * @enumerator: A #GUdevEnumerator. + * @name: Wildcard filter for sysfs attribute key. + * @value: Wildcard filter for sysfs attribute value. + * + * All returned devices will not have a sysfs attribute matching the given @name and @value. + * + * Returns: (transfer none): The passed in @enumerator. + * + * Since: 165 + */ +GUdevEnumerator * +g_udev_enumerator_add_nomatch_sysfs_attr (GUdevEnumerator *enumerator, + const gchar *name, + const gchar *value) +{ + g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (value != NULL, NULL); + udev_enumerate_add_nomatch_sysattr (enumerator->priv->e, name, value); + return enumerator; +} + +/** + * g_udev_enumerator_add_match_property: + * @enumerator: A #GUdevEnumerator. + * @name: Wildcard filter for property name. + * @value: Wildcard filter for property value. + * + * All returned devices will have a property matching the given @name and @value. + * + * Returns: (transfer none): The passed in @enumerator. + * + * Since: 165 + */ +GUdevEnumerator * +g_udev_enumerator_add_match_property (GUdevEnumerator *enumerator, + const gchar *name, + const gchar *value) +{ + g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (value != NULL, NULL); + udev_enumerate_add_match_property (enumerator->priv->e, name, value); + return enumerator; +} + +/** + * g_udev_enumerator_add_match_name: + * @enumerator: A #GUdevEnumerator. + * @name: Wildcard filter for kernel name e.g. "sda*". + * + * All returned devices will match the given @name. + * + * Returns: (transfer none): The passed in @enumerator. + * + * Since: 165 + */ +GUdevEnumerator * +g_udev_enumerator_add_match_name (GUdevEnumerator *enumerator, + const gchar *name) +{ + g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); + g_return_val_if_fail (name != NULL, NULL); + udev_enumerate_add_match_sysname (enumerator->priv->e, name); + return enumerator; +} + +/** + * g_udev_enumerator_add_sysfs_path: + * @enumerator: A #GUdevEnumerator. + * @sysfs_path: A sysfs path, e.g. "/sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda" + * + * Add a device to the list of devices, to retrieve it back sorted in dependency order. + * + * Returns: (transfer none): The passed in @enumerator. + * + * Since: 165 + */ +GUdevEnumerator * +g_udev_enumerator_add_sysfs_path (GUdevEnumerator *enumerator, + const gchar *sysfs_path) +{ + g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); + g_return_val_if_fail (sysfs_path != NULL, NULL); + udev_enumerate_add_syspath (enumerator->priv->e, sysfs_path); + return enumerator; +} + +/** + * g_udev_enumerator_add_match_tag: + * @enumerator: A #GUdevEnumerator. + * @tag: A udev tag e.g. "udev-acl". + * + * All returned devices will match the given @tag. + * + * Returns: (transfer none): The passed in @enumerator. + * + * Since: 165 + */ +GUdevEnumerator * +g_udev_enumerator_add_match_tag (GUdevEnumerator *enumerator, + const gchar *tag) +{ + g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); + g_return_val_if_fail (tag != NULL, NULL); + udev_enumerate_add_match_tag (enumerator->priv->e, tag); + return enumerator; +} + +/** + * g_udev_enumerator_add_match_is_initialized: + * @enumerator: A #GUdevEnumerator. + * + * All returned devices will be initialized. + * + * Returns: (transfer none): The passed in @enumerator. + * + * Since: 165 + */ +GUdevEnumerator * +g_udev_enumerator_add_match_is_initialized (GUdevEnumerator *enumerator) +{ + g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); + udev_enumerate_add_match_is_initialized (enumerator->priv->e); + return enumerator; +} + +/** + * g_udev_enumerator_execute: + * @enumerator: A #GUdevEnumerator. + * + * Executes the query in @enumerator. + * + * Returns: (element-type GUdevDevice) (transfer full): A list of #GUdevDevice objects. The caller should free the result by using g_object_unref() on each element in the list and then g_list_free() on the list. + * + * Since: 165 + */ +GList * +g_udev_enumerator_execute (GUdevEnumerator *enumerator) +{ + GList *ret; + struct udev_list_entry *l, *devices; + + g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); + + ret = NULL; + + /* retrieve the list */ + udev_enumerate_scan_devices (enumerator->priv->e); + + devices = udev_enumerate_get_list_entry (enumerator->priv->e); + for (l = devices; l != NULL; l = udev_list_entry_get_next (l)) + { + struct udev_device *udevice; + GUdevDevice *device; + + udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerator->priv->e), + udev_list_entry_get_name (l)); + if (udevice == NULL) + continue; + + device = _g_udev_device_new (udevice); + udev_device_unref (udevice); + ret = g_list_prepend (ret, device); + } + + ret = g_list_reverse (ret); + + return ret; +} diff --git a/src/udev/gudev/gudevenumerator.h b/src/udev/gudev/gudevenumerator.h new file mode 100644 index 0000000000..3fddccf573 --- /dev/null +++ b/src/udev/gudev/gudevenumerator.h @@ -0,0 +1,107 @@ +/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2008-2010 David Zeuthen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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 can be included directly, this file may disappear or change contents." +#endif + +#ifndef __G_UDEV_ENUMERATOR_H__ +#define __G_UDEV_ENUMERATOR_H__ + +#include + +G_BEGIN_DECLS + +#define G_UDEV_TYPE_ENUMERATOR (g_udev_enumerator_get_type ()) +#define G_UDEV_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_UDEV_TYPE_ENUMERATOR, GUdevEnumerator)) +#define G_UDEV_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_UDEV_TYPE_ENUMERATOR, GUdevEnumeratorClass)) +#define G_UDEV_IS_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_UDEV_TYPE_ENUMERATOR)) +#define G_UDEV_IS_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_UDEV_TYPE_ENUMERATOR)) +#define G_UDEV_ENUMERATOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_UDEV_TYPE_ENUMERATOR, GUdevEnumeratorClass)) + +typedef struct _GUdevEnumeratorClass GUdevEnumeratorClass; +typedef struct _GUdevEnumeratorPrivate GUdevEnumeratorPrivate; + +/** + * GUdevEnumerator: + * + * The #GUdevEnumerator struct is opaque and should not be accessed directly. + * + * Since: 165 + */ +struct _GUdevEnumerator +{ + GObject parent; + + /*< private >*/ + GUdevEnumeratorPrivate *priv; +}; + +/** + * GUdevEnumeratorClass: + * @parent_class: Parent class. + * + * Class structure for #GUdevEnumerator. + * + * Since: 165 + */ +struct _GUdevEnumeratorClass +{ + GObjectClass parent_class; + + /*< private >*/ + /* Padding for future expansion */ + void (*reserved1) (void); + void (*reserved2) (void); + void (*reserved3) (void); + void (*reserved4) (void); + void (*reserved5) (void); + void (*reserved6) (void); + void (*reserved7) (void); + void (*reserved8) (void); +}; + +GType g_udev_enumerator_get_type (void) G_GNUC_CONST; +GUdevEnumerator *g_udev_enumerator_new (GUdevClient *client); +GUdevEnumerator *g_udev_enumerator_add_match_subsystem (GUdevEnumerator *enumerator, + const gchar *subsystem); +GUdevEnumerator *g_udev_enumerator_add_nomatch_subsystem (GUdevEnumerator *enumerator, + const gchar *subsystem); +GUdevEnumerator *g_udev_enumerator_add_match_sysfs_attr (GUdevEnumerator *enumerator, + const gchar *name, + const gchar *value); +GUdevEnumerator *g_udev_enumerator_add_nomatch_sysfs_attr (GUdevEnumerator *enumerator, + const gchar *name, + const gchar *value); +GUdevEnumerator *g_udev_enumerator_add_match_property (GUdevEnumerator *enumerator, + const gchar *name, + const gchar *value); +GUdevEnumerator *g_udev_enumerator_add_match_name (GUdevEnumerator *enumerator, + const gchar *name); +GUdevEnumerator *g_udev_enumerator_add_match_tag (GUdevEnumerator *enumerator, + const gchar *tag); +GUdevEnumerator *g_udev_enumerator_add_match_is_initialized (GUdevEnumerator *enumerator); +GUdevEnumerator *g_udev_enumerator_add_sysfs_path (GUdevEnumerator *enumerator, + const gchar *sysfs_path); +GList *g_udev_enumerator_execute (GUdevEnumerator *enumerator); + +G_END_DECLS + +#endif /* __G_UDEV_ENUMERATOR_H__ */ diff --git a/src/udev/gudev/gudevenums.h b/src/udev/gudev/gudevenums.h new file mode 100644 index 0000000000..c3a0aa8747 --- /dev/null +++ b/src/udev/gudev/gudevenums.h @@ -0,0 +1,49 @@ +/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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 can be included directly, this file may disappear or change contents." +#endif + +#ifndef __G_UDEV_ENUMS_H__ +#define __G_UDEV_ENUMS_H__ + +#include + +G_BEGIN_DECLS + +/** + * GUdevDeviceType: + * @G_UDEV_DEVICE_TYPE_NONE: Device does not have a device file. + * @G_UDEV_DEVICE_TYPE_BLOCK: Device is a block device. + * @G_UDEV_DEVICE_TYPE_CHAR: Device is a character device. + * + * Enumeration used to specify a the type of a device. + */ +typedef enum +{ + G_UDEV_DEVICE_TYPE_NONE = 0, + G_UDEV_DEVICE_TYPE_BLOCK = 'b', + G_UDEV_DEVICE_TYPE_CHAR = 'c', +} GUdevDeviceType; + +G_END_DECLS + +#endif /* __G_UDEV_ENUMS_H__ */ diff --git a/src/udev/gudev/gudevenumtypes.c.template b/src/udev/gudev/gudevenumtypes.c.template new file mode 100644 index 0000000000..fc30b39e2e --- /dev/null +++ b/src/udev/gudev/gudevenumtypes.c.template @@ -0,0 +1,39 @@ +/*** BEGIN file-header ***/ +#include + +/*** END file-header ***/ + +/*** BEGIN file-production ***/ +/* enumerations from "@filename@" */ +/*** END file-production ***/ + +/*** BEGIN value-header ***/ +GType +@enum_name@_get_type (void) +{ + static volatile gsize g_define_type_id__volatile = 0; + + if (g_once_init_enter (&g_define_type_id__volatile)) + { + static const G@Type@Value values[] = { +/*** END value-header ***/ + +/*** BEGIN value-production ***/ + { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, +/*** END value-production ***/ + +/*** BEGIN value-tail ***/ + { 0, NULL, NULL } + }; + GType g_define_type_id = + g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); + g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); + } + + return g_define_type_id__volatile; +} + +/*** END value-tail ***/ + +/*** BEGIN file-tail ***/ +/*** END file-tail ***/ diff --git a/src/udev/gudev/gudevenumtypes.h.template b/src/udev/gudev/gudevenumtypes.h.template new file mode 100644 index 0000000000..d0ab3393e6 --- /dev/null +++ b/src/udev/gudev/gudevenumtypes.h.template @@ -0,0 +1,24 @@ +/*** BEGIN file-header ***/ +#ifndef __GUDEV_ENUM_TYPES_H__ +#define __GUDEV_ENUM_TYPES_H__ + +#include + +G_BEGIN_DECLS +/*** END file-header ***/ + +/*** BEGIN file-production ***/ + +/* enumerations from "@filename@" */ +/*** END file-production ***/ + +/*** BEGIN value-header ***/ +GType @enum_name@_get_type (void) G_GNUC_CONST; +#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ()) +/*** END value-header ***/ + +/*** BEGIN file-tail ***/ +G_END_DECLS + +#endif /* __GUDEV_ENUM_TYPES_H__ */ +/*** END file-tail ***/ diff --git a/src/udev/gudev/gudevmarshal.list b/src/udev/gudev/gudevmarshal.list new file mode 100644 index 0000000000..7e665999e8 --- /dev/null +++ b/src/udev/gudev/gudevmarshal.list @@ -0,0 +1 @@ +VOID:STRING,OBJECT diff --git a/src/udev/gudev/gudevprivate.h b/src/udev/gudev/gudevprivate.h new file mode 100644 index 0000000000..8866f52b88 --- /dev/null +++ b/src/udev/gudev/gudevprivate.h @@ -0,0 +1,41 @@ +/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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 can be included directly, this file may disappear or change contents." +#endif + +#ifndef __G_UDEV_PRIVATE_H__ +#define __G_UDEV_PRIVATE_H__ + +#include + +#include + +G_BEGIN_DECLS + +GUdevDevice * +_g_udev_device_new (struct udev_device *udevice); + +struct udev *_g_udev_client_get_udev (GUdevClient *client); + +G_END_DECLS + +#endif /* __G_UDEV_PRIVATE_H__ */ diff --git a/src/udev/gudev/gudevtypes.h b/src/udev/gudev/gudevtypes.h new file mode 100644 index 0000000000..888482783d --- /dev/null +++ b/src/udev/gudev/gudevtypes.h @@ -0,0 +1,51 @@ +/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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 can be included directly, this file may disappear or change contents." +#endif + +#ifndef __G_UDEV_TYPES_H__ +#define __G_UDEV_TYPES_H__ + +#include +#include + +G_BEGIN_DECLS + +typedef struct _GUdevClient GUdevClient; +typedef struct _GUdevDevice GUdevDevice; +typedef struct _GUdevEnumerator GUdevEnumerator; + +/** + * GUdevDeviceNumber: + * + * Corresponds to the standard #dev_t type as defined by POSIX (Until + * bug 584517 is resolved this work-around is needed). + */ +#ifdef _GUDEV_WORK_AROUND_DEV_T_BUG +typedef guint64 GUdevDeviceNumber; /* __UQUAD_TYPE */ +#else +typedef dev_t GUdevDeviceNumber; +#endif + +G_END_DECLS + +#endif /* __G_UDEV_TYPES_H__ */ diff --git a/src/udev/gudev/seed-example-enum.js b/src/udev/gudev/seed-example-enum.js new file mode 100755 index 0000000000..66206ad806 --- /dev/null +++ b/src/udev/gudev/seed-example-enum.js @@ -0,0 +1,38 @@ +#!/usr/bin/env seed + +const GLib = imports.gi.GLib; +const GUdev = imports.gi.GUdev; + +function print_device(device) { + print(" initialized: " + device.get_is_initialized()); + print(" usec since initialized: " + device.get_usec_since_initialized()); + print(" subsystem: " + device.get_subsystem()); + print(" devtype: " + device.get_devtype()); + print(" name: " + device.get_name()); + print(" number: " + device.get_number()); + print(" sysfs_path: " + device.get_sysfs_path()); + print(" driver: " + device.get_driver()); + print(" action: " + device.get_action()); + print(" seqnum: " + device.get_seqnum()); + print(" device type: " + device.get_device_type()); + print(" device number: " + device.get_device_number()); + print(" device file: " + device.get_device_file()); + print(" device file symlinks: " + device.get_device_file_symlinks()); + print(" tags: " + device.get_tags()); + var keys = device.get_property_keys(); + for (var n = 0; n < keys.length; n++) { + print(" " + keys[n] + "=" + device.get_property(keys[n])); + } +} + +var client = new GUdev.Client({subsystems: []}); +var enumerator = new GUdev.Enumerator({client: client}); +enumerator.add_match_subsystem('b*') + +var devices = enumerator.execute(); + +for (var n=0; n < devices.length; n++) { + var device = devices[n]; + print_device(device); + print(""); +} diff --git a/src/udev/gudev/seed-example.js b/src/udev/gudev/seed-example.js new file mode 100755 index 0000000000..e2ac324d23 --- /dev/null +++ b/src/udev/gudev/seed-example.js @@ -0,0 +1,72 @@ +#!/usr/bin/env seed + +// seed example + +const GLib = imports.gi.GLib; +const GUdev = imports.gi.GUdev; + +function print_device (device) { + print (" subsystem: " + device.get_subsystem ()); + print (" devtype: " + device.get_devtype ()); + print (" name: " + device.get_name ()); + print (" number: " + device.get_number ()); + print (" sysfs_path: " + device.get_sysfs_path ()); + print (" driver: " + device.get_driver ()); + print (" action: " + device.get_action ()); + print (" seqnum: " + device.get_seqnum ()); + print (" device type: " + device.get_device_type ()); + print (" device number: " + device.get_device_number ()); + print (" device file: " + device.get_device_file ()); + print (" device file symlinks: " + device.get_device_file_symlinks ()); + print (" foo: " + device.get_sysfs_attr_as_strv ("stat")); + var keys = device.get_property_keys (); + for (var n = 0; n < keys.length; n++) { + print (" " + keys[n] + "=" + device.get_property (keys[n])); + } +} + +function on_uevent (client, action, device) { + print ("action " + action + " on device " + device.get_sysfs_path()); + print_device (device); + print (""); +} + +var client = new GUdev.Client ({subsystems: ["block", "usb/usb_interface"]}); +client.signal.connect ("uevent", on_uevent); + +var block_devices = client.query_by_subsystem ("block"); +for (var n = 0; n < block_devices.length; n++) { + print ("block device: " + block_devices[n].get_device_file ()); +} + +var d; + +d = client.query_by_device_number (GUdev.DeviceType.BLOCK, 0x0810); +if (d == null) { + print ("query_by_device_number 0x810 -> null"); +} else { + print ("query_by_device_number 0x810 -> " + d.get_device_file ()); + dd = d.get_parent_with_subsystem ("usb", null); + print_device (dd); + print ("--------------------------------------------------------------------------"); + while (d != null) { + print_device (d); + print (""); + d = d.get_parent (); + } +} + +d = client.query_by_sysfs_path ("/sys/block/sda/sda1"); +print ("query_by_sysfs_path (\"/sys/block/sda1\") -> " + d.get_device_file ()); + +d = client.query_by_subsystem_and_name ("block", "sda2"); +print ("query_by_subsystem_and_name (\"block\", \"sda2\") -> " + d.get_device_file ()); + +d = client.query_by_device_file ("/dev/sda"); +print ("query_by_device_file (\"/dev/sda\") -> " + d.get_device_file ()); + +d = client.query_by_device_file ("/dev/block/8:0"); +print ("query_by_device_file (\"/dev/block/8:0\") -> " + d.get_device_file ()); + +var mainloop = GLib.main_loop_new (); +GLib.main_loop_run (mainloop); diff --git a/src/udev/keymap/.gitignore b/src/udev/keymap/.gitignore new file mode 100644 index 0000000000..4567584f4e --- /dev/null +++ b/src/udev/keymap/.gitignore @@ -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 index 0000000000..03d56e8aa4 --- /dev/null +++ b/src/udev/keymap/95-keyboard-force-release.rules @@ -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 index 0000000000..bbf311a17a --- /dev/null +++ b/src/udev/keymap/95-keymap.rules @@ -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 index 0000000000..52d50ed2de --- /dev/null +++ b/src/udev/keymap/README.keymap.txt @@ -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 . diff --git a/src/udev/keymap/check-keymaps.sh b/src/udev/keymap/check-keymaps.sh new file mode 100755 index 0000000000..405168c667 --- /dev/null +++ b/src/udev/keymap/check-keymaps.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +# check that all key names in keymaps/* are known in +# 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 index 0000000000..9ce27429b2 --- /dev/null +++ b/src/udev/keymap/findkeyboards @@ -0,0 +1,68 @@ +#!/bin/sh -e +# Find "real" keyboard devices and print their device path. +# Author: Martin Pitt +# +# 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 index 0000000000..3a7654d735 --- /dev/null +++ b/src/udev/keymap/force-release-maps/common-volume-keys @@ -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 index 0000000000..18e9bdee66 --- /dev/null +++ b/src/udev/keymap/force-release-maps/dell-touchpad @@ -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 index 0000000000..6621370095 --- /dev/null +++ b/src/udev/keymap/force-release-maps/hp-other @@ -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 index 0000000000..65707effb7 --- /dev/null +++ b/src/udev/keymap/force-release-maps/samsung-90x3a @@ -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 index 0000000000..c51123a0b6 --- /dev/null +++ b/src/udev/keymap/force-release-maps/samsung-other @@ -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 index 0000000000..dd040cebc3 --- /dev/null +++ b/src/udev/keymap/keyboard-force-release.sh.in @@ -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 index 0000000000..4c30ccf314 --- /dev/null +++ b/src/udev/keymap/keymap.c @@ -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 + * Adapted for udev-extras by Martin Pitt + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 []\n" + " keymap scancode keyname [...]\n" + " keymap -i \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 index 0000000000..4e7c297dea --- /dev/null +++ b/src/udev/keymap/keymaps/acer @@ -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 index 0000000000..1496d63a52 --- /dev/null +++ b/src/udev/keymap/keymaps/acer-aspire_5720 @@ -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 index 0000000000..633c4e854c --- /dev/null +++ b/src/udev/keymap/keymaps/acer-aspire_5920g @@ -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 index 0000000000..699c954b4e --- /dev/null +++ b/src/udev/keymap/keymaps/acer-aspire_6920 @@ -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 index 0000000000..fb27bfb4f5 --- /dev/null +++ b/src/udev/keymap/keymaps/acer-aspire_8930 @@ -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 index 0000000000..bfef4cf868 --- /dev/null +++ b/src/udev/keymap/keymaps/acer-travelmate_c300 @@ -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 index 0000000000..2a5995f982 --- /dev/null +++ b/src/udev/keymap/keymaps/asus @@ -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 index 0000000000..5fbc573aa4 --- /dev/null +++ b/src/udev/keymap/keymaps/compaq-e_evo @@ -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 index 0000000000..4f907b3eef --- /dev/null +++ b/src/udev/keymap/keymaps/dell @@ -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 index 0000000000..39872f559d --- /dev/null +++ b/src/udev/keymap/keymaps/dell-latitude-xt2 @@ -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 index 0000000000..4823a832f5 --- /dev/null +++ b/src/udev/keymap/keymaps/everex-xt5000 @@ -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 index 0000000000..9b8b36a170 --- /dev/null +++ b/src/udev/keymap/keymaps/fujitsu-amilo_li_2732 @@ -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 index 0000000000..f7b0c52444 --- /dev/null +++ b/src/udev/keymap/keymaps/fujitsu-amilo_pa_2548 @@ -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 index 0000000000..d2e38cbb23 --- /dev/null +++ b/src/udev/keymap/keymaps/fujitsu-amilo_pro_edition_v3505 @@ -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 index 0000000000..43e3199d59 --- /dev/null +++ b/src/udev/keymap/keymaps/fujitsu-amilo_pro_v3205 @@ -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 index 0000000000..1419bd9b5e --- /dev/null +++ b/src/udev/keymap/keymaps/fujitsu-amilo_si_1520 @@ -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 index 0000000000..d3d056b366 --- /dev/null +++ b/src/udev/keymap/keymaps/fujitsu-esprimo_mobile_v5 @@ -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 index 0000000000..52c70c50cb --- /dev/null +++ b/src/udev/keymap/keymaps/fujitsu-esprimo_mobile_v6 @@ -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 index 0000000000..d0a3656dd8 --- /dev/null +++ b/src/udev/keymap/keymaps/genius-slimstar-320 @@ -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 index 0000000000..4461fa2ce5 --- /dev/null +++ b/src/udev/keymap/keymaps/hewlett-packard @@ -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 index 0000000000..41ad2e9b5a --- /dev/null +++ b/src/udev/keymap/keymaps/hewlett-packard-2510p_2530p @@ -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 index 0000000000..42007c5483 --- /dev/null +++ b/src/udev/keymap/keymaps/hewlett-packard-compaq_elitebook @@ -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 index 0000000000..3d3cefc8e6 --- /dev/null +++ b/src/udev/keymap/keymaps/hewlett-packard-pavilion @@ -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 index 0000000000..1df39dcbd2 --- /dev/null +++ b/src/udev/keymap/keymaps/hewlett-packard-presario-2100 @@ -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 index 0000000000..d19005ab90 --- /dev/null +++ b/src/udev/keymap/keymaps/hewlett-packard-tablet @@ -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 index 0000000000..36a690fcf6 --- /dev/null +++ b/src/udev/keymap/keymaps/hewlett-packard-tx2 @@ -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 index 0000000000..027e50bf88 --- /dev/null +++ b/src/udev/keymap/keymaps/ibm-thinkpad-usb-keyboard-trackpoint @@ -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 index 0000000000..4a8b4ba5a7 --- /dev/null +++ b/src/udev/keymap/keymaps/inventec-symphony_6.0_7.0 @@ -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 index 0000000000..5bd165654a --- /dev/null +++ b/src/udev/keymap/keymaps/lenovo-3000 @@ -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 index 0000000000..fc339839f2 --- /dev/null +++ b/src/udev/keymap/keymaps/lenovo-ideapad @@ -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 index 0000000000..47e8846a68 --- /dev/null +++ b/src/udev/keymap/keymaps/lenovo-thinkpad-usb-keyboard-trackpoint @@ -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 index 0000000000..31ea3b2c70 --- /dev/null +++ b/src/udev/keymap/keymaps/lenovo-thinkpad_x200_tablet @@ -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 index 0000000000..6fd16b5662 --- /dev/null +++ b/src/udev/keymap/keymaps/lenovo-thinkpad_x6_tablet @@ -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 index 0000000000..ba08cba3fe --- /dev/null +++ b/src/udev/keymap/keymaps/lg-x110 @@ -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 index 0000000000..caa5d5d310 --- /dev/null +++ b/src/udev/keymap/keymaps/logitech-wave @@ -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 index 0000000000..a10dad5e4d --- /dev/null +++ b/src/udev/keymap/keymaps/logitech-wave-cordless @@ -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 index 0000000000..e7aa02206c --- /dev/null +++ b/src/udev/keymap/keymaps/logitech-wave-pro-cordless @@ -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 index 0000000000..c0e4f77af4 --- /dev/null +++ b/src/udev/keymap/keymaps/maxdata-pro_7000 @@ -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 index 0000000000..5a76c76799 --- /dev/null +++ b/src/udev/keymap/keymaps/medion-fid2060 @@ -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 index 0000000000..c3b5dfa60b --- /dev/null +++ b/src/udev/keymap/keymaps/medionnb-a555 @@ -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 index 0000000000..4a438698ed --- /dev/null +++ b/src/udev/keymap/keymaps/micro-star @@ -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 index 0000000000..773e0b3e82 --- /dev/null +++ b/src/udev/keymap/keymaps/module-asus-w3j @@ -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 index 0000000000..a92dfa2506 --- /dev/null +++ b/src/udev/keymap/keymaps/module-ibm @@ -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 index 0000000000..8e38883091 --- /dev/null +++ b/src/udev/keymap/keymaps/module-lenovo @@ -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 index 0000000000..7c000131d1 --- /dev/null +++ b/src/udev/keymap/keymaps/module-sony @@ -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 index 0000000000..596a34258a --- /dev/null +++ b/src/udev/keymap/keymaps/module-sony-old @@ -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 index 0000000000..c8ba001516 --- /dev/null +++ b/src/udev/keymap/keymaps/module-sony-vgn @@ -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 index 0000000000..34434a121d --- /dev/null +++ b/src/udev/keymap/keymaps/olpc-xo @@ -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 index 0000000000..ee864ade4d --- /dev/null +++ b/src/udev/keymap/keymaps/onkyo @@ -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 index 0000000000..b7f4851abe --- /dev/null +++ b/src/udev/keymap/keymaps/oqo-model2 @@ -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 index 0000000000..8b65eb6d03 --- /dev/null +++ b/src/udev/keymap/keymaps/samsung-90x3a @@ -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 index 0000000000..3ac0c2f10c --- /dev/null +++ b/src/udev/keymap/keymaps/samsung-other @@ -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 index 0000000000..ea2141ef84 --- /dev/null +++ b/src/udev/keymap/keymaps/samsung-sq1us @@ -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 index 0000000000..9d954ee415 --- /dev/null +++ b/src/udev/keymap/keymaps/samsung-sx20s @@ -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 index 0000000000..22007be71b --- /dev/null +++ b/src/udev/keymap/keymaps/toshiba-satellite_a100 @@ -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 index 0000000000..1429409351 --- /dev/null +++ b/src/udev/keymap/keymaps/toshiba-satellite_a110 @@ -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 index 0000000000..ae8e34941b --- /dev/null +++ b/src/udev/keymap/keymaps/toshiba-satellite_m30x @@ -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 index 0000000000..cf72fda47b --- /dev/null +++ b/src/udev/keymap/keymaps/zepto-znote @@ -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 index 0000000000..13fdb8eb57 --- /dev/null +++ b/src/udev/libudev-device-private.c @@ -0,0 +1,185 @@ +/* + * libudev - interface to udev device information + * + * Copyright (C) 2008-2010 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "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 index 0000000000..10f28b8cd5 --- /dev/null +++ b/src/udev/libudev-device.c @@ -0,0 +1,1744 @@ +/* + * libudev - interface to udev device information + * + * Copyright (C) 2008-2010 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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}/: 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 index 0000000000..034d96feba --- /dev/null +++ b/src/udev/libudev-enumerate.c @@ -0,0 +1,947 @@ +/* + * libudev - interface to udev device information + * + * Copyright (C) 2008-2010 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 0000000000..4bdef35ae8 --- /dev/null +++ b/src/udev/libudev-list.c @@ -0,0 +1,344 @@ +/* + * libudev - interface to udev device information + * + * Copyright (C) 2008 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include + +#include "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 index 0000000000..77dc55572f --- /dev/null +++ b/src/udev/libudev-monitor.c @@ -0,0 +1,874 @@ +/* + * libudev - interface to udev device information + * + * Copyright (C) 2008-2010 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 = 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 index 0000000000..4bbd8422fb --- /dev/null +++ b/src/udev/libudev-private.h @@ -0,0 +1,213 @@ +/* + * libudev - interface to udev device information + * + * Copyright (C) 2008-2010 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#ifndef _LIBUDEV_PRIVATE_H_ +#define _LIBUDEV_PRIVATE_H_ + +#include +#include +#include +#include +#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 index 0000000000..71771950aa --- /dev/null +++ b/src/udev/libudev-queue-private.c @@ -0,0 +1,412 @@ +/* + * libudev - interface to udev device information + * + * Copyright (C) 2008 Kay Sievers + * Copyright (C) 2009 Alan Jenkins + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libudev.h" +#include "libudev-private.h" + +static int rebuild_queue_file(struct udev_queue_export *udev_queue_export); + +struct udev_queue_export { + struct udev *udev; + int queued_count; /* number of unfinished events exported in queue file */ + FILE *queue_file; + unsigned long long int seqnum_max; /* earliest sequence number in queue file */ + unsigned long long int seqnum_min; /* latest sequence number in queue file */ + int waste_bytes; /* queue file bytes wasted on finished events */ +}; + +struct udev_queue_export *udev_queue_export_new(struct udev *udev) +{ + struct udev_queue_export *udev_queue_export; + unsigned long long int initial_seqnum; + + if (udev == NULL) + return NULL; + + udev_queue_export = 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 index 0000000000..0e82cb6ae8 --- /dev/null +++ b/src/udev/libudev-queue.c @@ -0,0 +1,474 @@ +/* + * libudev - interface to udev device information + * + * Copyright (C) 2008 Kay Sievers + * Copyright (C) 2009 Alan Jenkins + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "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 index 0000000000..0f2a617b18 --- /dev/null +++ b/src/udev/libudev-selinux-private.c @@ -0,0 +1,109 @@ +/* + * libudev - interface to udev device information + * + * Copyright (C) 2008 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include + +#include "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 index 0000000000..08f0ba2228 --- /dev/null +++ b/src/udev/libudev-util-private.c @@ -0,0 +1,242 @@ +/* + * libudev - interface to udev device information + * + * Copyright (C) 2003-2009 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 "[/]" 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 index 0000000000..7e345f0fb6 --- /dev/null +++ b/src/udev/libudev-util.c @@ -0,0 +1,570 @@ +/* + * libudev - interface to udev device information + * + * Copyright (C) 2008-2011 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 0000000000..dcba15de41 --- /dev/null +++ b/src/udev/libudev.c @@ -0,0 +1,457 @@ +/* + * libudev - interface to udev device information + * + * Copyright (C) 2008-2010 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "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 = 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 index 0000000000..10e098d4f7 --- /dev/null +++ b/src/udev/libudev.h @@ -0,0 +1,189 @@ +/* + * libudev - interface to udev device information + * + * Copyright (C) 2008-2011 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#ifndef _LIBUDEV_H_ +#define _LIBUDEV_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * udev - library context + * + * reads the udev config and system environment + * allows custom logging + */ +struct udev; +struct udev *udev_ref(struct udev *udev); +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 index 0000000000..c9a47fc9b8 --- /dev/null +++ b/src/udev/libudev.pc.in @@ -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 index 0ca2c03722..0000000000 --- a/src/udev/m4/.gitignore +++ /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 index 0000000000..c0e0839785 --- /dev/null +++ b/src/udev/mtd_probe/75-probe_mtd.rules @@ -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 index 0000000000..1aa08d3851 --- /dev/null +++ b/src/udev/mtd_probe/mtd_probe.c @@ -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 +#include +#include +#include +#include +#include +#include +#include + +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 index 0000000000..2a37ede578 --- /dev/null +++ b/src/udev/mtd_probe/mtd_probe.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2010 - Maxim Levitsky + * + * mtd_probe is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * mtd_probe is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with mtd_probe; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include + +/* Full oob structure as written on the flash */ +struct sm_oob { + uint32_t reserved; + uint8_t data_status; + uint8_t block_status; + uint8_t lba_copy1[2]; + uint8_t ecc2[3]; + uint8_t lba_copy2[2]; + uint8_t ecc1[3]; +} __attribute__((packed)); + + +/* one sector is always 512 bytes, but it can consist of two nand pages */ +#define SM_SECTOR_SIZE 512 + +/* oob area is also 16 bytes, but might be from two pages */ +#define SM_OOB_SIZE 16 + +/* This is maximum zone size, and all devices that have more that one zone + have this size */ +#define SM_MAX_ZONE_SIZE 1024 + +/* support for small page nand */ +#define SM_SMALL_PAGE 256 +#define SM_SMALL_OOB_SIZE 8 + + +void probe_smart_media(int mtd_fd, mtd_info_t *info); diff --git a/src/udev/mtd_probe/probe_smartmedia.c b/src/udev/mtd_probe/probe_smartmedia.c new file mode 100644 index 0000000000..b3cdefc633 --- /dev/null +++ b/src/udev/mtd_probe/probe_smartmedia.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mtd_probe.h" + +static const uint8_t cis_signature[] = { + 0x01, 0x03, 0xD9, 0x01, 0xFF, 0x18, 0x02, 0xDF, 0x01, 0x20 +}; + + +void probe_smart_media(int mtd_fd, mtd_info_t* info) +{ + 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 index d5d5897c31..0000000000 --- a/src/udev/rules/42-usb-hid-pm.rules +++ /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 index 5ad787fc76..0000000000 --- a/src/udev/rules/50-udev-default.rules +++ /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 index 8154e2dbb5..0000000000 --- a/src/udev/rules/60-persistent-alsa.rules +++ /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 index fb798ddb05..0000000000 --- a/src/udev/rules/60-persistent-input.rules +++ /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 index 2948200c53..0000000000 --- a/src/udev/rules/60-persistent-serial.rules +++ /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 index f2eabd92a8..0000000000 --- a/src/udev/rules/60-persistent-storage-tape.rules +++ /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 index b74821edd4..0000000000 --- a/src/udev/rules/60-persistent-storage.rules +++ /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 - -# 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 index ce57d48e86..0000000000 --- a/src/udev/rules/75-net-description.rules +++ /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 index 2e63e140cb..0000000000 --- a/src/udev/rules/75-tty-description.rules +++ /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 index e564441893..0000000000 --- a/src/udev/rules/78-sound-card.rules +++ /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 index 38ebfeb0e6..0000000000 --- a/src/udev/rules/80-drivers.rules +++ /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 index eca0faa5c5..0000000000 --- a/src/udev/rules/95-udev-late.rules +++ /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 index 0000000000..6aebddd809 --- /dev/null +++ b/src/udev/scsi_id/.gitignore @@ -0,0 +1 @@ +scsi_id_version.h diff --git a/src/udev/scsi_id/README b/src/udev/scsi_id/README new file mode 100644 index 0000000000..9cfe73991c --- /dev/null +++ b/src/udev/scsi_id/README @@ -0,0 +1,4 @@ +scsi_id - generate a SCSI unique identifier for a given SCSI device + +Please send questions, comments or patches to or +. diff --git a/src/udev/scsi_id/scsi.h b/src/udev/scsi_id/scsi.h new file mode 100644 index 0000000000..c423cac574 --- /dev/null +++ b/src/udev/scsi_id/scsi.h @@ -0,0 +1,97 @@ +/* + * scsi.h + * + * General scsi and linux scsi specific defines and structs. + * + * Copyright (C) IBM Corp. 2003 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#include + +struct scsi_ioctl_command { + unsigned int inlen; /* excluding scsi command length */ + unsigned int outlen; + unsigned char data[1]; + /* on input, scsi command starts here then opt. data */ +}; + +/* + * Default 5 second timeout + */ +#define DEF_TIMEOUT 5000 + +#define SENSE_BUFF_LEN 32 + +/* + * The request buffer size passed to the SCSI INQUIRY commands, use 254, + * as this is a nice value for some devices, especially some of the usb + * mass storage devices. + */ +#define SCSI_INQ_BUFF_LEN 254 + +/* + * SCSI INQUIRY vendor and model (really product) lengths. + */ +#define VENDOR_LENGTH 8 +#define MODEL_LENGTH 16 + +#define INQUIRY_CMD 0x12 +#define INQUIRY_CMDLEN 6 + +/* + * INQUIRY VPD page 0x83 identifier descriptor related values. Reference the + * SCSI Primary Commands specification for details. + */ + +/* + * id type values of id descriptors. These are assumed to fit in 4 bits. + */ +#define SCSI_ID_VENDOR_SPECIFIC 0 +#define SCSI_ID_T10_VENDOR 1 +#define SCSI_ID_EUI_64 2 +#define SCSI_ID_NAA 3 +#define SCSI_ID_RELPORT 4 +#define SCSI_ID_TGTGROUP 5 +#define SCSI_ID_LUNGROUP 6 +#define SCSI_ID_MD5 7 +#define SCSI_ID_NAME 8 + +/* + * Supported NAA values. These fit in 4 bits, so the "don't care" value + * cannot conflict with real values. + */ +#define SCSI_ID_NAA_DONT_CARE 0xff +#define SCSI_ID_NAA_IEEE_REG 5 +#define SCSI_ID_NAA_IEEE_REG_EXTENDED 6 + +/* + * Supported Code Set values. + */ +#define SCSI_ID_BINARY 1 +#define SCSI_ID_ASCII 2 + +struct scsi_id_search_values { + u_char id_type; + u_char naa_type; + u_char code_set; +}; + +/* + * Following are the "true" SCSI status codes. Linux has traditionally + * used a 1 bit right and masked version of these. So now CHECK_CONDITION + * and friends (in ) are deprecated. + */ +#define SCSI_CHECK_CONDITION 0x2 +#define SCSI_CONDITION_MET 0x4 +#define SCSI_BUSY 0x8 +#define SCSI_IMMEDIATE 0x10 +#define SCSI_IMMEDIATE_CONDITION_MET 0x14 +#define SCSI_RESERVATION_CONFLICT 0x18 +#define SCSI_COMMAND_TERMINATED 0x22 +#define SCSI_TASK_SET_FULL 0x28 +#define SCSI_ACA_ACTIVE 0x30 +#define SCSI_TASK_ABORTED 0x40 diff --git a/src/udev/scsi_id/scsi_id.c b/src/udev/scsi_id/scsi_id.c new file mode 100644 index 0000000000..9bb0d7f538 --- /dev/null +++ b/src/udev/scsi_id/scsi_id.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 \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 index 0000000000..828a98305f --- /dev/null +++ b/src/udev/scsi_id/scsi_id.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) IBM Corp. 2003 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#define MAX_PATH_LEN 512 + +/* + * MAX_ATTR_LEN: maximum length of the result of reading a sysfs + * attribute. + */ +#define MAX_ATTR_LEN 256 + +/* + * MAX_SERIAL_LEN: the maximum length of the serial number, including + * added prefixes such as vendor and product (model) strings. + */ +#define MAX_SERIAL_LEN 256 + +/* + * MAX_BUFFER_LEN: maximum buffer size and line length used while reading + * the config file. + */ +#define MAX_BUFFER_LEN 256 + +struct scsi_id_device { + char vendor[9]; + char model[17]; + char revision[5]; + char type[33]; + char kernel[64]; + char serial[MAX_SERIAL_LEN]; + char serial_short[MAX_SERIAL_LEN]; + int use_sg; + + /* Always from page 0x80 e.g. 'B3G1P8500RWT' - may not be unique */ + char unit_serial_number[MAX_SERIAL_LEN]; + + /* NULs if not set - otherwise hex encoding using lower-case e.g. '50014ee0016eb572' */ + char wwn[17]; + + /* NULs if not set - otherwise hex encoding using lower-case e.g. '0xe00000d80000' */ + char wwn_vendor_extension[17]; + + /* NULs if not set - otherwise decimal number */ + char tgpt_group[8]; +}; + +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 index 0000000000..f1d63f40cc --- /dev/null +++ b/src/udev/scsi_id/scsi_serial.c @@ -0,0 +1,990 @@ +/* + * Copyright (C) IBM Corp. 2003 + * + * Author: Patrick Mansfield + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libudev.h" +#include "libudev-private.h" +#include "scsi.h" +#include "scsi_id.h" + +/* + * A priority based list of id, naa, and binary/ascii for the identifier + * descriptor in VPD page 0x83. + * + * Brute force search for a match starting with the first value in the + * following id_search_list. This is not a performance issue, since there + * is normally one or some small number of descriptors. + */ +static const struct scsi_id_search_values id_search_list[] = { + { SCSI_ID_TGTGROUP, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, + { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_BINARY }, + { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_ASCII }, + { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_BINARY }, + { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_ASCII }, + /* + * Devices already exist using NAA values that are now marked + * reserved. These should not conflict with other values, or it is + * a bug in the device. As long as we find the IEEE extended one + * first, we really don't care what other ones are used. Using + * don't care here means that a device that returns multiple + * non-IEEE descriptors in a random order will get different + * names. + */ + { SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, + { SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, + { SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, + { SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, + { SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, + { SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, + { SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, + { SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, +}; + +static const char hex_str[]="0123456789abcdef"; + +/* + * Values returned in the result/status, only the ones used by the code + * are used here. + */ + +#define DID_NO_CONNECT 0x01 /* Unable to connect before timeout */ +#define DID_BUS_BUSY 0x02 /* Bus remain busy until timeout */ +#define DID_TIME_OUT 0x03 /* Timed out for some other reason */ +#define DRIVER_TIMEOUT 0x06 +#define DRIVER_SENSE 0x08 /* Sense_buffer has been set */ + +/* The following "category" function returns one of the following */ +#define SG_ERR_CAT_CLEAN 0 /* No errors or other information */ +#define SG_ERR_CAT_MEDIA_CHANGED 1 /* interpreted from sense buffer */ +#define SG_ERR_CAT_RESET 2 /* interpreted from sense buffer */ +#define SG_ERR_CAT_TIMEOUT 3 +#define SG_ERR_CAT_RECOVERED 4 /* Successful command after recovered err */ +#define SG_ERR_CAT_NOTSUPPORTED 5 /* Illegal / unsupported command */ +#define SG_ERR_CAT_SENSE 98 /* Something else in the sense buffer */ +#define SG_ERR_CAT_OTHER 99 /* Some other error/warning */ + +static int do_scsi_page80_inquiry(struct udev *udev, + struct scsi_id_device *dev_scsi, int fd, + char *serial, char *serial_short, int max_len); + +static int sg_err_category_new(struct udev *udev, + int scsi_status, int msg_status, int + host_status, int driver_status, const + unsigned char *sense_buffer, int sb_len) +{ + scsi_status &= 0x7e; + + /* + * XXX change to return only two values - failed or OK. + */ + + if (!scsi_status && !host_status && !driver_status) + return SG_ERR_CAT_CLEAN; + + if ((scsi_status == SCSI_CHECK_CONDITION) || + (scsi_status == SCSI_COMMAND_TERMINATED) || + ((driver_status & 0xf) == DRIVER_SENSE)) { + if (sense_buffer && (sb_len > 2)) { + int sense_key; + unsigned char asc; + + if (sense_buffer[0] & 0x2) { + sense_key = sense_buffer[1] & 0xf; + asc = sense_buffer[2]; + } else { + sense_key = sense_buffer[2] & 0xf; + asc = (sb_len > 12) ? sense_buffer[12] : 0; + } + + if (sense_key == RECOVERED_ERROR) + return SG_ERR_CAT_RECOVERED; + else if (sense_key == UNIT_ATTENTION) { + if (0x28 == asc) + return SG_ERR_CAT_MEDIA_CHANGED; + if (0x29 == asc) + return SG_ERR_CAT_RESET; + } else if (sense_key == ILLEGAL_REQUEST) { + return SG_ERR_CAT_NOTSUPPORTED; + } + } + return SG_ERR_CAT_SENSE; + } + if (host_status) { + if ((host_status == DID_NO_CONNECT) || + (host_status == DID_BUS_BUSY) || + (host_status == DID_TIME_OUT)) + return SG_ERR_CAT_TIMEOUT; + } + if (driver_status) { + if (driver_status == DRIVER_TIMEOUT) + return SG_ERR_CAT_TIMEOUT; + } + return SG_ERR_CAT_OTHER; +} + +static int sg_err_category3(struct udev *udev, struct sg_io_hdr *hp) +{ + return sg_err_category_new(udev, + hp->status, hp->msg_status, + hp->host_status, hp->driver_status, + hp->sbp, hp->sb_len_wr); +} + +static int sg_err_category4(struct udev *udev, struct sg_io_v4 *hp) +{ + return sg_err_category_new(udev, hp->device_status, 0, + hp->transport_status, hp->driver_status, + (unsigned char *)(uintptr_t)hp->response, + hp->response_len); +} + +static int scsi_dump_sense(struct udev *udev, + struct scsi_id_device *dev_scsi, + unsigned char *sense_buffer, int sb_len) +{ + int s; + int code; + int sense_class; + int sense_key; + int asc, ascq; +#ifdef DUMP_SENSE + char out_buffer[256]; + int i, j; +#endif + + /* + * Figure out and print the sense key, asc and ascq. + * + * If you want to suppress these for a particular drive model, add + * a black list entry in the scsi_id config file. + * + * XXX We probably need to: lookup the sense/asc/ascq in a retry + * table, and if found return 1 (after dumping the sense, asc, and + * ascq). So, if/when we get something like a power on/reset, + * we'll retry the command. + */ + + 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 index beb8604bc6..0000000000 --- a/src/udev/src/.gitignore +++ /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 index d2e31278b0..0000000000 --- a/src/udev/src/COPYING +++ /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. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin 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. - - , 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 index a6a2bfd088..0000000000 --- a/src/udev/src/accelerometer/61-accelerometer.rules +++ /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 index bc9715b264..0000000000 --- a/src/udev/src/accelerometer/accelerometer.c +++ /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 - * - * orientation_calc() from the sensorfw package - * Copyright (C) 2009-2010 Nokia Corporation - * Authors: - * Üstün Ergenoglu - * Timo Rongas - * Lihan Guo - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with keymap; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "libudev.h" -#include "libudev-private.h" - -/* we must use this kernel-compatible implementation */ -#define BITS_PER_LONG (sizeof(unsigned long) * 8) -#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) -#define OFF(x) ((x)%BITS_PER_LONG) -#define BIT(x) (1UL<> OFF(bit)) & 1) - -static int debug = 0; - -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] \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 index 846a73b547..0000000000 --- a/src/udev/src/ata_id/ata_id.c +++ /dev/null @@ -1,721 +0,0 @@ -/* - * ata_id - reads product/serial number from ATA drives - * - * Copyright (C) 2005-2008 Kay Sievers - * Copyright (C) 2009 Lennart Poettering - * Copyright (C) 2009-2010 David Zeuthen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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] \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 index 6eaf76a72c..0000000000 --- a/src/udev/src/cdrom_id/60-cdrom_id.rules +++ /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 index f90d52ec9c..0000000000 --- a/src/udev/src/cdrom_id/cdrom_id.c +++ /dev/null @@ -1,1099 +0,0 @@ -/* - * cdrom_id - optical drive and media information prober - * - * Copyright (C) 2008-2010 Kay Sievers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE 1 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "libudev.h" -#include "libudev-private.h" - -static bool debug; - -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 \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 \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 , 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] \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 index 076fe479e2..0000000000 --- a/src/udev/src/collect/collect.c +++ /dev/null @@ -1,473 +0,0 @@ -/* - * Collect variables across events. - * - * usage: collect [--add|--remove] - * - * Adds ID to the list governed by . - * must be part of the ID list . - * If all IDs given by are listed (ie collect has been - * invoked for each ID in ) collect returns 0, the - * number of missing IDs otherwise. - * A negative number is returned on error. - * - * Copyright(C) 2007, Hannes Reinecke - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "libudev.h" -#include "libudev-private.h" - -#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] \n" - "\n" - " Adds ID to the list governed by .\n" - " must be part of the list .\n" - " If all IDs given by are listed (ie collect has been\n" - " invoked for each ID in ) collect returns 0, the\n" - " number of missing IDs otherwise.\n" - " On error a negative number is returned.\n" - "\n"); -} - -/* - * prepare - * - * Prepares the database file - */ -static int prepare(char *dir, char *filename) -{ - struct stat statbuf; - char buf[512]; - int fd; - - if (stat(dir, &statbuf) < 0) - mkdir(dir, 0700); - - 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 index dca700a998..0000000000 --- a/src/udev/src/docs/.gitignore +++ /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 index 07d06eb14f..0000000000 --- a/src/udev/src/docs/Makefile.am +++ /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 index b7feb45529..0000000000 --- a/src/udev/src/docs/libudev-docs.xml +++ /dev/null @@ -1,32 +0,0 @@ - - -]> - - - libudev Reference Manual - for libudev version &version; - - 2009-2011 - Kay Sievers <kay.sievers@vrfy.org> - - - - - libudev - - - - - - - - - - - API Index - - - diff --git a/src/udev/src/docs/libudev-sections.txt b/src/udev/src/docs/libudev-sections.txt deleted file mode 100644 index 15c3e934b5..0000000000 --- a/src/udev/src/docs/libudev-sections.txt +++ /dev/null @@ -1,127 +0,0 @@ -
-libudev -udev -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 -
- -
-libudev-list -udev_list -udev_list_entry -udev_list_entry_get_next -udev_list_entry_get_by_name -udev_list_entry_get_name -udev_list_entry_get_value -udev_list_entry_foreach -
- -
-libudev-device -udev_device -udev_device -udev_device_ref -udev_device_unref -udev_device_get_udev -udev_device_new_from_syspath -udev_device_new_from_devnum -udev_device_new_from_subsystem_sysname -udev_device_new_from_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 -
- -
-libudev-monitor -udev_monitor -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 -
- -
-libudev-enumerate -udev_enumerate -udev_enumerate -udev_enumerate_ref -udev_enumerate_unref -udev_enumerate_get_udev -udev_enumerate_new -udev_enumerate_add_match_subsystem -udev_enumerate_add_nomatch_subsystem -udev_enumerate_add_match_sysattr -udev_enumerate_add_nomatch_sysattr -udev_enumerate_add_match_property -udev_enumerate_add_match_tag -udev_enumerate_add_match_parent -udev_enumerate_add_match_is_initialized -udev_enumerate_add_match_sysname -udev_enumerate_add_syspath -udev_enumerate_scan_devices -udev_enumerate_scan_subsystems -udev_enumerate_get_list_entry -
- -
-libudev-queue -udev_queue -udev_queue -udev_queue_ref -udev_queue_unref -udev_queue_get_udev -udev_queue_new -udev_queue_get_udev_is_active -udev_queue_get_queue_is_empty -udev_queue_get_seqnum_is_finished -udev_queue_get_seqnum_sequence_is_finished -udev_queue_get_queued_list_entry -udev_queue_get_kernel_seqnum -udev_queue_get_udev_seqnum -
- -
-libudev-util -udev_util -udev_util_encode_string -
diff --git a/src/udev/src/docs/libudev.types b/src/udev/src/docs/libudev.types deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/udev/src/docs/version.xml.in b/src/udev/src/docs/version.xml.in deleted file mode 100644 index d78bda9342..0000000000 --- a/src/udev/src/docs/version.xml.in +++ /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 index 53e4a9e59a..0000000000 --- a/src/udev/src/floppy/60-floppy.rules +++ /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 index f71ef0d809..0000000000 --- a/src/udev/src/floppy/create_floppy_devices.c +++ /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 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "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 index d20fa523e4..0000000000 --- a/src/udev/src/gudev/.gitignore +++ /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 index da97db2bd0..0000000000 --- a/src/udev/src/gudev/COPYING +++ /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. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin 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. - - , 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 index 8eada6d409..0000000000 --- a/src/udev/src/gudev/docs/.gitignore +++ /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 index cfe696c503..0000000000 --- a/src/udev/src/gudev/docs/Makefile.am +++ /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 index f876c3bc05..0000000000 --- a/src/udev/src/gudev/docs/gudev-docs.xml +++ /dev/null @@ -1,93 +0,0 @@ - - -]> - - - GUDev Reference Manual - For GUdev version &version; - - - David - Zeuthen - -
- davidz@redhat.com -
-
-
- - Bastien - Nocera - -
- hadess@hadess.net -
-
-
-
- - - 2011 - The GUDev Authors - - - - - Permission is granted to copy, distribute and/or modify this - document under the terms of the GNU Free - Documentation License, 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 GNU Free - Documentation License from the Free Software - Foundation by visiting their Web site or by writing - to: - -
- The Free Software Foundation, Inc., - 59 Temple Place - Suite 330, - Boston, MA 02111-1307, - USA -
-
- - - 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. - -
-
- - - API Reference - - - This part presents the class and function reference for the - libgudev library. - - - - - - - - - Object Hierarchy - - - - Index - - - Index of new symbols in 165 - - - -
diff --git a/src/udev/src/gudev/docs/gudev-sections.txt b/src/udev/src/gudev/docs/gudev-sections.txt deleted file mode 100644 index 213e1a7465..0000000000 --- a/src/udev/src/gudev/docs/gudev-sections.txt +++ /dev/null @@ -1,113 +0,0 @@ -
-gudevclient -GUdevClient -GUdevClient -GUdevClientClass -GUdevDeviceType -GUdevDeviceNumber -g_udev_client_new -g_udev_client_query_by_subsystem -g_udev_client_query_by_device_number -g_udev_client_query_by_device_file -g_udev_client_query_by_sysfs_path -g_udev_client_query_by_subsystem_and_name - -G_UDEV_CLIENT -G_UDEV_IS_CLIENT -G_UDEV_TYPE_CLIENT -g_udev_client_get_type -G_UDEV_CLIENT_CLASS -G_UDEV_IS_CLIENT_CLASS -G_UDEV_CLIENT_GET_CLASS - -GUdevClientPrivate -
- -
-gudevdevice -GUdevDevice -GUdevDevice -GUdevDeviceClass -g_udev_device_get_subsystem -g_udev_device_get_devtype -g_udev_device_get_name -g_udev_device_get_number -g_udev_device_get_sysfs_path -g_udev_device_get_driver -g_udev_device_get_action -g_udev_device_get_seqnum -g_udev_device_get_device_type -g_udev_device_get_device_number -g_udev_device_get_device_file -g_udev_device_get_device_file_symlinks -g_udev_device_get_parent -g_udev_device_get_parent_with_subsystem -g_udev_device_get_tags -g_udev_device_get_is_initialized -g_udev_device_get_usec_since_initialized -g_udev_device_get_property_keys -g_udev_device_has_property -g_udev_device_get_property -g_udev_device_get_property_as_int -g_udev_device_get_property_as_uint64 -g_udev_device_get_property_as_double -g_udev_device_get_property_as_boolean -g_udev_device_get_property_as_strv -g_udev_device_get_sysfs_attr -g_udev_device_get_sysfs_attr_as_int -g_udev_device_get_sysfs_attr_as_uint64 -g_udev_device_get_sysfs_attr_as_double -g_udev_device_get_sysfs_attr_as_boolean -g_udev_device_get_sysfs_attr_as_strv - -G_UDEV_DEVICE -G_UDEV_IS_DEVICE -G_UDEV_TYPE_DEVICE -g_udev_device_get_type -G_UDEV_DEVICE_CLASS -G_UDEV_IS_DEVICE_CLASS -G_UDEV_DEVICE_GET_CLASS - -GUdevDevicePrivate -
- -
-gudevenumerator -GUdevEnumerator -GUdevEnumerator -GUdevEnumeratorClass -g_udev_enumerator_new -g_udev_enumerator_add_match_subsystem -g_udev_enumerator_add_nomatch_subsystem -g_udev_enumerator_add_match_sysfs_attr -g_udev_enumerator_add_nomatch_sysfs_attr -g_udev_enumerator_add_match_property -g_udev_enumerator_add_match_name -g_udev_enumerator_add_match_tag -g_udev_enumerator_add_match_is_initialized -g_udev_enumerator_add_sysfs_path -g_udev_enumerator_execute - -G_UDEV_ENUMERATOR -G_UDEV_IS_ENUMERATOR -G_UDEV_TYPE_ENUMERATOR -g_udev_enumerator_get_type -G_UDEV_ENUMERATOR_CLASS -G_UDEV_IS_ENUMERATOR_CLASS -G_UDEV_ENUMERATOR_GET_CLASS - -GUdevEnumeratorPrivate -
- -
-gudevmarshal - -g_udev_marshal_VOID__STRING_OBJECT -
- -
-gudevenumtypes - -G_TYPE_UDEV_DEVICE_TYPE -g_udev_device_type_get_type -
diff --git a/src/udev/src/gudev/docs/gudev.types b/src/udev/src/gudev/docs/gudev.types deleted file mode 100644 index a89857a04d..0000000000 --- a/src/udev/src/gudev/docs/gudev.types +++ /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 index d78bda9342..0000000000 --- a/src/udev/src/gudev/docs/version.xml.in +++ /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 index 5586fd6a61..0000000000 --- a/src/udev/src/gudev/gjs-example.js +++ /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 index 058262d767..0000000000 --- a/src/udev/src/gudev/gudev-1.0.pc.in +++ /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 index a313460817..0000000000 --- a/src/udev/src/gudev/gudev.h +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2008 David Zeuthen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU 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 -#include -#include -#include -#include -#include -#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 index 2b94102ac5..0000000000 --- a/src/udev/src/gudev/gudevclient.c +++ /dev/null @@ -1,527 +0,0 @@ -/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2008-2010 David Zeuthen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU 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 -#include - -#include "gudevclient.h" -#include "gudevdevice.h" -#include "gudevmarshal.h" -#include "gudevprivate.h" - -/** - * SECTION:gudevclient - * @short_description: Query devices and listen to uevents - * - * #GUdevClient is used to query information about devices on a Linux - * system from the Linux kernel and the udev device - * manager. - * - * Device information is retrieved from the kernel (through the - * sysfs filesystem) and the udev daemon (through a - * tmpfs filesystem) and presented through - * #GUdevDevice objects. This means that no blocking IO ever happens - * (in both cases, we are essentially just reading data from kernel - * memory) and as such there are no asynchronous versions of the - * provided methods. - * - * To get #GUdevDevice objects, use - * g_udev_client_query_by_subsystem(), - * g_udev_client_query_by_device_number(), - * g_udev_client_query_by_device_file(), - * g_udev_client_query_by_sysfs_path(), - * g_udev_client_query_by_subsystem_and_name() - * or the #GUdevEnumerator type. - * - * To listen to uevents, connect to the #GUdevClient::uevent signal. - */ - -struct _GUdevClientPrivate -{ - GSource *watch_source; - struct udev *udev; - struct udev_monitor *monitor; - - gchar **subsystems; -}; - -enum -{ - PROP_0, - PROP_SUBSYSTEMS, -}; - -enum -{ - UEVENT_SIGNAL, - LAST_SIGNAL, -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -G_DEFINE_TYPE (GUdevClient, g_udev_client, G_TYPE_OBJECT) - -/* ---------------------------------------------------------------------------------------------------- */ - -static gboolean -monitor_event (GIOChannel *source, - GIOCondition condition, - gpointer data) -{ - GUdevClient *client = (GUdevClient *) data; - GUdevDevice *device; - struct udev_device *udevice; - - if (client->priv->monitor == NULL) - goto out; - udevice = udev_monitor_receive_device (client->priv->monitor); - if (udevice == NULL) - goto out; - - device = _g_udev_device_new (udevice); - udev_device_unref (udevice); - g_signal_emit (client, - signals[UEVENT_SIGNAL], - 0, - g_udev_device_get_action (device), - device); - g_object_unref (device); - - out: - return TRUE; -} - -static void -g_udev_client_finalize (GObject *object) -{ - GUdevClient *client = G_UDEV_CLIENT (object); - - if (client->priv->watch_source != NULL) - { - g_source_destroy (client->priv->watch_source); - client->priv->watch_source = NULL; - } - - if (client->priv->monitor != NULL) - { - udev_monitor_unref (client->priv->monitor); - client->priv->monitor = NULL; - } - - if (client->priv->udev != NULL) - { - udev_unref (client->priv->udev); - client->priv->udev = NULL; - } - - g_strfreev (client->priv->subsystems); - - if (G_OBJECT_CLASS (g_udev_client_parent_class)->finalize != NULL) - G_OBJECT_CLASS (g_udev_client_parent_class)->finalize (object); -} - -static void -g_udev_client_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GUdevClient *client = G_UDEV_CLIENT (object); - - switch (prop_id) - { - case PROP_SUBSYSTEMS: - if (client->priv->subsystems != NULL) - g_strfreev (client->priv->subsystems); - client->priv->subsystems = g_strdupv (g_value_get_boxed (value)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -g_udev_client_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GUdevClient *client = G_UDEV_CLIENT (object); - - switch (prop_id) - { - case PROP_SUBSYSTEMS: - g_value_set_boxed (value, client->priv->subsystems); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -g_udev_client_constructed (GObject *object) -{ - GUdevClient *client = G_UDEV_CLIENT (object); - GIOChannel *channel; - guint n; - - client->priv->udev = udev_new (); - - /* connect to event source */ - client->priv->monitor = udev_monitor_new_from_netlink (client->priv->udev, "udev"); - - //g_debug ("ss = %p", client->priv->subsystems); - - if (client->priv->subsystems != NULL) - { - /* install subsystem filters to only wake up for certain events */ - for (n = 0; client->priv->subsystems[n] != NULL; n++) - { - gchar *subsystem; - gchar *devtype; - gchar *s; - - subsystem = g_strdup (client->priv->subsystems[n]); - devtype = NULL; - - //g_debug ("s = '%s'", subsystem); - - s = strstr (subsystem, "/"); - if (s != NULL) - { - devtype = s + 1; - *s = '\0'; - } - - if (client->priv->monitor != NULL) - udev_monitor_filter_add_match_subsystem_devtype (client->priv->monitor, subsystem, devtype); - - g_free (subsystem); - } - - /* listen to events, and buffer them */ - if (client->priv->monitor != NULL) - { - udev_monitor_enable_receiving (client->priv->monitor); - channel = g_io_channel_unix_new (udev_monitor_get_fd (client->priv->monitor)); - client->priv->watch_source = g_io_create_watch (channel, G_IO_IN); - g_io_channel_unref (channel); - g_source_set_callback (client->priv->watch_source, (GSourceFunc) monitor_event, client, NULL); - g_source_attach (client->priv->watch_source, g_main_context_get_thread_default ()); - g_source_unref (client->priv->watch_source); - } - else - { - client->priv->watch_source = NULL; - } - } - - if (G_OBJECT_CLASS (g_udev_client_parent_class)->constructed != NULL) - G_OBJECT_CLASS (g_udev_client_parent_class)->constructed (object); -} - - -static void -g_udev_client_class_init (GUdevClientClass *klass) -{ - GObjectClass *gobject_class = (GObjectClass *) klass; - - gobject_class->constructed = g_udev_client_constructed; - gobject_class->set_property = g_udev_client_set_property; - gobject_class->get_property = g_udev_client_get_property; - gobject_class->finalize = g_udev_client_finalize; - - /** - * GUdevClient:subsystems: - * - * The subsystems to listen for uevents on. - * - * To listen for only a specific DEVTYPE for a given SUBSYSTEM, use - * "subsystem/devtype". For example, to only listen for uevents - * where SUBSYSTEM is usb and DEVTYPE is usb_interface, use - * "usb/usb_interface". - * - * If this property is %NULL, then no events will be reported. If - * it's the empty array, events from all subsystems will be - * reported. - */ - g_object_class_install_property (gobject_class, - PROP_SUBSYSTEMS, - g_param_spec_boxed ("subsystems", - "The subsystems to listen for changes on", - "The subsystems to listen for changes on", - G_TYPE_STRV, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE)); - - /** - * GUdevClient::uevent: - * @client: The #GUdevClient receiving the event. - * @action: The action for the uevent e.g. "add", "remove", "change", "move", etc. - * @device: Details about the #GUdevDevice the event is for. - * - * Emitted when @client receives an uevent. - * - * This signal is emitted in the - * thread-default main loop - * of the thread that @client was created in. - */ - signals[UEVENT_SIGNAL] = g_signal_new ("uevent", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GUdevClientClass, uevent), - NULL, - NULL, - g_udev_marshal_VOID__STRING_OBJECT, - G_TYPE_NONE, - 2, - G_TYPE_STRING, - G_UDEV_TYPE_DEVICE); - - g_type_class_add_private (klass, sizeof (GUdevClientPrivate)); -} - -static void -g_udev_client_init (GUdevClient *client) -{ - client->priv = G_TYPE_INSTANCE_GET_PRIVATE (client, - G_UDEV_TYPE_CLIENT, - GUdevClientPrivate); -} - -/** - * g_udev_client_new: - * @subsystems: (array zero-terminated=1) (element-type utf8) (transfer none) (allow-none): A %NULL terminated string array of subsystems to listen for uevents on, %NULL to not listen on uevents at all, or an empty array to listen to uevents on all subsystems. See the documentation for the #GUdevClient:subsystems property for details on this parameter. - * - * Constructs a #GUdevClient object that can be used to query - * information about devices. Connect to the #GUdevClient::uevent - * signal to listen for uevents. Note that signals are emitted in the - * thread-default main loop - * of the thread that you call this constructor from. - * - * Returns: A new #GUdevClient object. Free with g_object_unref(). - */ -GUdevClient * -g_udev_client_new (const gchar * const *subsystems) -{ - return G_UDEV_CLIENT (g_object_new (G_UDEV_TYPE_CLIENT, "subsystems", subsystems, NULL)); -} - -/** - * g_udev_client_query_by_subsystem: - * @client: A #GUdevClient. - * @subsystem: (allow-none): The subsystem to get devices for or %NULL to get all devices. - * - * Gets all devices belonging to @subsystem. - * - * Returns: (element-type GUdevDevice) (transfer full): A list of #GUdevDevice objects. The caller should free the result by using g_object_unref() on each element in the list and then g_list_free() on the list. - */ -GList * -g_udev_client_query_by_subsystem (GUdevClient *client, - const gchar *subsystem) -{ - struct udev_enumerate *enumerate; - struct udev_list_entry *l, *devices; - GList *ret; - - g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); - - ret = NULL; - - /* prepare a device scan */ - enumerate = udev_enumerate_new (client->priv->udev); - - /* filter for subsystem */ - if (subsystem != NULL) - udev_enumerate_add_match_subsystem (enumerate, subsystem); - /* retrieve the list */ - udev_enumerate_scan_devices (enumerate); - - /* add devices to the list */ - devices = udev_enumerate_get_list_entry (enumerate); - for (l = devices; l != NULL; l = udev_list_entry_get_next (l)) - { - struct udev_device *udevice; - GUdevDevice *device; - - udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate), - udev_list_entry_get_name (l)); - if (udevice == NULL) - continue; - device = _g_udev_device_new (udevice); - udev_device_unref (udevice); - ret = g_list_prepend (ret, device); - } - udev_enumerate_unref (enumerate); - - ret = g_list_reverse (ret); - - return ret; -} - -/** - * g_udev_client_query_by_device_number: - * @client: A #GUdevClient. - * @type: A value from the #GUdevDeviceType enumeration. - * @number: A device number. - * - * Looks up a device for a type and device number. - * - * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref(). - */ -GUdevDevice * -g_udev_client_query_by_device_number (GUdevClient *client, - GUdevDeviceType type, - GUdevDeviceNumber number) -{ - struct udev_device *udevice; - GUdevDevice *device; - - g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); - - device = NULL; - udevice = udev_device_new_from_devnum (client->priv->udev, type, number); - - if (udevice == NULL) - goto out; - - device = _g_udev_device_new (udevice); - udev_device_unref (udevice); - - out: - return device; -} - -/** - * g_udev_client_query_by_device_file: - * @client: A #GUdevClient. - * @device_file: A device file. - * - * Looks up a device for a device file. - * - * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref(). - */ -GUdevDevice * -g_udev_client_query_by_device_file (GUdevClient *client, - const gchar *device_file) -{ - struct stat stat_buf; - GUdevDevice *device; - - g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); - g_return_val_if_fail (device_file != NULL, NULL); - - device = NULL; - - if (stat (device_file, &stat_buf) != 0) - goto out; - - if (stat_buf.st_rdev == 0) - goto out; - - if (S_ISBLK (stat_buf.st_mode)) - device = g_udev_client_query_by_device_number (client, G_UDEV_DEVICE_TYPE_BLOCK, stat_buf.st_rdev); - else if (S_ISCHR (stat_buf.st_mode)) - device = g_udev_client_query_by_device_number (client, G_UDEV_DEVICE_TYPE_CHAR, stat_buf.st_rdev); - - out: - return device; -} - -/** - * g_udev_client_query_by_sysfs_path: - * @client: A #GUdevClient. - * @sysfs_path: A sysfs path. - * - * Looks up a device for a sysfs path. - * - * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref(). - */ -GUdevDevice * -g_udev_client_query_by_sysfs_path (GUdevClient *client, - const gchar *sysfs_path) -{ - struct udev_device *udevice; - GUdevDevice *device; - - g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); - g_return_val_if_fail (sysfs_path != NULL, NULL); - - device = NULL; - udevice = udev_device_new_from_syspath (client->priv->udev, sysfs_path); - if (udevice == NULL) - goto out; - - device = _g_udev_device_new (udevice); - udev_device_unref (udevice); - - out: - return device; -} - -/** - * g_udev_client_query_by_subsystem_and_name: - * @client: A #GUdevClient. - * @subsystem: A subsystem name. - * @name: The name of the device. - * - * Looks up a device for a subsystem and name. - * - * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref(). - */ -GUdevDevice * -g_udev_client_query_by_subsystem_and_name (GUdevClient *client, - const gchar *subsystem, - const gchar *name) -{ - struct udev_device *udevice; - GUdevDevice *device; - - g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); - g_return_val_if_fail (subsystem != NULL, NULL); - g_return_val_if_fail (name != NULL, NULL); - - device = NULL; - udevice = udev_device_new_from_subsystem_sysname (client->priv->udev, subsystem, name); - if (udevice == NULL) - goto out; - - device = _g_udev_device_new (udevice); - udev_device_unref (udevice); - - out: - return device; -} - -struct udev * -_g_udev_client_get_udev (GUdevClient *client) -{ - g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); - return client->priv->udev; -} diff --git a/src/udev/src/gudev/gudevclient.h b/src/udev/src/gudev/gudevclient.h deleted file mode 100644 index b425d03d48..0000000000 --- a/src/udev/src/gudev/gudevclient.h +++ /dev/null @@ -1,100 +0,0 @@ -/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2008 David Zeuthen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU 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 can be included directly, this file may disappear or change contents." -#endif - -#ifndef __G_UDEV_CLIENT_H__ -#define __G_UDEV_CLIENT_H__ - -#include - -G_BEGIN_DECLS - -#define G_UDEV_TYPE_CLIENT (g_udev_client_get_type ()) -#define G_UDEV_CLIENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_UDEV_TYPE_CLIENT, GUdevClient)) -#define G_UDEV_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_UDEV_TYPE_CLIENT, GUdevClientClass)) -#define G_UDEV_IS_CLIENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_UDEV_TYPE_CLIENT)) -#define G_UDEV_IS_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_UDEV_TYPE_CLIENT)) -#define G_UDEV_CLIENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_UDEV_TYPE_CLIENT, GUdevClientClass)) - -typedef struct _GUdevClientClass GUdevClientClass; -typedef struct _GUdevClientPrivate GUdevClientPrivate; - -/** - * GUdevClient: - * - * The #GUdevClient struct is opaque and should not be accessed directly. - */ -struct _GUdevClient -{ - GObject parent; - - /*< private >*/ - GUdevClientPrivate *priv; -}; - -/** - * GUdevClientClass: - * @parent_class: Parent class. - * @uevent: Signal class handler for the #GUdevClient::uevent signal. - * - * Class structure for #GUdevClient. - */ -struct _GUdevClientClass -{ - GObjectClass parent_class; - - /* signals */ - void (*uevent) (GUdevClient *client, - const gchar *action, - GUdevDevice *device); - - /*< private >*/ - /* Padding for future expansion */ - void (*reserved1) (void); - void (*reserved2) (void); - void (*reserved3) (void); - void (*reserved4) (void); - void (*reserved5) (void); - void (*reserved6) (void); - void (*reserved7) (void); - void (*reserved8) (void); -}; - -GType g_udev_client_get_type (void) G_GNUC_CONST; -GUdevClient *g_udev_client_new (const gchar* const *subsystems); -GList *g_udev_client_query_by_subsystem (GUdevClient *client, - const gchar *subsystem); -GUdevDevice *g_udev_client_query_by_device_number (GUdevClient *client, - GUdevDeviceType type, - GUdevDeviceNumber number); -GUdevDevice *g_udev_client_query_by_device_file (GUdevClient *client, - const gchar *device_file); -GUdevDevice *g_udev_client_query_by_sysfs_path (GUdevClient *client, - const gchar *sysfs_path); -GUdevDevice *g_udev_client_query_by_subsystem_and_name (GUdevClient *client, - const gchar *subsystem, - const gchar *name); - -G_END_DECLS - -#endif /* __G_UDEV_CLIENT_H__ */ diff --git a/src/udev/src/gudev/gudevdevice.c b/src/udev/src/gudev/gudevdevice.c deleted file mode 100644 index 62a26f99b7..0000000000 --- a/src/udev/src/gudev/gudevdevice.c +++ /dev/null @@ -1,963 +0,0 @@ -/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2008 David Zeuthen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU 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 -#include - -#include "gudevdevice.h" -#include "gudevprivate.h" - -/** - * SECTION:gudevdevice - * @short_description: Get information about a device - * - * The #GUdevDevice class is used to get information about a specific - * device. Note that you cannot instantiate a #GUdevDevice object - * yourself. Instead you must use #GUdevClient to obtain #GUdevDevice - * objects. - * - * To get basic information about a device, use - * g_udev_device_get_subsystem(), g_udev_device_get_devtype(), - * g_udev_device_get_name(), g_udev_device_get_number(), - * g_udev_device_get_sysfs_path(), g_udev_device_get_driver(), - * g_udev_device_get_action(), g_udev_device_get_seqnum(), - * g_udev_device_get_device_type(), g_udev_device_get_device_number(), - * g_udev_device_get_device_file(), - * g_udev_device_get_device_file_symlinks(). - * - * To navigate the device tree, use g_udev_device_get_parent() and - * g_udev_device_get_parent_with_subsystem(). - * - * To access udev properties for the device, use - * g_udev_device_get_property_keys(), - * g_udev_device_has_property(), - * g_udev_device_get_property(), - * g_udev_device_get_property_as_int(), - * g_udev_device_get_property_as_uint64(), - * g_udev_device_get_property_as_double(), - * g_udev_device_get_property_as_boolean() and - * g_udev_device_get_property_as_strv(). - * - * To access sysfs attributes for the device, use - * g_udev_device_get_sysfs_attr(), - * 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 /dev) that points to - * the device file for @device. - * - * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): A %NULL terminated string array of symlinks. This array is owned by @device and should not be freed by the caller. - */ -const gchar * const * -g_udev_device_get_device_file_symlinks (GUdevDevice *device) -{ - struct udev_list_entry *l; - GPtrArray *p; - - g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); - - if (device->priv->device_file_symlinks != NULL) - goto out; - - p = g_ptr_array_new (); - for (l = udev_device_get_devlinks_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l)) - { - g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l))); - } - g_ptr_array_add (p, NULL); - device->priv->device_file_symlinks = (gchar **) g_ptr_array_free (p, FALSE); - - out: - return (const gchar * const *) device->priv->device_file_symlinks; -} - -/* ---------------------------------------------------------------------------------------------------- */ - -/** - * g_udev_device_get_parent: - * @device: A #GUdevDevice. - * - * Gets the immediate parent of @device, if any. - * - * Returns: (transfer full): A #GUdevDevice or %NULL if @device has no parent. Free with g_object_unref(). - */ -GUdevDevice * -g_udev_device_get_parent (GUdevDevice *device) -{ - GUdevDevice *ret; - struct udev_device *udevice; - - g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); - - ret = NULL; - - udevice = udev_device_get_parent (device->priv->udevice); - if (udevice == NULL) - goto out; - - ret = _g_udev_device_new (udevice); - - out: - return ret; -} - -/** - * g_udev_device_get_parent_with_subsystem: - * @device: A #GUdevDevice. - * @subsystem: The subsystem of the parent to get. - * @devtype: (allow-none): The devtype of the parent to get or %NULL. - * - * Walks up the chain of parents of @device and returns the first - * device encountered where @subsystem and @devtype matches, if any. - * - * Returns: (transfer full): A #GUdevDevice or %NULL if @device has no parent with @subsystem and @devtype. Free with g_object_unref(). - */ -GUdevDevice * -g_udev_device_get_parent_with_subsystem (GUdevDevice *device, - const gchar *subsystem, - const gchar *devtype) -{ - GUdevDevice *ret; - struct udev_device *udevice; - - g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); - g_return_val_if_fail (subsystem != NULL, NULL); - - ret = NULL; - - udevice = udev_device_get_parent_with_subsystem_devtype (device->priv->udevice, - subsystem, - devtype); - if (udevice == NULL) - goto out; - - ret = _g_udev_device_new (udevice); - - out: - return ret; -} - -/* ---------------------------------------------------------------------------------------------------- */ - -/** - * g_udev_device_get_property_keys: - * @device: A #GUdevDevice. - * - * Gets all keys for properties on @device. - * - * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): A %NULL terminated string array of property keys. This array is owned by @device and should not be freed by the caller. - */ -const gchar* const * -g_udev_device_get_property_keys (GUdevDevice *device) -{ - struct udev_list_entry *l; - GPtrArray *p; - - g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); - - if (device->priv->property_keys != NULL) - goto out; - - p = g_ptr_array_new (); - for (l = udev_device_get_properties_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l)) - { - g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l))); - } - g_ptr_array_add (p, NULL); - device->priv->property_keys = (gchar **) g_ptr_array_free (p, FALSE); - - out: - return (const gchar * const *) device->priv->property_keys; -} - - -/** - * g_udev_device_has_property: - * @device: A #GUdevDevice. - * @key: Name of property. - * - * Check if a the property with the given key exists. - * - * Returns: %TRUE only if the value for @key exist. - */ -gboolean -g_udev_device_has_property (GUdevDevice *device, - const gchar *key) -{ - g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE); - g_return_val_if_fail (key != NULL, FALSE); - return udev_device_get_property_value (device->priv->udevice, key) != NULL; -} - -/** - * g_udev_device_get_property: - * @device: A #GUdevDevice. - * @key: Name of property. - * - * Look up the value for @key on @device. - * - * Returns: The value for @key or %NULL if @key doesn't exist on @device. Do not free this string, it is owned by @device. - */ -const gchar * -g_udev_device_get_property (GUdevDevice *device, - const gchar *key) -{ - g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); - g_return_val_if_fail (key != NULL, NULL); - return udev_device_get_property_value (device->priv->udevice, key); -} - -/** - * g_udev_device_get_property_as_int: - * @device: A #GUdevDevice. - * @key: Name of property. - * - * Look up the value for @key on @device and convert it to an integer - * using strtol(). - * - * Returns: The value for @key or 0 if @key doesn't exist or - * isn't an integer. - */ -gint -g_udev_device_get_property_as_int (GUdevDevice *device, - const gchar *key) -{ - gint result; - const gchar *s; - - g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0); - g_return_val_if_fail (key != NULL, 0); - - result = 0; - s = g_udev_device_get_property (device, key); - if (s == NULL) - goto out; - - result = strtol (s, NULL, 0); -out: - return result; -} - -/** - * g_udev_device_get_property_as_uint64: - * @device: A #GUdevDevice. - * @key: Name of property. - * - * Look up the value for @key on @device and convert it to an unsigned - * 64-bit integer using g_ascii_strtoull(). - * - * Returns: The value for @key or 0 if @key doesn't exist or isn't a - * #guint64. - */ -guint64 -g_udev_device_get_property_as_uint64 (GUdevDevice *device, - const gchar *key) -{ - guint64 result; - const gchar *s; - - g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0); - g_return_val_if_fail (key != NULL, 0); - - result = 0; - s = g_udev_device_get_property (device, key); - if (s == NULL) - goto out; - - result = g_ascii_strtoull (s, NULL, 0); -out: - return result; -} - -/** - * g_udev_device_get_property_as_double: - * @device: A #GUdevDevice. - * @key: Name of property. - * - * Look up the value for @key on @device and convert it to a double - * precision floating point number using strtod(). - * - * Returns: The value for @key or 0.0 if @key doesn't exist or isn't a - * #gdouble. - */ -gdouble -g_udev_device_get_property_as_double (GUdevDevice *device, - const gchar *key) -{ - gdouble result; - const gchar *s; - - g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0.0); - g_return_val_if_fail (key != NULL, 0.0); - - result = 0.0; - s = g_udev_device_get_property (device, key); - if (s == NULL) - goto out; - - result = strtod (s, NULL); -out: - return result; -} - -/** - * g_udev_device_get_property_as_boolean: - * @device: A #GUdevDevice. - * @key: Name of property. - * - * Look up the value for @key on @device and convert it to an - * boolean. This is done by doing a case-insensitive string comparison - * on the string value against "1" and "true". - * - * Returns: The value for @key or %FALSE if @key doesn't exist or - * isn't a #gboolean. - */ -gboolean -g_udev_device_get_property_as_boolean (GUdevDevice *device, - const gchar *key) -{ - gboolean result; - const gchar *s; - - g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE); - g_return_val_if_fail (key != NULL, FALSE); - - result = FALSE; - s = g_udev_device_get_property (device, key); - if (s == NULL) - goto out; - - if (strcmp (s, "1") == 0 || g_ascii_strcasecmp (s, "true") == 0) - result = TRUE; - out: - return result; -} - -static gchar ** -split_at_whitespace (const gchar *s) -{ - gchar **result; - guint n; - guint m; - - result = g_strsplit_set (s, " \v\t\r\n", 0); - - /* remove empty strings, thanks GLib */ - for (n = 0; result[n] != NULL; n++) - { - if (strlen (result[n]) == 0) - { - g_free (result[n]); - for (m = n; result[m] != NULL; m++) - result[m] = result[m + 1]; - n--; - } - } - - return result; -} - -/** - * g_udev_device_get_property_as_strv: - * @device: A #GUdevDevice. - * @key: Name of property. - * - * Look up the value for @key on @device and return the result of - * splitting it into non-empty tokens split at white space (only space - * (' '), form-feed ('\f'), newline ('\n'), carriage return ('\r'), - * horizontal tab ('\t'), and vertical tab ('\v') are considered; the - * locale is not taken into account). - * - * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): The value of @key on @device split into tokens or %NULL if @key doesn't exist. This array is owned by @device and should not be freed by the caller. - */ -const gchar* const * -g_udev_device_get_property_as_strv (GUdevDevice *device, - const gchar *key) -{ - gchar **result; - const gchar *s; - - g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); - g_return_val_if_fail (key != NULL, NULL); - - if (device->priv->prop_strvs != NULL) - { - result = g_hash_table_lookup (device->priv->prop_strvs, key); - if (result != NULL) - goto out; - } - - result = NULL; - s = g_udev_device_get_property (device, key); - if (s == NULL) - goto out; - - result = split_at_whitespace (s); - if (result == NULL) - goto out; - - if (device->priv->prop_strvs == NULL) - device->priv->prop_strvs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_strfreev); - g_hash_table_insert (device->priv->prop_strvs, g_strdup (key), result); - -out: - return (const gchar* const *) result; -} - -/* ---------------------------------------------------------------------------------------------------- */ - -/** - * g_udev_device_get_sysfs_attr: - * @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 index d4873bad0f..0000000000 --- a/src/udev/src/gudev/gudevdevice.h +++ /dev/null @@ -1,128 +0,0 @@ -/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2008 David Zeuthen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU 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 can be included directly, this file may disappear or change contents." -#endif - -#ifndef __G_UDEV_DEVICE_H__ -#define __G_UDEV_DEVICE_H__ - -#include - -G_BEGIN_DECLS - -#define G_UDEV_TYPE_DEVICE (g_udev_device_get_type ()) -#define G_UDEV_DEVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_UDEV_TYPE_DEVICE, GUdevDevice)) -#define G_UDEV_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_UDEV_TYPE_DEVICE, GUdevDeviceClass)) -#define G_UDEV_IS_DEVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_UDEV_TYPE_DEVICE)) -#define G_UDEV_IS_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_UDEV_TYPE_DEVICE)) -#define G_UDEV_DEVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_UDEV_TYPE_DEVICE, GUdevDeviceClass)) - -typedef struct _GUdevDeviceClass GUdevDeviceClass; -typedef struct _GUdevDevicePrivate GUdevDevicePrivate; - -/** - * GUdevDevice: - * - * The #GUdevDevice struct is opaque and should not be accessed directly. - */ -struct _GUdevDevice -{ - GObject parent; - - /*< private >*/ - GUdevDevicePrivate *priv; -}; - -/** - * GUdevDeviceClass: - * @parent_class: Parent class. - * - * Class structure for #GUdevDevice. - */ -struct _GUdevDeviceClass -{ - GObjectClass parent_class; - - /*< private >*/ - /* Padding for future expansion */ - void (*reserved1) (void); - void (*reserved2) (void); - void (*reserved3) (void); - void (*reserved4) (void); - void (*reserved5) (void); - void (*reserved6) (void); - void (*reserved7) (void); - void (*reserved8) (void); -}; - -GType g_udev_device_get_type (void) G_GNUC_CONST; -gboolean g_udev_device_get_is_initialized (GUdevDevice *device); -guint64 g_udev_device_get_usec_since_initialized (GUdevDevice *device); -const gchar *g_udev_device_get_subsystem (GUdevDevice *device); -const gchar *g_udev_device_get_devtype (GUdevDevice *device); -const gchar *g_udev_device_get_name (GUdevDevice *device); -const gchar *g_udev_device_get_number (GUdevDevice *device); -const gchar *g_udev_device_get_sysfs_path (GUdevDevice *device); -const gchar *g_udev_device_get_driver (GUdevDevice *device); -const gchar *g_udev_device_get_action (GUdevDevice *device); -guint64 g_udev_device_get_seqnum (GUdevDevice *device); -GUdevDeviceType g_udev_device_get_device_type (GUdevDevice *device); -GUdevDeviceNumber g_udev_device_get_device_number (GUdevDevice *device); -const gchar *g_udev_device_get_device_file (GUdevDevice *device); -const gchar* const *g_udev_device_get_device_file_symlinks (GUdevDevice *device); -GUdevDevice *g_udev_device_get_parent (GUdevDevice *device); -GUdevDevice *g_udev_device_get_parent_with_subsystem (GUdevDevice *device, - const gchar *subsystem, - const gchar *devtype); -const gchar* const *g_udev_device_get_property_keys (GUdevDevice *device); -gboolean g_udev_device_has_property (GUdevDevice *device, - const gchar *key); -const gchar *g_udev_device_get_property (GUdevDevice *device, - const gchar *key); -gint g_udev_device_get_property_as_int (GUdevDevice *device, - const gchar *key); -guint64 g_udev_device_get_property_as_uint64 (GUdevDevice *device, - const gchar *key); -gdouble g_udev_device_get_property_as_double (GUdevDevice *device, - const gchar *key); -gboolean g_udev_device_get_property_as_boolean (GUdevDevice *device, - const gchar *key); -const gchar* const *g_udev_device_get_property_as_strv (GUdevDevice *device, - const gchar *key); - -const gchar *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 index db09074625..0000000000 --- a/src/udev/src/gudev/gudevenumerator.c +++ /dev/null @@ -1,431 +0,0 @@ -/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2008-2010 David Zeuthen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU 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 -#include - -#include "gudevclient.h" -#include "gudevenumerator.h" -#include "gudevdevice.h" -#include "gudevmarshal.h" -#include "gudevprivate.h" - -/** - * SECTION:gudevenumerator - * @short_description: Lookup and sort devices - * - * #GUdevEnumerator is used to lookup and sort devices. - * - * Since: 165 - */ - -struct _GUdevEnumeratorPrivate -{ - GUdevClient *client; - struct udev_enumerate *e; -}; - -enum -{ - PROP_0, - PROP_CLIENT, -}; - -G_DEFINE_TYPE (GUdevEnumerator, g_udev_enumerator, G_TYPE_OBJECT) - -/* ---------------------------------------------------------------------------------------------------- */ - -static void -g_udev_enumerator_finalize (GObject *object) -{ - GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object); - - if (enumerator->priv->client != NULL) - { - g_object_unref (enumerator->priv->client); - enumerator->priv->client = NULL; - } - - if (enumerator->priv->e != NULL) - { - udev_enumerate_unref (enumerator->priv->e); - enumerator->priv->e = NULL; - } - - if (G_OBJECT_CLASS (g_udev_enumerator_parent_class)->finalize != NULL) - G_OBJECT_CLASS (g_udev_enumerator_parent_class)->finalize (object); -} - -static void -g_udev_enumerator_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object); - - switch (prop_id) - { - case PROP_CLIENT: - if (enumerator->priv->client != NULL) - g_object_unref (enumerator->priv->client); - enumerator->priv->client = g_value_dup_object (value); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -g_udev_enumerator_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object); - - switch (prop_id) - { - case PROP_CLIENT: - g_value_set_object (value, enumerator->priv->client); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -g_udev_enumerator_constructed (GObject *object) -{ - GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object); - - g_assert (G_UDEV_IS_CLIENT (enumerator->priv->client)); - - enumerator->priv->e = udev_enumerate_new (_g_udev_client_get_udev (enumerator->priv->client)); - - if (G_OBJECT_CLASS (g_udev_enumerator_parent_class)->constructed != NULL) - G_OBJECT_CLASS (g_udev_enumerator_parent_class)->constructed (object); -} - -static void -g_udev_enumerator_class_init (GUdevEnumeratorClass *klass) -{ - GObjectClass *gobject_class = (GObjectClass *) klass; - - gobject_class->finalize = g_udev_enumerator_finalize; - gobject_class->set_property = g_udev_enumerator_set_property; - gobject_class->get_property = g_udev_enumerator_get_property; - gobject_class->constructed = g_udev_enumerator_constructed; - - /** - * GUdevEnumerator:client: - * - * The #GUdevClient to enumerate devices from. - * - * Since: 165 - */ - g_object_class_install_property (gobject_class, - PROP_CLIENT, - g_param_spec_object ("client", - "The client to enumerate devices from", - "The client to enumerate devices from", - G_UDEV_TYPE_CLIENT, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE)); - - g_type_class_add_private (klass, sizeof (GUdevEnumeratorPrivate)); -} - -static void -g_udev_enumerator_init (GUdevEnumerator *enumerator) -{ - enumerator->priv = G_TYPE_INSTANCE_GET_PRIVATE (enumerator, - G_UDEV_TYPE_ENUMERATOR, - GUdevEnumeratorPrivate); -} - -/** - * g_udev_enumerator_new: - * @client: A #GUdevClient to enumerate devices from. - * - * Constructs a #GUdevEnumerator object that can be used to enumerate - * and sort devices. Use the add_match_*() and add_nomatch_*() methods - * and execute the query to get a list of devices with - * g_udev_enumerator_execute(). - * - * Returns: A new #GUdevEnumerator object. Free with g_object_unref(). - * - * Since: 165 - */ -GUdevEnumerator * -g_udev_enumerator_new (GUdevClient *client) -{ - g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); - return G_UDEV_ENUMERATOR (g_object_new (G_UDEV_TYPE_ENUMERATOR, "client", client, NULL)); -} - - -/** - * g_udev_enumerator_add_match_subsystem: - * @enumerator: A #GUdevEnumerator. - * @subsystem: Wildcard for subsystem name e.g. 'scsi' or 'a*'. - * - * All returned devices will match the given @subsystem. - * - * Returns: (transfer none): The passed in @enumerator. - * - * Since: 165 - */ -GUdevEnumerator * -g_udev_enumerator_add_match_subsystem (GUdevEnumerator *enumerator, - const gchar *subsystem) -{ - g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); - g_return_val_if_fail (subsystem != NULL, NULL); - udev_enumerate_add_match_subsystem (enumerator->priv->e, subsystem); - return enumerator; -} - -/** - * g_udev_enumerator_add_nomatch_subsystem: - * @enumerator: A #GUdevEnumerator. - * @subsystem: Wildcard for subsystem name e.g. 'scsi' or 'a*'. - * - * All returned devices will not match the given @subsystem. - * - * Returns: (transfer none): The passed in @enumerator. - * - * Since: 165 - */ -GUdevEnumerator * -g_udev_enumerator_add_nomatch_subsystem (GUdevEnumerator *enumerator, - const gchar *subsystem) -{ - g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); - g_return_val_if_fail (subsystem != NULL, NULL); - udev_enumerate_add_nomatch_subsystem (enumerator->priv->e, subsystem); - return enumerator; -} - -/** - * g_udev_enumerator_add_match_sysfs_attr: - * @enumerator: A #GUdevEnumerator. - * @name: Wildcard filter for sysfs attribute key. - * @value: Wildcard filter for sysfs attribute value. - * - * All returned devices will have a sysfs attribute matching the given @name and @value. - * - * Returns: (transfer none): The passed in @enumerator. - * - * Since: 165 - */ -GUdevEnumerator * -g_udev_enumerator_add_match_sysfs_attr (GUdevEnumerator *enumerator, - const gchar *name, - const gchar *value) -{ - g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); - g_return_val_if_fail (name != NULL, NULL); - g_return_val_if_fail (value != NULL, NULL); - udev_enumerate_add_match_sysattr (enumerator->priv->e, name, value); - return enumerator; -} - -/** - * g_udev_enumerator_add_nomatch_sysfs_attr: - * @enumerator: A #GUdevEnumerator. - * @name: Wildcard filter for sysfs attribute key. - * @value: Wildcard filter for sysfs attribute value. - * - * All returned devices will not have a sysfs attribute matching the given @name and @value. - * - * Returns: (transfer none): The passed in @enumerator. - * - * Since: 165 - */ -GUdevEnumerator * -g_udev_enumerator_add_nomatch_sysfs_attr (GUdevEnumerator *enumerator, - const gchar *name, - const gchar *value) -{ - g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); - g_return_val_if_fail (name != NULL, NULL); - g_return_val_if_fail (value != NULL, NULL); - udev_enumerate_add_nomatch_sysattr (enumerator->priv->e, name, value); - return enumerator; -} - -/** - * g_udev_enumerator_add_match_property: - * @enumerator: A #GUdevEnumerator. - * @name: Wildcard filter for property name. - * @value: Wildcard filter for property value. - * - * All returned devices will have a property matching the given @name and @value. - * - * Returns: (transfer none): The passed in @enumerator. - * - * Since: 165 - */ -GUdevEnumerator * -g_udev_enumerator_add_match_property (GUdevEnumerator *enumerator, - const gchar *name, - const gchar *value) -{ - g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); - g_return_val_if_fail (name != NULL, NULL); - g_return_val_if_fail (value != NULL, NULL); - udev_enumerate_add_match_property (enumerator->priv->e, name, value); - return enumerator; -} - -/** - * g_udev_enumerator_add_match_name: - * @enumerator: A #GUdevEnumerator. - * @name: Wildcard filter for kernel name e.g. "sda*". - * - * All returned devices will match the given @name. - * - * Returns: (transfer none): The passed in @enumerator. - * - * Since: 165 - */ -GUdevEnumerator * -g_udev_enumerator_add_match_name (GUdevEnumerator *enumerator, - const gchar *name) -{ - g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); - g_return_val_if_fail (name != NULL, NULL); - udev_enumerate_add_match_sysname (enumerator->priv->e, name); - return enumerator; -} - -/** - * g_udev_enumerator_add_sysfs_path: - * @enumerator: A #GUdevEnumerator. - * @sysfs_path: A sysfs path, e.g. "/sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda" - * - * Add a device to the list of devices, to retrieve it back sorted in dependency order. - * - * Returns: (transfer none): The passed in @enumerator. - * - * Since: 165 - */ -GUdevEnumerator * -g_udev_enumerator_add_sysfs_path (GUdevEnumerator *enumerator, - const gchar *sysfs_path) -{ - g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); - g_return_val_if_fail (sysfs_path != NULL, NULL); - udev_enumerate_add_syspath (enumerator->priv->e, sysfs_path); - return enumerator; -} - -/** - * g_udev_enumerator_add_match_tag: - * @enumerator: A #GUdevEnumerator. - * @tag: A udev tag e.g. "udev-acl". - * - * All returned devices will match the given @tag. - * - * Returns: (transfer none): The passed in @enumerator. - * - * Since: 165 - */ -GUdevEnumerator * -g_udev_enumerator_add_match_tag (GUdevEnumerator *enumerator, - const gchar *tag) -{ - g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); - g_return_val_if_fail (tag != NULL, NULL); - udev_enumerate_add_match_tag (enumerator->priv->e, tag); - return enumerator; -} - -/** - * g_udev_enumerator_add_match_is_initialized: - * @enumerator: A #GUdevEnumerator. - * - * All returned devices will be initialized. - * - * Returns: (transfer none): The passed in @enumerator. - * - * Since: 165 - */ -GUdevEnumerator * -g_udev_enumerator_add_match_is_initialized (GUdevEnumerator *enumerator) -{ - g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); - udev_enumerate_add_match_is_initialized (enumerator->priv->e); - return enumerator; -} - -/** - * g_udev_enumerator_execute: - * @enumerator: A #GUdevEnumerator. - * - * Executes the query in @enumerator. - * - * Returns: (element-type GUdevDevice) (transfer full): A list of #GUdevDevice objects. The caller should free the result by using g_object_unref() on each element in the list and then g_list_free() on the list. - * - * Since: 165 - */ -GList * -g_udev_enumerator_execute (GUdevEnumerator *enumerator) -{ - GList *ret; - struct udev_list_entry *l, *devices; - - g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); - - ret = NULL; - - /* retrieve the list */ - udev_enumerate_scan_devices (enumerator->priv->e); - - devices = udev_enumerate_get_list_entry (enumerator->priv->e); - for (l = devices; l != NULL; l = udev_list_entry_get_next (l)) - { - struct udev_device *udevice; - GUdevDevice *device; - - udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerator->priv->e), - udev_list_entry_get_name (l)); - if (udevice == NULL) - continue; - - device = _g_udev_device_new (udevice); - udev_device_unref (udevice); - ret = g_list_prepend (ret, device); - } - - ret = g_list_reverse (ret); - - return ret; -} diff --git a/src/udev/src/gudev/gudevenumerator.h b/src/udev/src/gudev/gudevenumerator.h deleted file mode 100644 index 3fddccf573..0000000000 --- a/src/udev/src/gudev/gudevenumerator.h +++ /dev/null @@ -1,107 +0,0 @@ -/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2008-2010 David Zeuthen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU 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 can be included directly, this file may disappear or change contents." -#endif - -#ifndef __G_UDEV_ENUMERATOR_H__ -#define __G_UDEV_ENUMERATOR_H__ - -#include - -G_BEGIN_DECLS - -#define G_UDEV_TYPE_ENUMERATOR (g_udev_enumerator_get_type ()) -#define G_UDEV_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_UDEV_TYPE_ENUMERATOR, GUdevEnumerator)) -#define G_UDEV_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_UDEV_TYPE_ENUMERATOR, GUdevEnumeratorClass)) -#define G_UDEV_IS_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_UDEV_TYPE_ENUMERATOR)) -#define G_UDEV_IS_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_UDEV_TYPE_ENUMERATOR)) -#define G_UDEV_ENUMERATOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_UDEV_TYPE_ENUMERATOR, GUdevEnumeratorClass)) - -typedef struct _GUdevEnumeratorClass GUdevEnumeratorClass; -typedef struct _GUdevEnumeratorPrivate GUdevEnumeratorPrivate; - -/** - * GUdevEnumerator: - * - * The #GUdevEnumerator struct is opaque and should not be accessed directly. - * - * Since: 165 - */ -struct _GUdevEnumerator -{ - GObject parent; - - /*< private >*/ - GUdevEnumeratorPrivate *priv; -}; - -/** - * GUdevEnumeratorClass: - * @parent_class: Parent class. - * - * Class structure for #GUdevEnumerator. - * - * Since: 165 - */ -struct _GUdevEnumeratorClass -{ - GObjectClass parent_class; - - /*< private >*/ - /* Padding for future expansion */ - void (*reserved1) (void); - void (*reserved2) (void); - void (*reserved3) (void); - void (*reserved4) (void); - void (*reserved5) (void); - void (*reserved6) (void); - void (*reserved7) (void); - void (*reserved8) (void); -}; - -GType g_udev_enumerator_get_type (void) G_GNUC_CONST; -GUdevEnumerator *g_udev_enumerator_new (GUdevClient *client); -GUdevEnumerator *g_udev_enumerator_add_match_subsystem (GUdevEnumerator *enumerator, - const gchar *subsystem); -GUdevEnumerator *g_udev_enumerator_add_nomatch_subsystem (GUdevEnumerator *enumerator, - const gchar *subsystem); -GUdevEnumerator *g_udev_enumerator_add_match_sysfs_attr (GUdevEnumerator *enumerator, - const gchar *name, - const gchar *value); -GUdevEnumerator *g_udev_enumerator_add_nomatch_sysfs_attr (GUdevEnumerator *enumerator, - const gchar *name, - const gchar *value); -GUdevEnumerator *g_udev_enumerator_add_match_property (GUdevEnumerator *enumerator, - const gchar *name, - const gchar *value); -GUdevEnumerator *g_udev_enumerator_add_match_name (GUdevEnumerator *enumerator, - const gchar *name); -GUdevEnumerator *g_udev_enumerator_add_match_tag (GUdevEnumerator *enumerator, - const gchar *tag); -GUdevEnumerator *g_udev_enumerator_add_match_is_initialized (GUdevEnumerator *enumerator); -GUdevEnumerator *g_udev_enumerator_add_sysfs_path (GUdevEnumerator *enumerator, - const gchar *sysfs_path); -GList *g_udev_enumerator_execute (GUdevEnumerator *enumerator); - -G_END_DECLS - -#endif /* __G_UDEV_ENUMERATOR_H__ */ diff --git a/src/udev/src/gudev/gudevenums.h b/src/udev/src/gudev/gudevenums.h deleted file mode 100644 index c3a0aa8747..0000000000 --- a/src/udev/src/gudev/gudevenums.h +++ /dev/null @@ -1,49 +0,0 @@ -/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2008 David Zeuthen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU 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 can be included directly, this file may disappear or change contents." -#endif - -#ifndef __G_UDEV_ENUMS_H__ -#define __G_UDEV_ENUMS_H__ - -#include - -G_BEGIN_DECLS - -/** - * GUdevDeviceType: - * @G_UDEV_DEVICE_TYPE_NONE: Device does not have a device file. - * @G_UDEV_DEVICE_TYPE_BLOCK: Device is a block device. - * @G_UDEV_DEVICE_TYPE_CHAR: Device is a character device. - * - * Enumeration used to specify a the type of a device. - */ -typedef enum -{ - G_UDEV_DEVICE_TYPE_NONE = 0, - G_UDEV_DEVICE_TYPE_BLOCK = 'b', - G_UDEV_DEVICE_TYPE_CHAR = 'c', -} GUdevDeviceType; - -G_END_DECLS - -#endif /* __G_UDEV_ENUMS_H__ */ diff --git a/src/udev/src/gudev/gudevenumtypes.c.template b/src/udev/src/gudev/gudevenumtypes.c.template deleted file mode 100644 index fc30b39e2e..0000000000 --- a/src/udev/src/gudev/gudevenumtypes.c.template +++ /dev/null @@ -1,39 +0,0 @@ -/*** BEGIN file-header ***/ -#include - -/*** END file-header ***/ - -/*** BEGIN file-production ***/ -/* enumerations from "@filename@" */ -/*** END file-production ***/ - -/*** BEGIN value-header ***/ -GType -@enum_name@_get_type (void) -{ - static volatile gsize g_define_type_id__volatile = 0; - - if (g_once_init_enter (&g_define_type_id__volatile)) - { - static const G@Type@Value values[] = { -/*** END value-header ***/ - -/*** BEGIN value-production ***/ - { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, -/*** END value-production ***/ - -/*** BEGIN value-tail ***/ - { 0, NULL, NULL } - }; - GType g_define_type_id = - g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); - g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); - } - - return g_define_type_id__volatile; -} - -/*** END value-tail ***/ - -/*** BEGIN file-tail ***/ -/*** END file-tail ***/ diff --git a/src/udev/src/gudev/gudevenumtypes.h.template b/src/udev/src/gudev/gudevenumtypes.h.template deleted file mode 100644 index d0ab3393e6..0000000000 --- a/src/udev/src/gudev/gudevenumtypes.h.template +++ /dev/null @@ -1,24 +0,0 @@ -/*** BEGIN file-header ***/ -#ifndef __GUDEV_ENUM_TYPES_H__ -#define __GUDEV_ENUM_TYPES_H__ - -#include - -G_BEGIN_DECLS -/*** END file-header ***/ - -/*** BEGIN file-production ***/ - -/* enumerations from "@filename@" */ -/*** END file-production ***/ - -/*** BEGIN value-header ***/ -GType @enum_name@_get_type (void) G_GNUC_CONST; -#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ()) -/*** END value-header ***/ - -/*** BEGIN file-tail ***/ -G_END_DECLS - -#endif /* __GUDEV_ENUM_TYPES_H__ */ -/*** END file-tail ***/ diff --git a/src/udev/src/gudev/gudevmarshal.list b/src/udev/src/gudev/gudevmarshal.list deleted file mode 100644 index 7e665999e8..0000000000 --- a/src/udev/src/gudev/gudevmarshal.list +++ /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 index 8866f52b88..0000000000 --- a/src/udev/src/gudev/gudevprivate.h +++ /dev/null @@ -1,41 +0,0 @@ -/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2008 David Zeuthen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU 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 can be included directly, this file may disappear or change contents." -#endif - -#ifndef __G_UDEV_PRIVATE_H__ -#define __G_UDEV_PRIVATE_H__ - -#include - -#include - -G_BEGIN_DECLS - -GUdevDevice * -_g_udev_device_new (struct udev_device *udevice); - -struct udev *_g_udev_client_get_udev (GUdevClient *client); - -G_END_DECLS - -#endif /* __G_UDEV_PRIVATE_H__ */ diff --git a/src/udev/src/gudev/gudevtypes.h b/src/udev/src/gudev/gudevtypes.h deleted file mode 100644 index 888482783d..0000000000 --- a/src/udev/src/gudev/gudevtypes.h +++ /dev/null @@ -1,51 +0,0 @@ -/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2008 David Zeuthen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU 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 can be included directly, this file may disappear or change contents." -#endif - -#ifndef __G_UDEV_TYPES_H__ -#define __G_UDEV_TYPES_H__ - -#include -#include - -G_BEGIN_DECLS - -typedef struct _GUdevClient GUdevClient; -typedef struct _GUdevDevice GUdevDevice; -typedef struct _GUdevEnumerator GUdevEnumerator; - -/** - * GUdevDeviceNumber: - * - * Corresponds to the standard #dev_t type as defined by POSIX (Until - * bug 584517 is resolved this work-around is needed). - */ -#ifdef _GUDEV_WORK_AROUND_DEV_T_BUG -typedef guint64 GUdevDeviceNumber; /* __UQUAD_TYPE */ -#else -typedef dev_t GUdevDeviceNumber; -#endif - -G_END_DECLS - -#endif /* __G_UDEV_TYPES_H__ */ diff --git a/src/udev/src/gudev/seed-example-enum.js b/src/udev/src/gudev/seed-example-enum.js deleted file mode 100755 index 66206ad806..0000000000 --- a/src/udev/src/gudev/seed-example-enum.js +++ /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 index e2ac324d23..0000000000 --- a/src/udev/src/gudev/seed-example.js +++ /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 index 4567584f4e..0000000000 --- a/src/udev/src/keymap/.gitignore +++ /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 index 03d56e8aa4..0000000000 --- a/src/udev/src/keymap/95-keyboard-force-release.rules +++ /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 index bbf311a17a..0000000000 --- a/src/udev/src/keymap/95-keymap.rules +++ /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 index 52d50ed2de..0000000000 --- a/src/udev/src/keymap/README.keymap.txt +++ /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 . diff --git a/src/udev/src/keymap/check-keymaps.sh b/src/udev/src/keymap/check-keymaps.sh deleted file mode 100755 index 405168c667..0000000000 --- a/src/udev/src/keymap/check-keymaps.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash - -# check that all key names in keymaps/* are known in -# 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 index 9ce27429b2..0000000000 --- a/src/udev/src/keymap/findkeyboards +++ /dev/null @@ -1,68 +0,0 @@ -#!/bin/sh -e -# Find "real" keyboard devices and print their device path. -# Author: Martin Pitt -# -# 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 index 3a7654d735..0000000000 --- a/src/udev/src/keymap/force-release-maps/common-volume-keys +++ /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 index 18e9bdee66..0000000000 --- a/src/udev/src/keymap/force-release-maps/dell-touchpad +++ /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 index 6621370095..0000000000 --- a/src/udev/src/keymap/force-release-maps/hp-other +++ /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 index 65707effb7..0000000000 --- a/src/udev/src/keymap/force-release-maps/samsung-90x3a +++ /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 index c51123a0b6..0000000000 --- a/src/udev/src/keymap/force-release-maps/samsung-other +++ /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 index dd040cebc3..0000000000 --- a/src/udev/src/keymap/keyboard-force-release.sh.in +++ /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 index 92ec67b3a6..0000000000 --- a/src/udev/src/keymap/keymap.c +++ /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 - * Adapted for udev-extras by Martin Pitt - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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 []\n" - " keymap scancode keyname [...]\n" - " keymap -i \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 index 4e7c297dea..0000000000 --- a/src/udev/src/keymap/keymaps/acer +++ /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 index 1496d63a52..0000000000 --- a/src/udev/src/keymap/keymaps/acer-aspire_5720 +++ /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 index 633c4e854c..0000000000 --- a/src/udev/src/keymap/keymaps/acer-aspire_5920g +++ /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 index 699c954b4e..0000000000 --- a/src/udev/src/keymap/keymaps/acer-aspire_6920 +++ /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 index fb27bfb4f5..0000000000 --- a/src/udev/src/keymap/keymaps/acer-aspire_8930 +++ /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 index bfef4cf868..0000000000 --- a/src/udev/src/keymap/keymaps/acer-travelmate_c300 +++ /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 index 2a5995f982..0000000000 --- a/src/udev/src/keymap/keymaps/asus +++ /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 index 5fbc573aa4..0000000000 --- a/src/udev/src/keymap/keymaps/compaq-e_evo +++ /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 index 4f907b3eef..0000000000 --- a/src/udev/src/keymap/keymaps/dell +++ /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 index 39872f559d..0000000000 --- a/src/udev/src/keymap/keymaps/dell-latitude-xt2 +++ /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 index 4823a832f5..0000000000 --- a/src/udev/src/keymap/keymaps/everex-xt5000 +++ /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 index 9b8b36a170..0000000000 --- a/src/udev/src/keymap/keymaps/fujitsu-amilo_li_2732 +++ /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 index f7b0c52444..0000000000 --- a/src/udev/src/keymap/keymaps/fujitsu-amilo_pa_2548 +++ /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 index d2e38cbb23..0000000000 --- a/src/udev/src/keymap/keymaps/fujitsu-amilo_pro_edition_v3505 +++ /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 index 43e3199d59..0000000000 --- a/src/udev/src/keymap/keymaps/fujitsu-amilo_pro_v3205 +++ /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 index 1419bd9b5e..0000000000 --- a/src/udev/src/keymap/keymaps/fujitsu-amilo_si_1520 +++ /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 index d3d056b366..0000000000 --- a/src/udev/src/keymap/keymaps/fujitsu-esprimo_mobile_v5 +++ /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 index 52c70c50cb..0000000000 --- a/src/udev/src/keymap/keymaps/fujitsu-esprimo_mobile_v6 +++ /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 index d0a3656dd8..0000000000 --- a/src/udev/src/keymap/keymaps/genius-slimstar-320 +++ /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 index 4461fa2ce5..0000000000 --- a/src/udev/src/keymap/keymaps/hewlett-packard +++ /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 index 41ad2e9b5a..0000000000 --- a/src/udev/src/keymap/keymaps/hewlett-packard-2510p_2530p +++ /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 index 42007c5483..0000000000 --- a/src/udev/src/keymap/keymaps/hewlett-packard-compaq_elitebook +++ /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 index 3d3cefc8e6..0000000000 --- a/src/udev/src/keymap/keymaps/hewlett-packard-pavilion +++ /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 index 1df39dcbd2..0000000000 --- a/src/udev/src/keymap/keymaps/hewlett-packard-presario-2100 +++ /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 index d19005ab90..0000000000 --- a/src/udev/src/keymap/keymaps/hewlett-packard-tablet +++ /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 index 36a690fcf6..0000000000 --- a/src/udev/src/keymap/keymaps/hewlett-packard-tx2 +++ /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 index 027e50bf88..0000000000 --- a/src/udev/src/keymap/keymaps/ibm-thinkpad-usb-keyboard-trackpoint +++ /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 index 4a8b4ba5a7..0000000000 --- a/src/udev/src/keymap/keymaps/inventec-symphony_6.0_7.0 +++ /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 index 5bd165654a..0000000000 --- a/src/udev/src/keymap/keymaps/lenovo-3000 +++ /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 index fc339839f2..0000000000 --- a/src/udev/src/keymap/keymaps/lenovo-ideapad +++ /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 index 47e8846a68..0000000000 --- a/src/udev/src/keymap/keymaps/lenovo-thinkpad-usb-keyboard-trackpoint +++ /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 index 31ea3b2c70..0000000000 --- a/src/udev/src/keymap/keymaps/lenovo-thinkpad_x200_tablet +++ /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 index 6fd16b5662..0000000000 --- a/src/udev/src/keymap/keymaps/lenovo-thinkpad_x6_tablet +++ /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 index ba08cba3fe..0000000000 --- a/src/udev/src/keymap/keymaps/lg-x110 +++ /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 index caa5d5d310..0000000000 --- a/src/udev/src/keymap/keymaps/logitech-wave +++ /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 index a10dad5e4d..0000000000 --- a/src/udev/src/keymap/keymaps/logitech-wave-cordless +++ /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 index e7aa02206c..0000000000 --- a/src/udev/src/keymap/keymaps/logitech-wave-pro-cordless +++ /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 index c0e4f77af4..0000000000 --- a/src/udev/src/keymap/keymaps/maxdata-pro_7000 +++ /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 index 5a76c76799..0000000000 --- a/src/udev/src/keymap/keymaps/medion-fid2060 +++ /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 index c3b5dfa60b..0000000000 --- a/src/udev/src/keymap/keymaps/medionnb-a555 +++ /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 index 4a438698ed..0000000000 --- a/src/udev/src/keymap/keymaps/micro-star +++ /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 index 773e0b3e82..0000000000 --- a/src/udev/src/keymap/keymaps/module-asus-w3j +++ /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 index a92dfa2506..0000000000 --- a/src/udev/src/keymap/keymaps/module-ibm +++ /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 index 8e38883091..0000000000 --- a/src/udev/src/keymap/keymaps/module-lenovo +++ /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 index 7c000131d1..0000000000 --- a/src/udev/src/keymap/keymaps/module-sony +++ /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 index 596a34258a..0000000000 --- a/src/udev/src/keymap/keymaps/module-sony-old +++ /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 index c8ba001516..0000000000 --- a/src/udev/src/keymap/keymaps/module-sony-vgn +++ /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 index 34434a121d..0000000000 --- a/src/udev/src/keymap/keymaps/olpc-xo +++ /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 index ee864ade4d..0000000000 --- a/src/udev/src/keymap/keymaps/onkyo +++ /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 index b7f4851abe..0000000000 --- a/src/udev/src/keymap/keymaps/oqo-model2 +++ /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 index 8b65eb6d03..0000000000 --- a/src/udev/src/keymap/keymaps/samsung-90x3a +++ /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 index 3ac0c2f10c..0000000000 --- a/src/udev/src/keymap/keymaps/samsung-other +++ /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 index ea2141ef84..0000000000 --- a/src/udev/src/keymap/keymaps/samsung-sq1us +++ /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 index 9d954ee415..0000000000 --- a/src/udev/src/keymap/keymaps/samsung-sx20s +++ /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 index 22007be71b..0000000000 --- a/src/udev/src/keymap/keymaps/toshiba-satellite_a100 +++ /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 index 1429409351..0000000000 --- a/src/udev/src/keymap/keymaps/toshiba-satellite_a110 +++ /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 index ae8e34941b..0000000000 --- a/src/udev/src/keymap/keymaps/toshiba-satellite_m30x +++ /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 index cf72fda47b..0000000000 --- a/src/udev/src/keymap/keymaps/zepto-znote +++ /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 index 13fdb8eb57..0000000000 --- a/src/udev/src/libudev-device-private.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008-2010 Kay Sievers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "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 index 10f28b8cd5..0000000000 --- a/src/udev/src/libudev-device.c +++ /dev/null @@ -1,1744 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008-2010 Kay Sievers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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}/: 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 index 034d96feba..0000000000 --- a/src/udev/src/libudev-enumerate.c +++ /dev/null @@ -1,947 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008-2010 Kay Sievers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 index 4bdef35ae8..0000000000 --- a/src/udev/src/libudev-list.c +++ /dev/null @@ -1,344 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008 Kay Sievers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include - -#include "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 index 77dc55572f..0000000000 --- a/src/udev/src/libudev-monitor.c +++ /dev/null @@ -1,874 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008-2010 Kay Sievers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 = 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 index 5f5c64a63d..0000000000 --- a/src/udev/src/libudev-private.h +++ /dev/null @@ -1,213 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008-2010 Kay Sievers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - */ - -#ifndef _LIBUDEV_PRIVATE_H_ -#define _LIBUDEV_PRIVATE_H_ - -#include -#include -#include -#include -#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 index 71771950aa..0000000000 --- a/src/udev/src/libudev-queue-private.c +++ /dev/null @@ -1,412 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008 Kay Sievers - * Copyright (C) 2009 Alan Jenkins - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "libudev.h" -#include "libudev-private.h" - -static int rebuild_queue_file(struct udev_queue_export *udev_queue_export); - -struct udev_queue_export { - struct udev *udev; - int queued_count; /* number of unfinished events exported in queue file */ - FILE *queue_file; - unsigned long long int seqnum_max; /* earliest sequence number in queue file */ - unsigned long long int seqnum_min; /* latest sequence number in queue file */ - int waste_bytes; /* queue file bytes wasted on finished events */ -}; - -struct udev_queue_export *udev_queue_export_new(struct udev *udev) -{ - struct udev_queue_export *udev_queue_export; - unsigned long long int initial_seqnum; - - if (udev == NULL) - return NULL; - - udev_queue_export = 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 index 0e82cb6ae8..0000000000 --- a/src/udev/src/libudev-queue.c +++ /dev/null @@ -1,474 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008 Kay Sievers - * Copyright (C) 2009 Alan Jenkins - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "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 index 0f2a617b18..0000000000 --- a/src/udev/src/libudev-selinux-private.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008 Kay Sievers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include - -#include "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 index 08f0ba2228..0000000000 --- a/src/udev/src/libudev-util-private.c +++ /dev/null @@ -1,242 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2003-2009 Kay Sievers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 "[/]" 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 index 7e345f0fb6..0000000000 --- a/src/udev/src/libudev-util.c +++ /dev/null @@ -1,570 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008-2011 Kay Sievers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 index d954daef68..0000000000 --- a/src/udev/src/libudev.c +++ /dev/null @@ -1,457 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008-2010 Kay Sievers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "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 = 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 index 10e098d4f7..0000000000 --- a/src/udev/src/libudev.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008-2011 Kay Sievers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - */ - -#ifndef _LIBUDEV_H_ -#define _LIBUDEV_H_ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * udev - library context - * - * reads the udev config and system environment - * allows custom logging - */ -struct udev; -struct udev *udev_ref(struct udev *udev); -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 index c9a47fc9b8..0000000000 --- a/src/udev/src/libudev.pc.in +++ /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 index c0e0839785..0000000000 --- a/src/udev/src/mtd_probe/75-probe_mtd.rules +++ /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 index 1aa08d3851..0000000000 --- a/src/udev/src/mtd_probe/mtd_probe.c +++ /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 -#include -#include -#include -#include -#include -#include -#include - -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 index 2a37ede578..0000000000 --- a/src/udev/src/mtd_probe/mtd_probe.h +++ /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 - -/* 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 index b3cdefc633..0000000000 --- a/src/udev/src/mtd_probe/probe_smartmedia.c +++ /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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "mtd_probe.h" - -static const uint8_t cis_signature[] = { - 0x01, 0x03, 0xD9, 0x01, 0xFF, 0x18, 0x02, 0xDF, 0x01, 0x20 -}; - - -void probe_smart_media(int mtd_fd, mtd_info_t* info) -{ - 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 index e6da0101d6..0000000000 --- a/src/udev/src/rule_generator/75-cd-aliases-generator.rules +++ /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 index 4f80573478..0000000000 --- a/src/udev/src/rule_generator/75-persistent-net-generator.rules +++ /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 index 2eec1b6abf..0000000000 --- a/src/udev/src/rule_generator/rule_generator.functions +++ /dev/null @@ -1,113 +0,0 @@ -# functions used by the udev rule generator - -# Copyright (C) 2006 Marco d'Itri - -# 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 . - -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 index 645b9cd521..0000000000 --- a/src/udev/src/rule_generator/write_cd_rules +++ /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 -# -# 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 . - -# debug, if UDEV_LOG= -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 index bcea4b09dc..0000000000 --- a/src/udev/src/rule_generator/write_net_rules +++ /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= 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 -# Copyright (C) 2007 Kay Sievers -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# debug, if UDEV_LOG= -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 index 6aebddd809..0000000000 --- a/src/udev/src/scsi_id/.gitignore +++ /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 index 9cfe73991c..0000000000 --- a/src/udev/src/scsi_id/README +++ /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 or -. diff --git a/src/udev/src/scsi_id/scsi.h b/src/udev/src/scsi_id/scsi.h deleted file mode 100644 index c423cac574..0000000000 --- a/src/udev/src/scsi_id/scsi.h +++ /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 - -struct scsi_ioctl_command { - unsigned int inlen; /* excluding scsi command length */ - unsigned int outlen; - unsigned char data[1]; - /* on input, scsi command starts here then opt. data */ -}; - -/* - * Default 5 second timeout - */ -#define DEF_TIMEOUT 5000 - -#define SENSE_BUFF_LEN 32 - -/* - * The request buffer size passed to the SCSI INQUIRY commands, use 254, - * as this is a nice value for some devices, especially some of the usb - * mass storage devices. - */ -#define SCSI_INQ_BUFF_LEN 254 - -/* - * SCSI INQUIRY vendor and model (really product) lengths. - */ -#define VENDOR_LENGTH 8 -#define MODEL_LENGTH 16 - -#define INQUIRY_CMD 0x12 -#define INQUIRY_CMDLEN 6 - -/* - * INQUIRY VPD page 0x83 identifier descriptor related values. Reference the - * SCSI Primary Commands specification for details. - */ - -/* - * id type values of id descriptors. These are assumed to fit in 4 bits. - */ -#define SCSI_ID_VENDOR_SPECIFIC 0 -#define SCSI_ID_T10_VENDOR 1 -#define SCSI_ID_EUI_64 2 -#define SCSI_ID_NAA 3 -#define SCSI_ID_RELPORT 4 -#define SCSI_ID_TGTGROUP 5 -#define SCSI_ID_LUNGROUP 6 -#define SCSI_ID_MD5 7 -#define SCSI_ID_NAME 8 - -/* - * Supported NAA values. These fit in 4 bits, so the "don't care" value - * cannot conflict with real values. - */ -#define SCSI_ID_NAA_DONT_CARE 0xff -#define SCSI_ID_NAA_IEEE_REG 5 -#define SCSI_ID_NAA_IEEE_REG_EXTENDED 6 - -/* - * Supported Code Set values. - */ -#define SCSI_ID_BINARY 1 -#define SCSI_ID_ASCII 2 - -struct scsi_id_search_values { - u_char id_type; - u_char naa_type; - u_char code_set; -}; - -/* - * Following are the "true" SCSI status codes. Linux has traditionally - * used a 1 bit right and masked version of these. So now CHECK_CONDITION - * and friends (in ) are deprecated. - */ -#define SCSI_CHECK_CONDITION 0x2 -#define SCSI_CONDITION_MET 0x4 -#define SCSI_BUSY 0x8 -#define SCSI_IMMEDIATE 0x10 -#define SCSI_IMMEDIATE_CONDITION_MET 0x14 -#define SCSI_RESERVATION_CONFLICT 0x18 -#define SCSI_COMMAND_TERMINATED 0x22 -#define SCSI_TASK_SET_FULL 0x28 -#define SCSI_ACA_ACTIVE 0x30 -#define SCSI_TASK_ABORTED 0x40 diff --git a/src/udev/src/scsi_id/scsi_id.8 b/src/udev/src/scsi_id/scsi_id.8 deleted file mode 100644 index 0d4dba9149..0000000000 --- a/src/udev/src/scsi_id/scsi_id.8 +++ /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= 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= -vendor="ATA",options=-p 0x80 -.RE -.fi -.LP -.SH "SEE ALSO" -.BR udev (7) -.SH AUTHORS -Developed by Patrick Mansfield 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 index 9bb0d7f538..0000000000 --- a/src/udev/src/scsi_id/scsi_id.c +++ /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 . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 \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 index 828a98305f..0000000000 --- a/src/udev/src/scsi_id/scsi_id.h +++ /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 . - */ - -#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 index f1d63f40cc..0000000000 --- a/src/udev/src/scsi_id/scsi_serial.c +++ /dev/null @@ -1,990 +0,0 @@ -/* - * Copyright (C) IBM Corp. 2003 - * - * Author: Patrick Mansfield - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "libudev.h" -#include "libudev-private.h" -#include "scsi.h" -#include "scsi_id.h" - -/* - * A priority based list of id, naa, and binary/ascii for the identifier - * descriptor in VPD page 0x83. - * - * Brute force search for a match starting with the first value in the - * following id_search_list. This is not a performance issue, since there - * is normally one or some small number of descriptors. - */ -static const struct scsi_id_search_values id_search_list[] = { - { SCSI_ID_TGTGROUP, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, - { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_BINARY }, - { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_ASCII }, - { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_BINARY }, - { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_ASCII }, - /* - * Devices already exist using NAA values that are now marked - * reserved. These should not conflict with other values, or it is - * a bug in the device. As long as we find the IEEE extended one - * first, we really don't care what other ones are used. Using - * don't care here means that a device that returns multiple - * non-IEEE descriptors in a random order will get different - * names. - */ - { SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, - { SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, - { SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, - { SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, - { SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, - { SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, - { SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, - { SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, -}; - -static const char hex_str[]="0123456789abcdef"; - -/* - * Values returned in the result/status, only the ones used by the code - * are used here. - */ - -#define DID_NO_CONNECT 0x01 /* Unable to connect before timeout */ -#define DID_BUS_BUSY 0x02 /* Bus remain busy until timeout */ -#define DID_TIME_OUT 0x03 /* Timed out for some other reason */ -#define DRIVER_TIMEOUT 0x06 -#define DRIVER_SENSE 0x08 /* Sense_buffer has been set */ - -/* The following "category" function returns one of the following */ -#define SG_ERR_CAT_CLEAN 0 /* No errors or other information */ -#define SG_ERR_CAT_MEDIA_CHANGED 1 /* interpreted from sense buffer */ -#define SG_ERR_CAT_RESET 2 /* interpreted from sense buffer */ -#define SG_ERR_CAT_TIMEOUT 3 -#define SG_ERR_CAT_RECOVERED 4 /* Successful command after recovered err */ -#define SG_ERR_CAT_NOTSUPPORTED 5 /* Illegal / unsupported command */ -#define SG_ERR_CAT_SENSE 98 /* Something else in the sense buffer */ -#define SG_ERR_CAT_OTHER 99 /* Some other error/warning */ - -static int do_scsi_page80_inquiry(struct udev *udev, - struct scsi_id_device *dev_scsi, int fd, - char *serial, char *serial_short, int max_len); - -static int sg_err_category_new(struct udev *udev, - int scsi_status, int msg_status, int - host_status, int driver_status, const - unsigned char *sense_buffer, int sb_len) -{ - scsi_status &= 0x7e; - - /* - * XXX change to return only two values - failed or OK. - */ - - if (!scsi_status && !host_status && !driver_status) - return SG_ERR_CAT_CLEAN; - - if ((scsi_status == SCSI_CHECK_CONDITION) || - (scsi_status == SCSI_COMMAND_TERMINATED) || - ((driver_status & 0xf) == DRIVER_SENSE)) { - if (sense_buffer && (sb_len > 2)) { - int sense_key; - unsigned char asc; - - if (sense_buffer[0] & 0x2) { - sense_key = sense_buffer[1] & 0xf; - asc = sense_buffer[2]; - } else { - sense_key = sense_buffer[2] & 0xf; - asc = (sb_len > 12) ? sense_buffer[12] : 0; - } - - if (sense_key == RECOVERED_ERROR) - return SG_ERR_CAT_RECOVERED; - else if (sense_key == UNIT_ATTENTION) { - if (0x28 == asc) - return SG_ERR_CAT_MEDIA_CHANGED; - if (0x29 == asc) - return SG_ERR_CAT_RESET; - } else if (sense_key == ILLEGAL_REQUEST) { - return SG_ERR_CAT_NOTSUPPORTED; - } - } - return SG_ERR_CAT_SENSE; - } - if (host_status) { - if ((host_status == DID_NO_CONNECT) || - (host_status == DID_BUS_BUSY) || - (host_status == DID_TIME_OUT)) - return SG_ERR_CAT_TIMEOUT; - } - if (driver_status) { - if (driver_status == DRIVER_TIMEOUT) - return SG_ERR_CAT_TIMEOUT; - } - return SG_ERR_CAT_OTHER; -} - -static int sg_err_category3(struct udev *udev, struct sg_io_hdr *hp) -{ - return sg_err_category_new(udev, - hp->status, hp->msg_status, - hp->host_status, hp->driver_status, - hp->sbp, hp->sb_len_wr); -} - -static int sg_err_category4(struct udev *udev, struct sg_io_v4 *hp) -{ - return sg_err_category_new(udev, hp->device_status, 0, - hp->transport_status, hp->driver_status, - (unsigned char *)(uintptr_t)hp->response, - hp->response_len); -} - -static int scsi_dump_sense(struct udev *udev, - struct scsi_id_device *dev_scsi, - unsigned char *sense_buffer, int sb_len) -{ - int s; - int code; - int sense_class; - int sense_key; - int asc, ascq; -#ifdef DUMP_SENSE - char out_buffer[256]; - int i, j; -#endif - - /* - * Figure out and print the sense key, asc and ascq. - * - * If you want to suppress these for a particular drive model, add - * a black list entry in the scsi_id config file. - * - * XXX We probably need to: lookup the sense/asc/ascq in a retry - * table, and if found return 1 (after dumping the sense, asc, and - * ascq). So, if/when we get something like a power on/reset, - * we'll retry the command. - */ - - 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 index 763e079b4e..0000000000 --- a/src/udev/src/sd-daemon.c +++ /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 -#include -#include -#include -#ifdef __BIONIC__ -#include -#else -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(__linux__) -#include -#endif - -#include "sd-daemon.h" - -#if (__GNUC__ >= 4) -#ifdef SD_EXPORT_SYMBOLS -/* Export symbols */ -#define _sd_export_ __attribute__ ((visibility("default"))) -#else -/* Don't export the symbols */ -#define _sd_export_ __attribute__ ((visibility("hidden"))) -#endif -#else -#define _sd_export_ -#endif - -_sd_export_ int sd_listen_fds(int unset_environment) { - -#if defined(DISABLE_SYSTEMD) || !defined(__linux__) - return 0; -#else - int r, fd; - const char *e; - char *p = NULL; - unsigned long l; - - if (!(e = getenv("LISTEN_PID"))) { - r = 0; - goto finish; - } - - errno = 0; - l = strtoul(e, &p, 10); - - if (errno != 0) { - r = -errno; - goto finish; - } - - if (!p || *p || l <= 0) { - r = -EINVAL; - goto finish; - } - - /* Is this for us? */ - if (getpid() != (pid_t) l) { - r = 0; - goto finish; - } - - if (!(e = getenv("LISTEN_FDS"))) { - r = 0; - goto finish; - } - - errno = 0; - l = strtoul(e, &p, 10); - - if (errno != 0) { - r = -errno; - goto finish; - } - - if (!p || *p) { - r = -EINVAL; - goto finish; - } - - for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) { - int flags; - - if ((flags = fcntl(fd, F_GETFD)) < 0) { - r = -errno; - goto finish; - } - - if (flags & FD_CLOEXEC) - continue; - - if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) { - r = -errno; - goto finish; - } - } - - r = (int) l; - -finish: - if (unset_environment) { - unsetenv("LISTEN_PID"); - unsetenv("LISTEN_FDS"); - } - - return r; -#endif -} - -_sd_export_ int sd_is_fifo(int fd, const char *path) { - struct stat st_fd; - - if (fd < 0) - return -EINVAL; - - memset(&st_fd, 0, sizeof(st_fd)); - if (fstat(fd, &st_fd) < 0) - return -errno; - - if (!S_ISFIFO(st_fd.st_mode)) - return 0; - - if (path) { - struct stat st_path; - - memset(&st_path, 0, sizeof(st_path)); - if (stat(path, &st_path) < 0) { - - if (errno == ENOENT || errno == ENOTDIR) - return 0; - - return -errno; - } - - return - st_path.st_dev == st_fd.st_dev && - st_path.st_ino == st_fd.st_ino; - } - - return 1; -} - -_sd_export_ int sd_is_special(int fd, const char *path) { - struct stat st_fd; - - if (fd < 0) - return -EINVAL; - - if (fstat(fd, &st_fd) < 0) - return -errno; - - if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode)) - return 0; - - if (path) { - struct stat st_path; - - if (stat(path, &st_path) < 0) { - - if (errno == ENOENT || errno == ENOTDIR) - return 0; - - return -errno; - } - - if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode)) - return - st_path.st_dev == st_fd.st_dev && - st_path.st_ino == st_fd.st_ino; - else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode)) - return st_path.st_rdev == st_fd.st_rdev; - else - return 0; - } - - return 1; -} - -static int sd_is_socket_internal(int fd, int type, int listening) { - struct stat st_fd; - - if (fd < 0 || type < 0) - return -EINVAL; - - if (fstat(fd, &st_fd) < 0) - return -errno; - - if (!S_ISSOCK(st_fd.st_mode)) - return 0; - - if (type != 0) { - int other_type = 0; - socklen_t l = sizeof(other_type); - - if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0) - return -errno; - - if (l != sizeof(other_type)) - return -EINVAL; - - if (other_type != type) - return 0; - } - - if (listening >= 0) { - int accepting = 0; - socklen_t l = sizeof(accepting); - - if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0) - return -errno; - - if (l != sizeof(accepting)) - return -EINVAL; - - if (!accepting != !listening) - return 0; - } - - return 1; -} - -union sockaddr_union { - struct sockaddr sa; - struct sockaddr_in in4; - struct sockaddr_in6 in6; - struct sockaddr_un un; - struct sockaddr_storage storage; -}; - -_sd_export_ int sd_is_socket(int fd, int family, int type, int listening) { - int r; - - if (family < 0) - return -EINVAL; - - if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) - return r; - - if (family > 0) { - union sockaddr_union sockaddr; - socklen_t l; - - memset(&sockaddr, 0, sizeof(sockaddr)); - l = sizeof(sockaddr); - - if (getsockname(fd, &sockaddr.sa, &l) < 0) - return -errno; - - if (l < sizeof(sa_family_t)) - return -EINVAL; - - return sockaddr.sa.sa_family == family; - } - - return 1; -} - -_sd_export_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) { - union sockaddr_union sockaddr; - socklen_t l; - int r; - - if (family != 0 && family != AF_INET && family != AF_INET6) - return -EINVAL; - - if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) - return r; - - memset(&sockaddr, 0, sizeof(sockaddr)); - l = sizeof(sockaddr); - - if (getsockname(fd, &sockaddr.sa, &l) < 0) - return -errno; - - if (l < sizeof(sa_family_t)) - return -EINVAL; - - if (sockaddr.sa.sa_family != AF_INET && - sockaddr.sa.sa_family != AF_INET6) - return 0; - - if (family > 0) - if (sockaddr.sa.sa_family != family) - return 0; - - if (port > 0) { - if (sockaddr.sa.sa_family == AF_INET) { - if (l < sizeof(struct sockaddr_in)) - return -EINVAL; - - return htons(port) == sockaddr.in4.sin_port; - } else { - if (l < sizeof(struct sockaddr_in6)) - return -EINVAL; - - return htons(port) == sockaddr.in6.sin6_port; - } - } - - return 1; -} - -_sd_export_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) { - union sockaddr_union sockaddr; - socklen_t l; - int r; - - if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) - return r; - - memset(&sockaddr, 0, sizeof(sockaddr)); - l = sizeof(sockaddr); - - if (getsockname(fd, &sockaddr.sa, &l) < 0) - return -errno; - - if (l < sizeof(sa_family_t)) - return -EINVAL; - - if (sockaddr.sa.sa_family != AF_UNIX) - return 0; - - if (path) { - if (length <= 0) - length = strlen(path); - - if (length <= 0) - /* Unnamed socket */ - return l == offsetof(struct sockaddr_un, sun_path); - - if (path[0]) - /* Normal path socket */ - return - (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) && - memcmp(path, sockaddr.un.sun_path, length+1) == 0; - else - /* Abstract namespace socket */ - return - (l == offsetof(struct sockaddr_un, sun_path) + length) && - memcmp(path, sockaddr.un.sun_path, length) == 0; - } - - return 1; -} - -_sd_export_ int sd_is_mq(int fd, const char *path) { -#if !defined(__linux__) - return 0; -#else - struct mq_attr attr; - - if (fd < 0) - return -EINVAL; - - if (mq_getattr(fd, &attr) < 0) - return -errno; - - if (path) { - char fpath[PATH_MAX]; - struct stat a, b; - - if (path[0] != '/') - return -EINVAL; - - if (fstat(fd, &a) < 0) - return -errno; - - strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12); - fpath[sizeof(fpath)-1] = 0; - - if (stat(fpath, &b) < 0) - return -errno; - - if (a.st_dev != b.st_dev || - a.st_ino != b.st_ino) - return 0; - } - - return 1; -#endif -} - -_sd_export_ int sd_notify(int unset_environment, const char *state) { -#if defined(DISABLE_SYSTEMD) || !defined(__linux__) || !defined(SOCK_CLOEXEC) - return 0; -#else - int fd = -1, r; - struct msghdr msghdr; - struct iovec iovec; - union sockaddr_union sockaddr; - const char *e; - - if (!state) { - r = -EINVAL; - goto finish; - } - - if (!(e = getenv("NOTIFY_SOCKET"))) - return 0; - - /* Must be an abstract socket, or an absolute path */ - if ((e[0] != '@' && e[0] != '/') || e[1] == 0) { - r = -EINVAL; - goto finish; - } - - if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) { - r = -errno; - goto finish; - } - - memset(&sockaddr, 0, sizeof(sockaddr)); - sockaddr.sa.sa_family = AF_UNIX; - strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path)); - - if (sockaddr.un.sun_path[0] == '@') - sockaddr.un.sun_path[0] = 0; - - memset(&iovec, 0, sizeof(iovec)); - iovec.iov_base = (char*) state; - iovec.iov_len = strlen(state); - - memset(&msghdr, 0, sizeof(msghdr)); - msghdr.msg_name = &sockaddr; - msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e); - - if (msghdr.msg_namelen > sizeof(struct sockaddr_un)) - msghdr.msg_namelen = sizeof(struct sockaddr_un); - - msghdr.msg_iov = &iovec; - msghdr.msg_iovlen = 1; - - if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) { - r = -errno; - goto finish; - } - - r = 1; - -finish: - if (unset_environment) - unsetenv("NOTIFY_SOCKET"); - - if (fd >= 0) - close(fd); - - return r; -#endif -} - -_sd_export_ int sd_notifyf(int unset_environment, const char *format, ...) { -#if defined(DISABLE_SYSTEMD) || !defined(__linux__) - return 0; -#else - va_list ap; - char *p = NULL; - int r; - - va_start(ap, format); - r = vasprintf(&p, format, ap); - va_end(ap); - - if (r < 0 || !p) - return -ENOMEM; - - r = sd_notify(unset_environment, p); - free(p); - - return r; -#endif -} - -_sd_export_ int sd_booted(void) { -#if defined(DISABLE_SYSTEMD) || !defined(__linux__) - return 0; -#else - - struct stat a, b; - - /* We simply test whether the systemd cgroup hierarchy is - * mounted */ - - if (lstat("/sys/fs/cgroup", &a) < 0) - return 0; - - if (lstat("/sys/fs/cgroup/systemd", &b) < 0) - return 0; - - return a.st_dev != b.st_dev; -#endif -} diff --git a/src/udev/src/sd-daemon.h b/src/udev/src/sd-daemon.h deleted file mode 100644 index fe51159ee6..0000000000 --- a/src/udev/src/sd-daemon.h +++ /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 -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* - Reference implementation of a few systemd related interfaces for - writing daemons. These interfaces are trivial to implement. To - simplify porting we provide this reference implementation. - Applications are welcome to reimplement the algorithms described - here if they do not want to include these two source files. - - The following functionality is provided: - - - Support for logging with log levels on stderr - - File descriptor passing for socket-based activation - - Daemon startup and status notification - - Detection of systemd boots - - You may compile this with -DDISABLE_SYSTEMD to disable systemd - support. This makes all those calls NOPs that are directly related to - systemd (i.e. only sd_is_xxx() will stay useful). - - Since this is drop-in code we don't want any of our symbols to be - exported in any case. Hence we declare hidden visibility for all of - them. - - You may find an up-to-date version of these source files online: - - http://cgit.freedesktop.org/systemd/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 index 6161fb3e31..0000000000 --- a/src/udev/src/test-libudev.c +++ /dev/null @@ -1,501 +0,0 @@ -/* - * test-libudev - * - * Copyright (C) 2008 Kay Sievers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "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 ? "" : 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 index c9712e974d..0000000000 --- a/src/udev/src/test-udev.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2003-2004 Greg Kroah-Hartman - * Copyright (C) 2004-2008 Kay Sievers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "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 index e57f03e5a1..0000000000 --- a/src/udev/src/udev-builtin-blkid.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * probe disks for filesystems and partitions - * - * Copyright (C) 2011 Kay Sievers - * Copyright (C) 2011 Karel Zak - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "udev.h" - -static void print_property(struct udev_device *dev, bool test, const char *name, const char *value) -{ - char s[265]; - - s[0] = '\0'; - - if (!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 index d212c64b4d..0000000000 --- a/src/udev/src/udev-builtin-firmware.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * firmware - Kernel firmware loader - * - * Copyright (C) 2009 Piter Punk - * Copyright (C) 2009-2011 Kay Sievers - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details:* - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "udev.h" - -static bool set_loading(struct udev *udev, char *loadpath, const char *state) -{ - FILE *ldfile; - - ldfile = fopen(loadpath, "we"); - if (ldfile == NULL) { - 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 index aa996f375d..0000000000 --- a/src/udev/src/udev-builtin-hwdb.c +++ /dev/null @@ -1,247 +0,0 @@ -/* - * usb-db, pci-db - lookup vendor/product database - * - * Copyright (C) 2009 Lennart Poettering - * Copyright (C) 2011 Kay Sievers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include - -#include "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 index a062ef7c7a..0000000000 --- a/src/udev/src/udev-builtin-input_id.c +++ /dev/null @@ -1,218 +0,0 @@ -/* - * compose persistent device path - * - * Copyright (C) 2009 Martin Pitt - * Portions Copyright (C) 2004 David Zeuthen, - * Copyright (C) 2011 Kay Sievers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "udev.h" - -/* we must use this kernel-compatible implementation */ -#define BITS_PER_LONG (sizeof(unsigned long) * 8) -#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) -#define OFF(x) ((x)%BITS_PER_LONG) -#define BIT(x) (1UL<> OFF(bit)) & 1) - -/* - * Read a capability attribute and return bitmask. - * @param dev udev_device - * @param attr sysfs attribute name (e. g. "capabilities/key") - * @param bitmask: Output array which has a sizeof of bitmask_size - */ -static void get_cap_mask(struct udev_device *dev, - struct udev_device *pdev, const char* attr, - unsigned long *bitmask, size_t bitmask_size, - bool test) -{ - 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 index 57e813f863..0000000000 --- a/src/udev/src/udev-builtin-kmod.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * load kernel modules - * - * Copyright (C) 2011 Kay Sievers - * Copyright (C) 2011 ProFUSION embedded systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "udev.h" - -static struct kmod_ctx *ctx; - -static int load_module(struct udev *udev, const char *alias) -{ - struct kmod_list *list = NULL; - struct kmod_list *l; - int err; - - err = kmod_module_new_from_lookup(ctx, alias, &list); - if (err < 0) - return err; - - if (list == NULL) - 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 \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 index a8559d2dd4..0000000000 --- a/src/udev/src/udev-builtin-path_id.c +++ /dev/null @@ -1,498 +0,0 @@ -/* - * compose persistent device path - * - * Copyright (C) 2009-2011 Kay Sievers - * - * Logic based on Hannes Reinecke's shell script. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "udev.h" - -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 index 85828e32d7..0000000000 --- a/src/udev/src/udev-builtin-usb_id.c +++ /dev/null @@ -1,482 +0,0 @@ -/* - * USB device properties and persistent device path - * - * Copyright (c) 2005 SUSE Linux Products GmbH, Germany - * Author: Hannes Reinecke - * - * Copyright (C) 2005-2011 Kay Sievers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "udev.h" - -static void set_usb_iftype(char *to, int if_class_num, size_t len) -{ - 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 index 5bc5fa68f6..0000000000 --- a/src/udev/src/udev-builtin.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2007-2009 Kay Sievers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "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 index f80f774427..0000000000 --- a/src/udev/src/udev-control.socket +++ /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 index 5556f1a77c..0000000000 --- a/src/udev/src/udev-ctrl.c +++ /dev/null @@ -1,494 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008 Kay Sievers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "udev.h" - -/* wire protocol magic must match */ -#define UDEV_CTRL_MAGIC 0xdead1dea - -enum udev_ctrl_msg_type { - UDEV_CTRL_UNKNOWN, - UDEV_CTRL_SET_LOG_LEVEL, - UDEV_CTRL_STOP_EXEC_QUEUE, - UDEV_CTRL_START_EXEC_QUEUE, - UDEV_CTRL_RELOAD, - UDEV_CTRL_SET_ENV, - UDEV_CTRL_SET_CHILDREN_MAX, - UDEV_CTRL_PING, - UDEV_CTRL_EXIT, -}; - -struct udev_ctrl_msg_wire { - char version[16]; - unsigned int magic; - enum udev_ctrl_msg_type type; - union { - int intval; - char buf[256]; - }; -}; - -struct udev_ctrl_msg { - int refcount; - struct udev_ctrl_connection *conn; - struct udev_ctrl_msg_wire ctrl_msg_wire; -}; - -struct udev_ctrl { - int refcount; - struct udev *udev; - int sock; - struct sockaddr_un saddr; - socklen_t addrlen; - bool bound; - bool cleanup_socket; - bool connected; -}; - -struct udev_ctrl_connection { - int refcount; - struct udev_ctrl *uctrl; - int sock; -}; - -struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd) -{ - struct udev_ctrl *uctrl; - - 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 index 45dd77ba2e..0000000000 --- a/src/udev/src/udev-event.c +++ /dev/null @@ -1,1011 +0,0 @@ -/* - * Copyright (C) 2003-2010 Kay Sievers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 index 23fa9d5e11..0000000000 --- a/src/udev/src/udev-kernel.socket +++ /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 index 7a01a479ee..0000000000 --- a/src/udev/src/udev-node.c +++ /dev/null @@ -1,379 +0,0 @@ -/* - * Copyright (C) 2003-2010 Kay Sievers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 index 8a85eae717..0000000000 --- a/src/udev/src/udev-rules.c +++ /dev/null @@ -1,2767 +0,0 @@ -/* - * Copyright (C) 2003-2010 Kay Sievers - * Copyright (C) 2008 Alan Jenkins - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "udev.h" - -#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 index b0a4964f76..0000000000 --- a/src/udev/src/udev-settle.service.in +++ /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 index cd81945c88..0000000000 --- a/src/udev/src/udev-trigger.service.in +++ /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 index 228d18fedf..0000000000 --- a/src/udev/src/udev-watch.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (C) 2004-2010 Kay Sievers - * Copyright (C) 2009 Canonical Ltd. - * Copyright (C) 2009 Scott James Remnant - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "udev.h" - -static int inotify_fd = -1; - -/* inotify descriptor, will be shared with rules directory; - * set to cloexec since we need our children to be able to add - * watches for us - */ -int udev_watch_init(struct udev *udev) -{ - inotify_fd = inotify_init1(IN_CLOEXEC); - if (inotify_fd < 0) - 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 index f39253eb67..0000000000 --- a/src/udev/src/udev.conf +++ /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 index bc051c9b65..0000000000 --- a/src/udev/src/udev.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (C) 2003 Greg Kroah-Hartman - * Copyright (C) 2003-2010 Kay Sievers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef _UDEV_H_ -#define _UDEV_H_ - -#include -#include -#include - -#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 index 0b04c02ef6..0000000000 --- a/src/udev/src/udev.pc.in +++ /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 index c27eb1baf5..0000000000 --- a/src/udev/src/udev.service.in +++ /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 index 8eb583a823..0000000000 --- a/src/udev/src/udev.xml +++ /dev/null @@ -1,695 +0,0 @@ - - - - - - - udev - udev - - - - udev - 7 - - - - udev - Linux dynamic device management - - - Description - udev supplies the system software with device events, manages permissions - of device nodes and may create additional symlinks in the /dev - directory, or renames network interfaces. The kernel usually just assigns unpredictable - device names based on the order of discovery. Meaningful symlinks or network device - names provide a way to reliably identify devices based on their properties or - current configuration. - - The udev daemon, udevd - 8, receives device uevents directly from - the kernel whenever a device is added or removed from the system, or it changes its - state. When udev receives a device event, it matches its configured set of rules - against various device attributes to identify the device. Rules that match may - provide additional device information to be stored in the udev database or - to be used to create meaningful symlink names. - - All device information udev processes is stored in the udev database and - sent out to possible event subscribers. Access to all stored data and the event - sources is provided by the library libudev. - - - Configuration - udev configuration files are placed in /etc/udev - and /usr/lib/udev. All empty lines or lines beginning with - '#' are ignored. - - Configuration file - udev expects its main configuration file at /etc/udev/udev.conf. - It consists of a set of variables allowing the user to override default udev values. - The following variables can be set: - - - - - Specifies where to place the device nodes in the filesystem. - The default value is /dev. - - - - - - - The logging priority. Valid values are the numerical syslog priorities - or their textual representations: , - and . - - - - - - Rules files - The udev rules are read from the files located in the - system rules directory /usr/lib/udev/rules.d, - the volatile runtime directory /run/udev/rules.d - and the local administration directory /etc/udev/rules.d. - All rules files are collectively sorted and processed in lexical order, - regardless of the directories in which they live. However, files with - identical file names replace each other. Files in /etc - have the highest priority, files in /run take precedence - over files with the same name in /lib. This can be - used to override a system-supplied rules file with a local file if needed; - a symlink in /etc with the same name as a rules file in - /lib, pointing to /dev/null, - disables the rules file entirely. - - Rule files must have the extension .rules; other - extensions are ignored. - - Every line in the rules file contains at least one key-value pair. - 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. - - A matching rule may rename a network interface, add symlinks - pointing to the device node, or run a specified program as part of - the event handling. - - A rule consists of a comma-separated list of one or more key-value pairs. - Each key has a distinct operation, depending on the used operator. Valid - operators are: - - - - - Compare for equality. - - - - - - - Compare for inequality. - - - - - - - Assign a value to a key. Keys that represent a list are reset - and only this single value is assigned. - - - - - - - Add the value to a key that holds a list of entries. - - - - - - - Assign a value to a key finally; disallow any later changes. - - - - - The following key names can be used to match against device properties. - Some of the keys also match against properties of the parent devices in sysfs, - not only the device that has generated the event. If multiple keys that match - a parent device are specified in a single rule, all these keys must match at - one and the same parent device. - - - - - Match the name of the event action. - - - - - - - Match the devpath of the event device. - - - - - - - Match the name of the event device. - - - - - - - Match the name of a network interface. It can be used once the - NAME key has been set in one of the preceding rules. - - - - - - - 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. - - - - - - - - Match the subsystem of the event device. - - - - - - 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. - - - - - - 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. - - - - - - - - Search the devpath upwards for a matching device name. - - - - - - - Search the devpath upwards for a matching device subsystem name. - - - - - - - Search the devpath upwards for a matching device driver name. - - - - - - - Search the devpath upwards for a device with matching sysfs attribute values. - If multiple 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. - - - - - - - Search the devpath upwards for a device with matching tag. - - - - - - - Match against a device property value. - - - - - - - Match against a device tag. - - - - - - - Test the existence of a file. An octal mode mask can be specified - if needed. - - - - - - - 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. - - - - - - - Match the returned string of the last PROGRAM call. This key can - be used in the same or in any later rule after a PROGRAM call. - - - - - Most of the fields support shell-style pattern matching. The following - pattern characters are supported: - - - - - Matches zero or more characters. - - - - - - Matches any single character. - - - - - - Matches any single character specified within the brackets. For - example, the pattern string 'tty[SR]' would match either 'ttyS' or 'ttyR'. - Ranges are also supported via the '-' character. - For example, to match on the range of all digits, the pattern [0-9] could - be used. If the first character following the '[' is a '!', any characters - not enclosed are matched. - - - - - The following keys can get values assigned: - - - - - 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. - - - - - - - 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. - - - - - - - - The permissions for the device node. Every specified value overrides - the compiled-in default value. - - - - - - - The value that should be written to a sysfs attribute of the - event device. - - - - - - - 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). - - - - - - - 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. - - - - - - - Add a program to the list of programs to be executed for a specific - device. - 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. - 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. - - - - - - - A named label to which a GOTO may jump. - - - - - - - Jumps to the next LABEL with a matching name. - - - - - - - Import a set of variables as device properties, - depending on type: - - - - - 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 . - - - - - - Import a text file specified as the assigned value, the content - of which must be in environment key format. - - - - - - 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. - - - - - - Import a single property from the kernel command line. For simple flags - the value of the property is set to '1'. - - - - - - Import the stored keys from the parent device by reading - the database entry of the parent device. The value assigned to - is used as a filter of key names - to import (with the same shell-style pattern matching used for - comparisons). - - - - - - - - - - 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. - - - - - - - Rule and device options: - - - - - Specify the priority of the created symlinks. Devices with higher - priorities overwrite existing symlinks of other devices. The default is 0. - - - - - - Number of seconds an event waits for operations to finish before - giving up and terminating itself. - - - - - - Usually control and other possibly unsafe characters are replaced - in strings used for device naming. The mode of replacement can be specified - with this option. - - - - - - Apply the permissions specified in this rule to the static device node with - the specified name. Static device nodes might be provided by kernel modules - or copied from /usr/lib/udev/devices. These nodes might not have - a corresponding kernel device at the time udevd is started; they can trigger - automatic kernel module loading. - - - - - - Watch the device node with inotify; when the node is closed after being opened for - writing, a change uevent is synthesized. - - - - - - Disable the watching of a device node with inotify. - - - - - - - - The , , , - , , and - fields support simple string substitutions. The - substitutions are performed after all rules have been processed, right before the program - is executed, allowing for the use of device properties set by earlier matching - rules. For all other fields, substitutions are performed while the individual rule is - being processed. The available substitutions are: - - - , - - The kernel name for this device. - - - - - , - - The kernel number for this device. For example, 'sda3' has - kernel number of '3' - - - - - , - - The devpath of the device. - - - - - , - - The name of the device matched while searching the devpath upwards for - , , and . - - - - - - - - The driver name of the device matched while searching the devpath upwards for - , , and . - - - - - - , - - The value of a sysfs attribute found at the device where - all keys of the rule have matched. If the matching device does not have - such an attribute, and a previous KERNELS, SUBSYSTEMS, DRIVERS, or - ATTRS test selected a parent device, then the attribute from that - parent device is used. - If the attribute is a symlink, the last element of the symlink target is - returned as the value. - - - - - , - - A device property value. - - - - - , - - The kernel major number for the device. - - - - - , - - The kernel minor number for the device. - - - - - , - - The string returned by the external program requested with PROGRAM. - A single part of the string, separated by a space character, may be selected - by specifying the part number as an attribute: . - If the number is followed by the '+' character, this part plus all remaining parts - of the result string are substituted: - - - - - , - - The node name of the parent device. - - - - - - - The current name of the device. If not changed by a rule, it is the - name of the kernel device. - - - - - - - A space-separated list of the current symlinks. The value is - only set during a remove event or if an earlier rule assigned a value. - - - - - , - - The udev_root value. - - - - - , - - The sysfs mount point. - - - - - , - - The name of the device node. - - - - - - - The '%' character itself. - - - - - - - The '$' character itself. - - - - - - - Author - Written by Greg Kroah-Hartman greg@kroah.com and - Kay Sievers kay.sievers@vrfy.org. With much help from - Dan Stekloff and many others. - - - - See Also - - udevd8 - , - - udevadm8 - - - diff --git a/src/udev/src/udevadm-control.c b/src/udev/src/udevadm-control.c deleted file mode 100644 index cafa214944..0000000000 --- a/src/udev/src/udevadm-control.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (C) 2005-2011 Kay Sievers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "udev.h" - -static void print_help(void) -{ - printf("Usage: udevadm control COMMAND\n" - " --exit instruct the daemon to cleanup and exit\n" - " --log-priority= 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== set a global property for all events\n" - " --children-max= maximum number of children\n" - " --timeout= 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 = 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 index ee9b59fea8..0000000000 --- a/src/udev/src/udevadm-info.c +++ /dev/null @@ -1,568 +0,0 @@ -/* - * Copyright (C) 2004-2009 Kay Sievers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "udev.h" - -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= 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= sys device path used for query or attribute walk\n" - " --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= 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 index 5997dd8e18..0000000000 --- a/src/udev/src/udevadm-monitor.c +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright (C) 2004-2010 Kay Sievers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "udev.h" - -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= filter events by subsystem\n" - " --tag-match= 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 index b168defd90..0000000000 --- a/src/udev/src/udevadm-settle.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (C) 2006-2009 Kay Sievers - * Copyright (C) 2009 Canonical Ltd. - * Copyright (C) 2009 Scott James Remnant - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "udev.h" - -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= maximum time to wait for events\n" - " --seq-start= first seqnum to wait for\n" - " --seq-end= last seqnum to wait for\n" - " --exit-if-exists= 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 index 3a49f7ce9c..0000000000 --- a/src/udev/src/udevadm-test-builtin.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2011 Kay Sievers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "udev.h" - -static void help(struct udev *udev) -{ - fprintf(stderr, "\n"); - fprintf(stderr, "Usage: udevadm builtin [--help] \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 index 6275cff899..0000000000 --- a/src/udev/src/udevadm-test.c +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (C) 2003-2004 Greg Kroah-Hartman - * Copyright (C) 2004-2008 Kay Sievers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "udev.h" - -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 \n" - " --action= 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 index 3cce23dfb2..0000000000 --- a/src/udev/src/udevadm-trigger.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (C) 2008-2009 Kay Sievers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "udev.h" - -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= event action value, default is \"change\"\n" - " --subsystem-match= trigger devices from a matching subsystem\n" - " --subsystem-nomatch= exclude devices from a matching subsystem\n" - " --attr-match=]> trigger devices with a matching attribute\n" - " --attr-nomatch=]> exclude devices with a matching attribute\n" - " --property-match== trigger devices with a matching property\n" - " --tag-match== trigger devices with a matching property\n" - " --sysname-match= trigger devices with a matching name\n" - " --parent-match= 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 index 224ece0bb7..0000000000 --- a/src/udev/src/udevadm.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (C) 2007-2009 Kay Sievers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "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 index 455ce80ca9..0000000000 --- a/src/udev/src/udevadm.xml +++ /dev/null @@ -1,472 +0,0 @@ - - - - - - - udevadm - udev - - - - udevadm - 8 - - - - - udevadmudev management tool - - - - - udevadm - - - - - - udevadm info options - - - udevadm trigger options - - - udevadm settle options - - - udevadm control command - - - udevadm monitor options - - - udevadm test options devpath - - - udevadm test-builtin options command devpath - - - - Description - udevadm expects a command and command specific options. It - controls the runtime behavior of udev, requests kernel events, - manages the event queue, and provides simple debugging mechanisms. - - - OPTIONS - - - - - Print debug messages to stderr. - - - - - - Print version number. - - - - - - Print help text. - - - - - udevadm info <replaceable>options</replaceable> - Queries the udev database for device information - stored in the udev database. It can also query the properties - of a device from its sysfs representation to help creating udev - rules that match this device. - - - - - Query the database for specified type of device data. It needs the - or to identify the specified - device. Valid queries are: - name, symlink, path, - property, all. - - - - - - The devpath of the device to query. - - - - - - The name of the device node or a symlink to query - - - - - - The udev root directory: /dev. If used in conjunction - with a name or symlink query, the - query returns the absolute path including the root directory. - - - - - - The udev runtime directory: /run/udev. - - - - - - Print all sysfs properties of the specified device that can be used - in udev rules to match the specified device. It prints all devices - along the chain, up to the root of sysfs that can be used in udev rules. - - - - - - Print output as key/value pairs. Values are enclosed in single quotes. - - - - - - Add a prefix to the key name of exported values. - - - - - - Print major/minor numbers of the underlying device, where the file - lives on. - - - - - - Export the content of the udev database. - - - - - - Cleanup the udev database. - - - - - - Print version. - - - - - - Print help text. - - - - - - udevadm trigger <optional>options</optional> - Request device events from the kernel. Primarily used to replay events at system coldplug time. - - - - - Print the list of devices which will be triggered. - - - - - - Do not actually trigger the event. - - - - - - Trigger a specific type of devices. Valid types are: - devices, subsystems. - The default value is devices. - - - - - - Type of event to be triggered. The default value is change. - - - - - - Trigger events for devices which belong to a matching subsystem. This option - can be specified multiple times and supports shell style pattern matching. - - - - - - Do not trigger events for devices which belong to a matching subsystem. This option - can be specified multiple times and supports shell style pattern matching. - - - - - - Trigger events for devices with a matching sysfs attribute. If a value is specified - along with the attribute name, the content of the attribute is matched against the given - value using shell style pattern matching. If no value is specified, the existence of the - sysfs attribute is checked. This option can be specified multiple times. - - - - - - Do not trigger events for devices with a matching sysfs attribute. If a value is - specified along with the attribute name, the content of the attribute is matched against - the given value using shell style pattern matching. If no value is specified, the existence - of the sysfs attribute is checked. This option can be specified multiple times. - - - - - - Trigger events for devices with a matching property value. This option can be - specified multiple times and supports shell style pattern matching. - - - - - - Trigger events for devices with a matching tag. This option can be - specified multiple times. - - - - - - Trigger events for devices with a matching sys device name. This option can be - specified multiple times and supports shell style pattern matching. - - - - - - Trigger events for all children of a given device. - - - - - - udevadm settle <optional>options</optional> - Watches the udev event queue, and exits if all current events are handled. - - - - - Maximum number of seconds to wait for the event queue to become empty. - The default value is 120 seconds. A value of 0 will check if the queue is empty - and always return immediately. - - - - - - Wait only for events after the given sequence number. - - - - - - Wait only for events before the given sequence number. - - - - - - Stop waiting if file exists. - - - - - - Do not print any output, like the remaining queue entries when reaching the timeout. - - - - - - Print help text. - - - - - - udevadm control <replaceable>command</replaceable> - Modify the internal state of the running udev daemon. - - - - - Signal and wait for udevd to exit. - - - - - - Set the internal log level of udevd. Valid values are the numerical - syslog priorities or their textual representations: , - and . - - - - - - Signal udevd to stop executing new events. Incoming events - will be queued. - - - - - - Signal udevd to enable the execution of events. - - - - - - 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. - - - - - - Set a global property for all events. - - - - value - - Set the maximum number of events, udevd will handle at the - same time. - - - - seconds - - The maximum number seconds to wait for a reply from udevd. - - - - - - Print help text. - - - - - - udevadm monitor <optional>options</optional> - Listens to the kernel uevents and events sent out by a udev rule - and prints the devpath of the event to the console. It can be used to analyze the - event timing, by comparing the timestamps of the kernel uevent and the udev event. - - - - - - Print the kernel uevents. - - - - - - Print the udev event after the rule processing. - - - - - - Also print the properties of the event. - - - - - - Filter events by subsystem[/devtype]. Only udev events with a matching subsystem value will pass. - - - - - - Filter events by property. Only udev events with a given tag attached will pass. - - - - - - Print help text. - - - - - - udevadm test <optional>options</optional> <replaceable>devpath</replaceable> - Simulate a udev event run for the given device, and print debug output. - - - - - The action string. - - - - - - The subsystem string. - - - - - - Print help text. - - - - - - udevadm test-builtin <optional>options</optional> <replaceable>command</replaceable> <replaceable>devpath</replaceable> - Run a built-in command for the given device, and print debug output. - - - - - Print help text. - - - - - - - Author - Written by Kay Sievers kay.sievers@vrfy.org. - - - - See Also - - udev7 - - - udevd8 - - - diff --git a/src/udev/src/udevd.c b/src/udev/src/udevd.c deleted file mode 100644 index 170221790a..0000000000 --- a/src/udev/src/udevd.c +++ /dev/null @@ -1,1746 +0,0 @@ -/* - * Copyright (C) 2004-2011 Kay Sievers - * Copyright (C) 2004 Chris Friesen - * Copyright (C) 2009 Canonical Ltd. - * Copyright (C) 2009 Scott James Remnant - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "udev.h" -#include "sd-daemon.h" - -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=\n" - " --exec-delay=\n" - " --resolve-names=early|late|never\n" - " --version\n" - " --help\n" - "\n"); - goto exit; - case 'V': - printf("%s\n", VERSION); - goto exit; - default: - goto exit; - } - } - - /* - * read the kernel commandline, in case we need to get into debug mode - * udev.log-priority= syslog priority - * udev.children-max= events are fully serialized if set to 1 - * - */ - 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 : ""); - 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 index c516eb9793..0000000000 --- a/src/udev/src/udevd.xml +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - - udevd - udev - - - - udevd - 8 - - - - - udevdevent managing daemon - - - - - udevd - - - - - - - - - - - Description - udevd listens to kernel uevents. For every event, udevd executes matching - instructions specified in udev rules. See - udev7 - . - On startup the content of the directory /usr/lib/udev/devices - is copied to /dev. 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. - The behavior of the running daemon can be changed with - udevadm control. - - - Options - - - - - Detach and run in the background. - - - - - - Print debug messages to stderr. - - - - - - Limit the number of parallel executed events. - - - - - - 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. - - - - - - Specify when udevd should resolve names of users and groups. - When set to (the default) names will be - resolved when the rules are parsed. When set to - names will be resolved for every event. - When set to names will never be resolved - and all devices will be owned by root. - - - - - - Print version number. - - - - - - Print help text. - - - - - - Environment - - - UDEV_LOG= - - Set the logging priority. - - - - - - Kernel command line - - - udev.log-priority= - - Set the logging priority. - - - - udev.children-max= - - Limit the number of parallel executed events. - - - - udev.exec-delay= - - 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. - - - - - - Author - Written by Kay Sievers kay.sievers@vrfy.org. - - - - See Also - - udev7 - , - udevadm8 - - - 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 index 93c5ee8c27..0000000000 --- a/src/udev/src/v4l_id/60-persistent-v4l.rules +++ /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 index a2a80b5f43..0000000000 --- a/src/udev/src/v4l_id/v4l_id.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2009 Kay Sievers - * Copyright (c) 2009 Filippo Argiolas - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details: - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int main (int argc, char *argv[]) -{ - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - {} - }; - int fd; - char *device; - struct v4l2_capability v2cap; - - while (1) { - int option; - - option = getopt_long(argc, argv, "h", options, NULL); - if (option == -1) - break; - - switch (option) { - case 'h': - printf("Usage: v4l_id [--help] \n\n"); - return 0; - default: - return 1; - } - } - device = argv[optind]; - - if (device == NULL) - return 2; - fd = open (device, O_RDONLY); - if (fd < 0) - return 3; - - if (ioctl (fd, VIDIOC_QUERYCAP, &v2cap) == 0) { - printf("ID_V4L_VERSION=2\n"); - printf("ID_V4L_PRODUCT=%s\n", v2cap.card); - printf("ID_V4L_CAPABILITIES=:"); - if ((v2cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) > 0) - printf("capture:"); - if ((v2cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) > 0) - printf("video_output:"); - if ((v2cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) > 0) - printf("video_overlay:"); - if ((v2cap.capabilities & V4L2_CAP_AUDIO) > 0) - printf("audio:"); - if ((v2cap.capabilities & V4L2_CAP_TUNER) > 0) - printf("tuner:"); - if ((v2cap.capabilities & V4L2_CAP_RADIO) > 0) - printf("radio:"); - printf("\n"); - } - - close (fd); - return 0; -} diff --git a/src/udev/test-libudev.c b/src/udev/test-libudev.c new file mode 100644 index 0000000000..6161fb3e31 --- /dev/null +++ b/src/udev/test-libudev.c @@ -0,0 +1,501 @@ +/* + * test-libudev + * + * Copyright (C) 2008 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "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 ? "" : 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 index 0000000000..c9712e974d --- /dev/null +++ b/src/udev/test-udev.c @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2003-2004 Greg Kroah-Hartman + * Copyright (C) 2004-2008 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "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/test/rules-test.sh b/src/udev/test/rules-test.sh index 1e224ff8b5..5b3acea31f 100755 --- a/src/udev/test/rules-test.sh +++ b/src/udev/test/rules-test.sh @@ -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 index 0000000000..e57f03e5a1 --- /dev/null +++ b/src/udev/udev-builtin-blkid.c @@ -0,0 +1,207 @@ +/* + * probe disks for filesystems and partitions + * + * Copyright (C) 2011 Kay Sievers + * Copyright (C) 2011 Karel Zak + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +static void print_property(struct udev_device *dev, bool test, const char *name, const char *value) +{ + char s[265]; + + s[0] = '\0'; + + if (!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 index 0000000000..d212c64b4d --- /dev/null +++ b/src/udev/udev-builtin-firmware.c @@ -0,0 +1,168 @@ +/* + * firmware - Kernel firmware loader + * + * Copyright (C) 2009 Piter Punk + * Copyright (C) 2009-2011 Kay Sievers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details:* + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +static bool set_loading(struct udev *udev, char *loadpath, const char *state) +{ + FILE *ldfile; + + ldfile = fopen(loadpath, "we"); + if (ldfile == NULL) { + 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 index 0000000000..aa996f375d --- /dev/null +++ b/src/udev/udev-builtin-hwdb.c @@ -0,0 +1,247 @@ +/* + * usb-db, pci-db - lookup vendor/product database + * + * Copyright (C) 2009 Lennart Poettering + * Copyright (C) 2011 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "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 index 0000000000..a062ef7c7a --- /dev/null +++ b/src/udev/udev-builtin-input_id.c @@ -0,0 +1,218 @@ +/* + * compose persistent device path + * + * Copyright (C) 2009 Martin Pitt + * Portions Copyright (C) 2004 David Zeuthen, + * Copyright (C) 2011 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +/* we must use this kernel-compatible implementation */ +#define BITS_PER_LONG (sizeof(unsigned long) * 8) +#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) +#define OFF(x) ((x)%BITS_PER_LONG) +#define BIT(x) (1UL<> OFF(bit)) & 1) + +/* + * Read a capability attribute and return bitmask. + * @param dev udev_device + * @param attr sysfs attribute name (e. g. "capabilities/key") + * @param bitmask: Output array which has a sizeof of bitmask_size + */ +static void get_cap_mask(struct udev_device *dev, + struct udev_device *pdev, const char* attr, + unsigned long *bitmask, size_t bitmask_size, + bool test) +{ + 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 index 0000000000..57e813f863 --- /dev/null +++ b/src/udev/udev-builtin-kmod.c @@ -0,0 +1,142 @@ +/* + * load kernel modules + * + * Copyright (C) 2011 Kay Sievers + * Copyright (C) 2011 ProFUSION embedded systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +static struct kmod_ctx *ctx; + +static int load_module(struct udev *udev, const char *alias) +{ + struct kmod_list *list = NULL; + struct kmod_list *l; + int err; + + err = kmod_module_new_from_lookup(ctx, alias, &list); + if (err < 0) + return err; + + if (list == NULL) + 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 \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 index 0000000000..a8559d2dd4 --- /dev/null +++ b/src/udev/udev-builtin-path_id.c @@ -0,0 +1,498 @@ +/* + * compose persistent device path + * + * Copyright (C) 2009-2011 Kay Sievers + * + * Logic based on Hannes Reinecke's shell script. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +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 index 0000000000..85828e32d7 --- /dev/null +++ b/src/udev/udev-builtin-usb_id.c @@ -0,0 +1,482 @@ +/* + * USB device properties and persistent device path + * + * Copyright (c) 2005 SUSE Linux Products GmbH, Germany + * Author: Hannes Reinecke + * + * Copyright (C) 2005-2011 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +static void set_usb_iftype(char *to, int if_class_num, size_t len) +{ + 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 index 0000000000..5bc5fa68f6 --- /dev/null +++ b/src/udev/udev-builtin.c @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2007-2009 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "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 index 0000000000..5556f1a77c --- /dev/null +++ b/src/udev/udev-ctrl.c @@ -0,0 +1,494 @@ +/* + * libudev - interface to udev device information + * + * Copyright (C) 2008 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +/* wire protocol magic must match */ +#define UDEV_CTRL_MAGIC 0xdead1dea + +enum udev_ctrl_msg_type { + UDEV_CTRL_UNKNOWN, + UDEV_CTRL_SET_LOG_LEVEL, + UDEV_CTRL_STOP_EXEC_QUEUE, + UDEV_CTRL_START_EXEC_QUEUE, + UDEV_CTRL_RELOAD, + UDEV_CTRL_SET_ENV, + UDEV_CTRL_SET_CHILDREN_MAX, + UDEV_CTRL_PING, + UDEV_CTRL_EXIT, +}; + +struct udev_ctrl_msg_wire { + char version[16]; + unsigned int magic; + enum udev_ctrl_msg_type type; + union { + int intval; + char buf[256]; + }; +}; + +struct udev_ctrl_msg { + int refcount; + struct udev_ctrl_connection *conn; + struct udev_ctrl_msg_wire ctrl_msg_wire; +}; + +struct udev_ctrl { + int refcount; + struct udev *udev; + int sock; + struct sockaddr_un saddr; + socklen_t addrlen; + bool bound; + bool cleanup_socket; + bool connected; +}; + +struct udev_ctrl_connection { + int refcount; + struct udev_ctrl *uctrl; + int sock; +}; + +struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd) +{ + struct udev_ctrl *uctrl; + + 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 index 0000000000..40a6b7d33e --- /dev/null +++ b/src/udev/udev-event.c @@ -0,0 +1,1011 @@ +/* + * Copyright (C) 2003-2010 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 0000000000..7a01a479ee --- /dev/null +++ b/src/udev/udev-node.c @@ -0,0 +1,379 @@ +/* + * Copyright (C) 2003-2010 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 0000000000..8a85eae717 --- /dev/null +++ b/src/udev/udev-rules.c @@ -0,0 +1,2767 @@ +/* + * Copyright (C) 2003-2010 Kay Sievers + * Copyright (C) 2008 Alan Jenkins + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +#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 index 0000000000..228d18fedf --- /dev/null +++ b/src/udev/udev-watch.c @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2004-2010 Kay Sievers + * Copyright (C) 2009 Canonical Ltd. + * Copyright (C) 2009 Scott James Remnant + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +static int inotify_fd = -1; + +/* inotify descriptor, will be shared with rules directory; + * set to cloexec since we need our children to be able to add + * watches for us + */ +int udev_watch_init(struct udev *udev) +{ + inotify_fd = inotify_init1(IN_CLOEXEC); + if (inotify_fd < 0) + 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 index 0000000000..f39253eb67 --- /dev/null +++ b/src/udev/udev.conf @@ -0,0 +1,3 @@ +# see udev(7) for details + +#udev_log="info" diff --git a/src/udev/udev.h b/src/udev/udev.h new file mode 100644 index 0000000000..bc051c9b65 --- /dev/null +++ b/src/udev/udev.h @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2003 Greg Kroah-Hartman + * Copyright (C) 2003-2010 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _UDEV_H_ +#define _UDEV_H_ + +#include +#include +#include + +#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 index 0000000000..0b04c02ef6 --- /dev/null +++ b/src/udev/udev.pc.in @@ -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 index 0000000000..cafa214944 --- /dev/null +++ b/src/udev/udevadm-control.c @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2005-2011 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +static void print_help(void) +{ + printf("Usage: udevadm control COMMAND\n" + " --exit instruct the daemon to cleanup and exit\n" + " --log-priority= 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== set a global property for all events\n" + " --children-max= maximum number of children\n" + " --timeout= 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 = 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 index 0000000000..ee9b59fea8 --- /dev/null +++ b/src/udev/udevadm-info.c @@ -0,0 +1,568 @@ +/* + * Copyright (C) 2004-2009 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +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= 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= sys device path used for query or attribute walk\n" + " --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= 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 index 0000000000..5997dd8e18 --- /dev/null +++ b/src/udev/udevadm-monitor.c @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2004-2010 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +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= filter events by subsystem\n" + " --tag-match= 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 index 0000000000..b168defd90 --- /dev/null +++ b/src/udev/udevadm-settle.c @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2006-2009 Kay Sievers + * Copyright (C) 2009 Canonical Ltd. + * Copyright (C) 2009 Scott James Remnant + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +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= maximum time to wait for events\n" + " --seq-start= first seqnum to wait for\n" + " --seq-end= last seqnum to wait for\n" + " --exit-if-exists= 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 index 0000000000..3a49f7ce9c --- /dev/null +++ b/src/udev/udevadm-test-builtin.c @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2011 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +static void help(struct udev *udev) +{ + fprintf(stderr, "\n"); + fprintf(stderr, "Usage: udevadm builtin [--help] \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 index 0000000000..6275cff899 --- /dev/null +++ b/src/udev/udevadm-test.c @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2003-2004 Greg Kroah-Hartman + * Copyright (C) 2004-2008 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +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 \n" + " --action= 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 index 0000000000..3cce23dfb2 --- /dev/null +++ b/src/udev/udevadm-trigger.c @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2008-2009 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +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= event action value, default is \"change\"\n" + " --subsystem-match= trigger devices from a matching subsystem\n" + " --subsystem-nomatch= exclude devices from a matching subsystem\n" + " --attr-match=]> trigger devices with a matching attribute\n" + " --attr-nomatch=]> exclude devices with a matching attribute\n" + " --property-match== trigger devices with a matching property\n" + " --tag-match== trigger devices with a matching property\n" + " --sysname-match= trigger devices with a matching name\n" + " --parent-match= 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 index 0000000000..224ece0bb7 --- /dev/null +++ b/src/udev/udevadm.c @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2007-2009 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "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 index 0000000000..694e758777 --- /dev/null +++ b/src/udev/udevd.c @@ -0,0 +1,1746 @@ +/* + * Copyright (C) 2004-2011 Kay Sievers + * Copyright (C) 2004 Chris Friesen + * Copyright (C) 2009 Canonical Ltd. + * Copyright (C) 2009 Scott James Remnant + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" +#include "sd-daemon.h" + +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=\n" + " --exec-delay=\n" + " --resolve-names=early|late|never\n" + " --version\n" + " --help\n" + "\n"); + goto exit; + case 'V': + printf("%s\n", VERSION); + goto exit; + default: + goto exit; + } + } + + /* + * read the kernel commandline, in case we need to get into debug mode + * udev.log-priority= syslog priority + * udev.children-max= events are fully serialized if set to 1 + * + */ + 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 : ""); + 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 index 0000000000..93c5ee8c27 --- /dev/null +++ b/src/udev/v4l_id/60-persistent-v4l.rules @@ -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 index 0000000000..a2a80b5f43 --- /dev/null +++ b/src/udev/v4l_id/v4l_id.c @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2009 Kay Sievers + * Copyright (c) 2009 Filippo Argiolas + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details: + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main (int argc, char *argv[]) +{ + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + {} + }; + int fd; + char *device; + struct v4l2_capability v2cap; + + while (1) { + int option; + + option = getopt_long(argc, argv, "h", options, NULL); + if (option == -1) + break; + + switch (option) { + case 'h': + printf("Usage: v4l_id [--help] \n\n"); + return 0; + default: + return 1; + } + } + device = argv[optind]; + + if (device == NULL) + return 2; + fd = open (device, O_RDONLY); + if (fd < 0) + return 3; + + if (ioctl (fd, VIDIOC_QUERYCAP, &v2cap) == 0) { + printf("ID_V4L_VERSION=2\n"); + printf("ID_V4L_PRODUCT=%s\n", v2cap.card); + printf("ID_V4L_CAPABILITIES=:"); + if ((v2cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) > 0) + printf("capture:"); + if ((v2cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) > 0) + printf("video_output:"); + if ((v2cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) > 0) + printf("video_overlay:"); + if ((v2cap.capabilities & V4L2_CAP_AUDIO) > 0) + printf("audio:"); + if ((v2cap.capabilities & V4L2_CAP_TUNER) > 0) + printf("tuner:"); + if ((v2cap.capabilities & V4L2_CAP_RADIO) > 0) + printf("radio:"); + printf("\n"); + } + + close (fd); + return 0; +} -- cgit v1.2.3-54-g00ecf