From f1ad44d6884b695bc7497994a840769610a07870 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 17 Mar 2025 11:19:05 +0900 Subject: [PATCH 1/6] udev-builtin: align builtins table --- src/udev/udev-builtin.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/udev/udev-builtin.c b/src/udev/udev-builtin.c index fd4b23c1cc..8df25e1603 100644 --- a/src/udev/udev-builtin.c +++ b/src/udev/udev-builtin.c @@ -12,24 +12,24 @@ static const UdevBuiltin *const builtins[_UDEV_BUILTIN_MAX] = { #if HAVE_BLKID - [UDEV_BUILTIN_BLKID] = &udev_builtin_blkid, + [UDEV_BUILTIN_BLKID] = &udev_builtin_blkid, #endif - [UDEV_BUILTIN_BTRFS] = &udev_builtin_btrfs, + [UDEV_BUILTIN_BTRFS] = &udev_builtin_btrfs, [UDEV_BUILTIN_FACTORY_RESET] = &udev_builtin_factory_reset, - [UDEV_BUILTIN_HWDB] = &udev_builtin_hwdb, - [UDEV_BUILTIN_INPUT_ID] = &udev_builtin_input_id, - [UDEV_BUILTIN_KEYBOARD] = &udev_builtin_keyboard, + [UDEV_BUILTIN_HWDB] = &udev_builtin_hwdb, + [UDEV_BUILTIN_INPUT_ID] = &udev_builtin_input_id, + [UDEV_BUILTIN_KEYBOARD] = &udev_builtin_keyboard, #if HAVE_KMOD - [UDEV_BUILTIN_KMOD] = &udev_builtin_kmod, + [UDEV_BUILTIN_KMOD] = &udev_builtin_kmod, #endif - [UDEV_BUILTIN_NET_DRIVER] = &udev_builtin_net_driver, - [UDEV_BUILTIN_NET_ID] = &udev_builtin_net_id, - [UDEV_BUILTIN_NET_LINK] = &udev_builtin_net_setup_link, - [UDEV_BUILTIN_PATH_ID] = &udev_builtin_path_id, + [UDEV_BUILTIN_NET_DRIVER] = &udev_builtin_net_driver, + [UDEV_BUILTIN_NET_ID] = &udev_builtin_net_id, + [UDEV_BUILTIN_NET_LINK] = &udev_builtin_net_setup_link, + [UDEV_BUILTIN_PATH_ID] = &udev_builtin_path_id, #if HAVE_ACL - [UDEV_BUILTIN_UACCESS] = &udev_builtin_uaccess, + [UDEV_BUILTIN_UACCESS] = &udev_builtin_uaccess, #endif - [UDEV_BUILTIN_USB_ID] = &udev_builtin_usb_id, + [UDEV_BUILTIN_USB_ID] = &udev_builtin_usb_id, }; void udev_builtin_init(void) { From 80ffdb8d549f89e1d59d859ce10bbebed94cc6bb Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 17 Mar 2025 12:03:12 +0900 Subject: [PATCH 2/6] udev-builtin: add missing UDEV_RELOAD_BUILTIN_FACTORY_RESET --- src/udev/udev-def.h | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/udev/udev-def.h b/src/udev/udev-def.h index 4064b25f57..d01d8d9875 100644 --- a/src/udev/udev-def.h +++ b/src/udev/udev-def.h @@ -61,25 +61,26 @@ typedef enum UdevBuiltinCommand { typedef enum UdevReloadFlags { #if HAVE_BLKID - UDEV_RELOAD_BUILTIN_BLKID = 1u << UDEV_BUILTIN_BLKID, + UDEV_RELOAD_BUILTIN_BLKID = 1u << UDEV_BUILTIN_BLKID, #endif - UDEV_RELOAD_BUILTIN_BTRFS = 1u << UDEV_BUILTIN_BTRFS, - UDEV_RELOAD_BUILTIN_HWDB = 1u << UDEV_BUILTIN_HWDB, - UDEV_RELOAD_BUILTIN_INPUT_ID = 1u << UDEV_BUILTIN_INPUT_ID, - UDEV_RELOAD_BUILTIN_KEYBOARD = 1u << UDEV_BUILTIN_KEYBOARD, + UDEV_RELOAD_BUILTIN_BTRFS = 1u << UDEV_BUILTIN_BTRFS, + UDEV_RELOAD_BUILTIN_FACTORY_RESET = 1u << UDEV_BUILTIN_FACTORY_RESET, + UDEV_RELOAD_BUILTIN_HWDB = 1u << UDEV_BUILTIN_HWDB, + UDEV_RELOAD_BUILTIN_INPUT_ID = 1u << UDEV_BUILTIN_INPUT_ID, + UDEV_RELOAD_BUILTIN_KEYBOARD = 1u << UDEV_BUILTIN_KEYBOARD, #if HAVE_KMOD - UDEV_RELOAD_BUILTIN_KMOD = 1u << UDEV_BUILTIN_KMOD, + UDEV_RELOAD_BUILTIN_KMOD = 1u << UDEV_BUILTIN_KMOD, #endif - UDEV_RELOAD_BUILTIN_DRIVER = 1u << UDEV_BUILTIN_NET_DRIVER, - UDEV_RELOAD_BUILTIN_NET_ID = 1u << UDEV_BUILTIN_NET_ID, - UDEV_RELOAD_BUILTIN_NET_LINK = 1u << UDEV_BUILTIN_NET_LINK, - UDEV_RELOAD_BUILTIN_PATH_ID = 1u << UDEV_BUILTIN_PATH_ID, + UDEV_RELOAD_BUILTIN_DRIVER = 1u << UDEV_BUILTIN_NET_DRIVER, + UDEV_RELOAD_BUILTIN_NET_ID = 1u << UDEV_BUILTIN_NET_ID, + UDEV_RELOAD_BUILTIN_NET_LINK = 1u << UDEV_BUILTIN_NET_LINK, + UDEV_RELOAD_BUILTIN_PATH_ID = 1u << UDEV_BUILTIN_PATH_ID, #if HAVE_ACL - UDEV_RELOAD_BUILTIN_UACCESS = 1u << UDEV_BUILTIN_UACCESS, + UDEV_RELOAD_BUILTIN_UACCESS = 1u << UDEV_BUILTIN_UACCESS, #endif - UDEV_RELOAD_BUILTIN_USB_ID = 1u << UDEV_BUILTIN_USB_ID, - UDEV_RELOAD_KILL_WORKERS = 1u << (_UDEV_BUILTIN_MAX + 0), - UDEV_RELOAD_RULES = 1u << (_UDEV_BUILTIN_MAX + 1), + UDEV_RELOAD_BUILTIN_USB_ID = 1u << UDEV_BUILTIN_USB_ID, + UDEV_RELOAD_KILL_WORKERS = 1u << (_UDEV_BUILTIN_MAX + 0), + UDEV_RELOAD_RULES = 1u << (_UDEV_BUILTIN_MAX + 1), } UdevReloadFlags; /* udev properties are conceptually close to environment variables. Let's validate names, values, and From 73a2912092c8749237932720bbd300486b9a783d Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 17 Mar 2025 12:04:24 +0900 Subject: [PATCH 3/6] udev-builtin: make btrfs builtin command only check arguments when run in test mode --- src/udev/udev-builtin-btrfs.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/udev/udev-builtin-btrfs.c b/src/udev/udev-builtin-btrfs.c index b166b228f3..200b069efa 100644 --- a/src/udev/udev-builtin-btrfs.c +++ b/src/udev/udev-builtin-btrfs.c @@ -19,6 +19,14 @@ static int builtin_btrfs(UdevEvent *event, int argc, char *argv[]) { if (argc != 3 || !streq(argv[1], "ready")) return log_device_error_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Invalid arguments"); + if (strlen(argv[2]) >= sizeof_field(struct btrfs_ioctl_vol_args, name)) + return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Device name too long for BTRFS_IOC_DEVICES_READY call: %s", argv[2]); + + if (event->event_mode != EVENT_UDEV_WORKER) { + log_device_debug(dev, "Running in test mode, skipping execution of 'btrfs' builtin command."); + return 0; + } + _cleanup_close_ int fd = open("/dev/btrfs-control", O_RDWR|O_CLOEXEC|O_NOCTTY); if (fd < 0) { if (ERRNO_IS_DEVICE_ABSENT(errno)) { @@ -33,9 +41,6 @@ static int builtin_btrfs(UdevEvent *event, int argc, char *argv[]) { } struct btrfs_ioctl_vol_args args = {}; - if (strlen(argv[2]) >= sizeof(args.name)) - return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Device name too long for BTRFS_IOC_DEVICES_READY call: %s", argv[2]); - strncpy(args.name, argv[2], sizeof(args.name)-1); r = ioctl(fd, BTRFS_IOC_DEVICES_READY, &args); if (r < 0) From 6cfb5866fef7e7e6dccef9f9a886aec2863f65a0 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 17 Mar 2025 12:18:41 +0900 Subject: [PATCH 4/6] udev-builtin-btrfs: refuse to call for irrelevant device node If btrfs builtin command is called, then check if the specified device node is owned by the device. This also allows the command is called specifying any device node. --- src/udev/udev-builtin-btrfs.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/udev/udev-builtin-btrfs.c b/src/udev/udev-builtin-btrfs.c index 200b069efa..a1238f1e1b 100644 --- a/src/udev/udev-builtin-btrfs.c +++ b/src/udev/udev-builtin-btrfs.c @@ -16,11 +16,19 @@ static int builtin_btrfs(UdevEvent *event, int argc, char *argv[]) { sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev); int r; - if (argc != 3 || !streq(argv[1], "ready")) - return log_device_error_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Invalid arguments"); + if (!IN_SET(argc, 2, 3) || !streq(argv[1], "ready")) + return log_device_error_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Invalid arguments."); - if (strlen(argv[2]) >= sizeof_field(struct btrfs_ioctl_vol_args, name)) - return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Device name too long for BTRFS_IOC_DEVICES_READY call: %s", argv[2]); + const char *node; + r = sd_device_get_devname(dev, &node); + if (r < 0) + return log_device_error_errno(dev, r, "Failed to get device node: %m"); + + if (argc == 3 && !streq(argv[2], node)) + return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Device node '%s' is not owned by the device, it must be '%s'.", argv[2], node); + + if (strlen(node) >= sizeof_field(struct btrfs_ioctl_vol_args, name)) + return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Device name too long for BTRFS_IOC_DEVICES_READY call: %s", node); if (event->event_mode != EVENT_UDEV_WORKER) { log_device_debug(dev, "Running in test mode, skipping execution of 'btrfs' builtin command."); @@ -41,7 +49,7 @@ static int builtin_btrfs(UdevEvent *event, int argc, char *argv[]) { } struct btrfs_ioctl_vol_args args = {}; - strncpy(args.name, argv[2], sizeof(args.name)-1); + strncpy(args.name, node, sizeof(args.name)-1); r = ioctl(fd, BTRFS_IOC_DEVICES_READY, &args); if (r < 0) return log_device_debug_errno(dev, errno, "Failed to call BTRFS_IOC_DEVICES_READY: %m"); From 6f2f4ceadfa06c0d959293b341684e431c9c007d Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 17 Mar 2025 11:24:14 +0900 Subject: [PATCH 5/6] shell-completion: add factory_reset udev builtin command --- shell-completion/bash/udevadm | 2 +- shell-completion/zsh/_udevadm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/shell-completion/bash/udevadm b/shell-completion/bash/udevadm index 34b24eccb8..f1d907aec8 100644 --- a/shell-completion/bash/udevadm +++ b/shell-completion/bash/udevadm @@ -110,7 +110,7 @@ _udevadm() { ) local verbs=(info trigger settle control monitor test-builtin test verify cat wait lock) - local builtins=(blkid btrfs hwdb input_id keyboard kmod net_driver net_id net_setup_link path_id uaccess usb_id) + local builtins=(blkid btrfs factory_reset hwdb input_id keyboard kmod net_driver net_id net_setup_link path_id uaccess usb_id) for ((i=0; i < COMP_CWORD; i++)); do if __contains_word "${COMP_WORDS[i]}" "${verbs[@]}"; then diff --git a/shell-completion/zsh/_udevadm b/shell-completion/zsh/_udevadm index 71f75a549c..685dece055 100644 --- a/shell-completion/zsh/_udevadm +++ b/shell-completion/zsh/_udevadm @@ -103,7 +103,7 @@ _udevadm_test-builtin(){ '(- *)'{-h,--help}'[Print help]' \ '(- *)'{-V,--version}'[Print version of the program]' \ '--action=[The action string.]:actions:(add change remove move online offline bind unbind)' \ - '*::builtins:(blkid btrfs hwdb input_id net_driver net_id net_setup_link kmod path_id uaccess usb_id)' + '*::builtins:(blkid btrfs factory_reset hwdb input_id keyboard kmod net_driver net_id net_setup_link path_id uaccess usb_id)' elif (( CURRENT == 3 )); then _arguments \ '--action=[The action string.]:actions:(add change remove move online offline bind unbind)' \ From 8b75e15a94a68a886b8ba955a47e91863db5b565 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 17 Mar 2025 12:04:52 +0900 Subject: [PATCH 6/6] TEST-17-UDEV: add more test cases for udev builtins --- test/units/TEST-17-UDEV.10.sh | 52 ++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/test/units/TEST-17-UDEV.10.sh b/test/units/TEST-17-UDEV.10.sh index 796d8dc5d2..d7e69ef673 100755 --- a/test/units/TEST-17-UDEV.10.sh +++ b/test/units/TEST-17-UDEV.10.sh @@ -159,26 +159,18 @@ udevadm test --json=short /sys/class/net/$netdev | jq . >/dev/null udevadm test --json=help udevadm test -h -# udevadm test-builtin path_id "$loopdev" -udevadm test-builtin net_id /sys/class/net/$netdev -udevadm test-builtin net_id "$(systemd-escape -p --suffix device /sys/devices/virtual/net/$netdev)" -udevadm test-builtin -a add net_id /sys/class/net/$netdev -udevadm test-builtin -a remove net_id /sys/class/net/$netdev -udevadm test-builtin -a change net_id /sys/class/net/$netdev -udevadm test-builtin -a move net_id /sys/class/net/$netdev -udevadm test-builtin -a online net_id /sys/class/net/$netdev -udevadm test-builtin -a offline net_id /sys/class/net/$netdev -udevadm test-builtin -a bind net_id /sys/class/net/$netdev -udevadm test-builtin -a unbind net_id /sys/class/net/$netdev -udevadm test-builtin -a help net_id /sys/class/net/$netdev -udevadm test-builtin net_setup_link /sys/class/net/$netdev +# Builtins +(! udevadm test-builtin aaaaa /dev/null) udevadm test-builtin blkid "$loopdev" -udevadm test-builtin input_id /sys/class/net/$netdev -udevadm test-builtin keyboard /dev/null -# udevadm test-builtin kmod /sys/class/net/$netdev -udevadm test-builtin uaccess /dev/null -# udevadm test-builtin usb_id dev/null -(! udevadm test-builtin hello /sys/class/net/$netdev) +(! udevadm test-builtin "btrfs" "$loopdev") +(! udevadm test-builtin "btrfs aaaaa" "$loopdev") +(! udevadm test-builtin "btrfs ready aaa" "$loopdev") +udevadm test-builtin "btrfs ready" "$loopdev" +udevadm test-builtin "btrfs ready $loopdev" "$loopdev" +(! udevadm test-builtin factory_reset "$loopdev") +(! udevadm test-builtin "factory_reset aaa" "$loopdev") +udevadm test-builtin "factory_reset status" "$loopdev" + # systemd-hwdb update is extremely slow when combined with sanitizers and run # in a VM without acceleration, so let's just skip the one particular test # if we detect this combination @@ -199,6 +191,28 @@ EOF systemd-hwdb update fi +udevadm test-builtin input_id /dev/null +udevadm test-builtin keyboard /dev/null +udevadm test-builtin kmod /dev/null +udevadm test-builtin net_driver /sys/class/net/$netdev | grep -F 'ID_NET_DRIVER=dummy' +(! udevadm test-builtin net_driver /dev/null) +udevadm test-builtin net_id /sys/class/net/$netdev +udevadm test-builtin net_id "$(systemd-escape -p --suffix device /sys/devices/virtual/net/$netdev)" +(! udevadm test-builtin net_id /dev/null) +udevadm test-builtin -a add net_id /sys/class/net/$netdev +udevadm test-builtin -a remove net_id /sys/class/net/$netdev +udevadm test-builtin -a change net_id /sys/class/net/$netdev +udevadm test-builtin -a move net_id /sys/class/net/$netdev +udevadm test-builtin -a online net_id /sys/class/net/$netdev +udevadm test-builtin -a offline net_id /sys/class/net/$netdev +udevadm test-builtin -a bind net_id /sys/class/net/$netdev +udevadm test-builtin -a unbind net_id /sys/class/net/$netdev +udevadm test-builtin -a help net_id /sys/class/net/$netdev +udevadm test-builtin net_setup_link /sys/class/net/$netdev +(! udevadm net_setup_link /dev/null) +(! udevadm test-builtin path_id /dev/null) +udevadm test-builtin uaccess /dev/null +(! udevadm test-builtin usb_id /dev/null) udevadm trigger udevadm trigger /dev/null