From a408442adf05ae2261021978449b7996b2a125cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Quentin=20Th=C3=A9bault?= Date: Wed, 13 May 2026 10:34:18 +0900 Subject: [PATCH] evdev: get devnum through sysctl when available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit D56968 evdev: add devnum sysctl (https://reviews.freebsd.org/D56968) makes devnum accessible through the sysctl interface, which can be used from within a jail that does not have access to the input devices through devfs. Use those sysctl values when available and keep the former stat(2) on devfs code path otherwise. Signed-off-by: Quentin Thébault Sponsored-by: Defenso --- udev-dev.c | 17 +++++++++++++++++ udev-device.c | 12 ++++++++++++ 2 files changed, 29 insertions(+) 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 ||