diff --git a/udev-dev.c b/udev-dev.c index 1d5318b..6011aa8 100644 --- a/udev-dev.c +++ b/udev-dev.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -267,6 +268,7 @@ create_evdev_handler(struct udev_device *ud) unsigned long sw_bits[NLONGS(SW_CNT)]; unsigned long prp_bits[NLONGS(INPUT_PROP_CNT)]; struct input_id id; + uint64_t devnum = 0; #ifdef HAVE_SYSCTLBYNAME const char *unit; char mib[32]; @@ -316,6 +318,16 @@ create_evdev_handler(struct udev_device *ud) if (sysctlbyname(mib, prp_bits, &len, NULL, 0) < 0) goto use_ioctl; + /* + * devnum sysctl is optional: sysctlbyname on kernels predacting its + * introduction will fail but that does not mean we should fall back to + * ioctl. We just leave devnum untouched, with its initialization value + * of zero. + */ + snprintf(mib, sizeof(mib), "kern.evdev.input.%s.devnum", unit); + len = sizeof(devnum); + (void)sysctlbyname(mib, &devnum, &len, NULL, 0); + goto found_values; use_ioctl: @@ -346,6 +358,11 @@ create_evdev_handler(struct udev_device *ud) #ifdef HAVE_SYSCTLBYNAME found_values: #endif + if (devnum != 0) { + udev_list_insertf(udev_device_get_properties_list(ud), + "DEVNUM", "%" PRIu64, devnum); + } + /* Derived from EvdevProbe() function of xf86-input-evdev driver */ has_keys = bit_find(key_bits, 0, BTN_MISC); has_buttons = bit_find(key_bits, BTN_MISC, BTN_JOYSTICK); diff --git a/udev-device.c b/udev-device.c index da81d1e..1ef89a5 100644 --- a/udev-device.c +++ b/udev-device.c @@ -439,8 +439,20 @@ udev_device_get_devnum(struct udev_device *ud) { const char *devpath; struct stat st; + const char *dn; TRC("(%p) %s", ud, ud->syspath); + + /* + * If a DEVNUM udev property is set (populated from a kernel + * sysctl by the evdev create handler), trust it. This avoids a + * stat(2) that would fail when the device node is not visible, such as + * in a jail without devfs. + */ + dn = udev_device_get_property_value(ud, "DEVNUM"); + if (dn != NULL) + return ((dev_t)strtoull(dn, NULL, 10)); + devpath = get_devpath_by_syspath(ud->syspath); if (devpath == NULL || stat(devpath, &st) < 0 ||