diff --git a/src/test/meson.build b/src/test/meson.build index 34dedb4f96..2e003f1fd2 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -640,18 +640,6 @@ tests += [ libacl], '', 'manual', '-DLOG_REALM=LOG_REALM_UDEV'], - [['src/test/test-udev-build-argv.c'], - [libudev_core, - libudev_static, - libsystemd_network, - libshared], - [threads, - librt, - libblkid, - libkmod, - libacl], - '', '', '-DLOG_REALM=LOG_REALM_UDEV'], - [['src/test/test-id128.c'], [], []], diff --git a/src/test/test-udev-build-argv.c b/src/test/test-udev-build-argv.c deleted file mode 100644 index c71c706e2e..0000000000 --- a/src/test/test-udev-build-argv.c +++ /dev/null @@ -1,78 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ - -#include "alloc-util.h" -#include "string-util.h" -#include "strv.h" -#include "tests.h" -#include "udev.h" - -static void test_udev_build_argv_one(const char *c) { - _cleanup_strv_free_ char **a = NULL; - _cleanup_free_ char *arg = NULL; - char *argv[128], **p; - int argc; - size_t i; - - assert_se(a = strv_split_full(c, NULL, SPLIT_QUOTES | SPLIT_RELAX)); - - assert_se(arg = strdup(c)); - assert_se(udev_build_argv(arg, &argc, argv) >= 0); - - log_info("command: %s", c); - - i = 0; - log_info("strv_split:"); - STRV_FOREACH(p, a) - log_info("argv[%zu] = '%s'", i++, *p); - - i = 0; - log_info("udev_build_argv:"); - STRV_FOREACH(p, argv) - log_info("argv[%zu] = '%s'", i++, *p); - - assert_se(strv_equal(argv, a)); - assert_se(argc == (int) strv_length(a)); - -} - -static void test_udev_build_argv(void) { - test_udev_build_argv_one("one two three"); - test_udev_build_argv_one("one 'two three ' \" four five \" 'aaa bbb "); - test_udev_build_argv_one("/bin/echo -e \\101"); - test_udev_build_argv_one("/bin/echo -n special-device"); - test_udev_build_argv_one("/bin/echo -n special-device"); - test_udev_build_argv_one("/bin/echo test"); - test_udev_build_argv_one("/bin/echo -n test-%b"); - test_udev_build_argv_one("/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9"); - test_udev_build_argv_one("/bin/sh -c 'echo foo3 foo4 foo5 foo6 foo7 foo8 foo9 | sed s/foo9/bar9/'"); - test_udev_build_argv_one("/bin/echo -n 'foo3 foo4' 'foo5 foo6 foo7 foo8'"); - test_udev_build_argv_one("/bin/sh -c 'printf %%s \\\"foo1 foo2\\\" | grep \\\"foo1 foo2\\\"'"); - test_udev_build_argv_one("/bin/sh -c \\\"printf %%s 'foo1 foo2' | grep 'foo1 foo2'\\\""); - test_udev_build_argv_one("/bin/sh -c 'printf \\\"%%s %%s\\\" \\\"foo1 foo2\\\" \\\"foo3\\\"| grep \\\"foo1 foo2\\\"'"); - test_udev_build_argv_one("/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9"); - test_udev_build_argv_one("/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9"); - test_udev_build_argv_one("/bin/echo -n foo"); - test_udev_build_argv_one("/bin/echo -n usb-%b"); - test_udev_build_argv_one("/bin/echo -n scsi-%b"); - test_udev_build_argv_one("/bin/echo -n foo-%b"); - test_udev_build_argv_one("/bin/echo test"); - test_udev_build_argv_one("/bin/echo symlink test this"); - test_udev_build_argv_one("/bin/echo symlink test this"); - test_udev_build_argv_one("/bin/echo link test this"); - test_udev_build_argv_one("/bin/echo -n node link1 link2"); - test_udev_build_argv_one("/bin/echo -n node link1 link2 link3 link4"); - test_udev_build_argv_one("/usr/bin/test -b %N"); - test_udev_build_argv_one("/bin/echo -e name; (/usr/bin/badprogram)"); - test_udev_build_argv_one("/bin/echo -e \\xc3\\xbcber"); - test_udev_build_argv_one("/bin/echo -e \\xef\\xe8garbage"); - test_udev_build_argv_one("/bin/echo 1 1 0400"); - test_udev_build_argv_one("/bin/echo 0 0 0400letsdoabuffferoverflow0123456789012345789012345678901234567890"); -} - -int main(int argc, char *argv[]) { - test_setup_logging(LOG_DEBUG); - - test_udev_build_argv(); - - return 0; -} diff --git a/src/udev/meson.build b/src/udev/meson.build index aba50eb6b7..53d65f99f2 100644 --- a/src/udev/meson.build +++ b/src/udev/meson.build @@ -19,12 +19,16 @@ systemd_udevd_sources = files('udevd.c') libudev_core_sources = ''' udev.h - udev-event.c - udev-watch.c - udev-node.c - udev-rules.c udev-ctrl.c + udev-ctrl.h + udev-event.c + udev-node.c + udev-node.h + udev-rules.c + udev-watch.c + udev-watch.h udev-builtin.c + udev-builtin.h udev-builtin-btrfs.c udev-builtin-hwdb.c udev-builtin-input_id.c diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c index 202efda3fe..a0da293b55 100644 --- a/src/udev/udev-builtin-blkid.c +++ b/src/udev/udev-builtin-blkid.c @@ -23,7 +23,8 @@ #include "gpt.h" #include "parse-util.h" #include "string-util.h" -#include "udev.h" +#include "strxcpyx.h" +#include "udev-builtin.h" static void print_property(struct udev_device *dev, bool test, const char *name, const char *value) { char s[256]; diff --git a/src/udev/udev-builtin-btrfs.c b/src/udev/udev-builtin-btrfs.c index 2e8535598d..fa6c352c30 100644 --- a/src/udev/udev-builtin-btrfs.c +++ b/src/udev/udev-builtin-btrfs.c @@ -11,7 +11,9 @@ #include "fd-util.h" #include "missing.h" #include "string-util.h" -#include "udev.h" +#include "strxcpyx.h" +#include "udev-builtin.h" +#include "util.h" static int builtin_btrfs(struct udev_device *dev, int argc, char *argv[], bool test) { struct btrfs_ioctl_vol_args args = {}; diff --git a/src/udev/udev-builtin-hwdb.c b/src/udev/udev-builtin-hwdb.c index befb009b5c..1978fddd14 100644 --- a/src/udev/udev-builtin-hwdb.c +++ b/src/udev/udev-builtin-hwdb.c @@ -9,9 +9,10 @@ #include "alloc-util.h" #include "hwdb-util.h" +#include "libudev-private.h" #include "parse-util.h" #include "string-util.h" -#include "udev.h" +#include "udev-builtin.h" static sd_hwdb *hwdb; diff --git a/src/udev/udev-builtin-input_id.c b/src/udev/udev-builtin-input_id.c index f7616987ab..4252a9a696 100644 --- a/src/udev/udev-builtin-input_id.c +++ b/src/udev/udev-builtin-input_id.c @@ -19,7 +19,7 @@ #include "missing.h" #include "stdio-util.h" #include "string-util.h" -#include "udev.h" +#include "udev-builtin.h" #include "util.h" /* we must use this kernel-compatible implementation */ diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c index 9160a5b5d5..0e026697c1 100644 --- a/src/udev/udev-builtin-keyboard.c +++ b/src/udev/udev-builtin-keyboard.c @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ +#include +#include #include #include #include @@ -10,7 +12,8 @@ #include "parse-util.h" #include "stdio-util.h" #include "string-util.h" -#include "udev.h" +#include "strxcpyx.h" +#include "udev-builtin.h" static const struct key_name *keyboard_lookup_key(const char *str, GPERF_LEN_TYPE len); #include "keyboard-keys-from-name.h" diff --git a/src/udev/udev-builtin-kmod.c b/src/udev/udev-builtin-kmod.c index 9436126dd8..6ed0210ee6 100644 --- a/src/udev/udev-builtin-kmod.c +++ b/src/udev/udev-builtin-kmod.c @@ -13,7 +13,7 @@ #include "module-util.h" #include "string-util.h" -#include "udev.h" +#include "udev-builtin.h" static struct kmod_ctx *ctx = NULL; diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c index 834172c388..6e46a139f3 100644 --- a/src/udev/udev-builtin-net_id.c +++ b/src/udev/udev-builtin-net_id.c @@ -101,14 +101,18 @@ #include #include +#include "alloc-util.h" #include "dirent-util.h" #include "fd-util.h" #include "fileio.h" #include "fs-util.h" +#include "libudev-private.h" #include "parse-util.h" #include "stdio-util.h" #include "string-util.h" -#include "udev.h" +#include "strv.h" +#include "strxcpyx.h" +#include "udev-builtin.h" #define ONBOARD_INDEX_MAX (16*1024-1) diff --git a/src/udev/udev-builtin-net_setup_link.c b/src/udev/udev-builtin-net_setup_link.c index ca8c16df0a..3384b76dc1 100644 --- a/src/udev/udev-builtin-net_setup_link.c +++ b/src/udev/udev-builtin-net_setup_link.c @@ -4,7 +4,7 @@ #include "libudev-device-internal.h" #include "link-config.h" #include "log.h" -#include "udev.h" +#include "udev-builtin.h" static link_config_ctx *ctx = NULL; diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c index 12c340110f..693b9820b8 100644 --- a/src/udev/udev-builtin-path_id.c +++ b/src/udev/udev-builtin-path_id.c @@ -18,9 +18,11 @@ #include "alloc-util.h" #include "dirent-util.h" #include "fd-util.h" +#include "libudev-private.h" #include "string-util.h" +#include "strv.h" #include "sysexits.h" -#include "udev.h" +#include "udev-builtin.h" _printf_(2,3) static void path_prepend(char **path, const char *fmt, ...) { diff --git a/src/udev/udev-builtin-uaccess.c b/src/udev/udev-builtin-uaccess.c index 4ddd89dbb1..695a411a74 100644 --- a/src/udev/udev-builtin-uaccess.c +++ b/src/udev/udev-builtin-uaccess.c @@ -6,13 +6,14 @@ #include #include #include +#include #include "sd-login.h" #include "login-util.h" #include "logind-acl.h" -#include "udev.h" -#include "util.h" +#include "log.h" +#include "udev-builtin.h" static int builtin_uaccess(struct udev_device *dev, int argc, char *argv[], bool test) { int r; diff --git a/src/udev/udev-builtin-usb_id.c b/src/udev/udev-builtin-usb_id.c index 97548e92ed..aaa0636493 100644 --- a/src/udev/udev-builtin-usb_id.c +++ b/src/udev/udev-builtin-usb_id.c @@ -17,8 +17,9 @@ #include "alloc-util.h" #include "fd-util.h" +#include "libudev-private.h" #include "string-util.h" -#include "udev.h" +#include "udev-builtin.h" static void set_usb_iftype(char *to, int if_class_num, size_t len) { const char *type = "generic"; diff --git a/src/udev/udev-builtin.c b/src/udev/udev-builtin.c index 956dc30ed2..6d204a46b3 100644 --- a/src/udev/udev-builtin.c +++ b/src/udev/udev-builtin.c @@ -5,6 +5,7 @@ #include #include "string-util.h" +#include "udev-builtin.h" #include "udev.h" static bool initialized; diff --git a/src/udev/udev-builtin.h b/src/udev/udev-builtin.h new file mode 100644 index 0000000000..0a6dc63ec2 --- /dev/null +++ b/src/udev/udev-builtin.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +#pragma once + +#include + +#include "libudev.h" + +enum udev_builtin_cmd { +#if HAVE_BLKID + UDEV_BUILTIN_BLKID, +#endif + UDEV_BUILTIN_BTRFS, + UDEV_BUILTIN_HWDB, + UDEV_BUILTIN_INPUT_ID, + UDEV_BUILTIN_KEYBOARD, +#if HAVE_KMOD + UDEV_BUILTIN_KMOD, +#endif + UDEV_BUILTIN_NET_ID, + UDEV_BUILTIN_NET_LINK, + UDEV_BUILTIN_PATH_ID, + UDEV_BUILTIN_USB_ID, +#if HAVE_ACL + UDEV_BUILTIN_UACCESS, +#endif + 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)(void); + void (*exit)(void); + bool (*validate)(void); + bool run_once; +}; + +#if HAVE_BLKID +extern const struct udev_builtin udev_builtin_blkid; +#endif +extern const struct udev_builtin udev_builtin_btrfs; +extern const struct udev_builtin udev_builtin_hwdb; +extern const struct udev_builtin udev_builtin_input_id; +extern const struct udev_builtin udev_builtin_keyboard; +#if HAVE_KMOD +extern const struct udev_builtin udev_builtin_kmod; +#endif +extern const struct udev_builtin udev_builtin_net_id; +extern const struct udev_builtin udev_builtin_net_setup_link; +extern const struct udev_builtin udev_builtin_path_id; +extern const struct udev_builtin udev_builtin_usb_id; +#if HAVE_ACL +extern const struct udev_builtin udev_builtin_uaccess; +#endif + +void udev_builtin_init(void); +void udev_builtin_exit(void); +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(void); +bool udev_builtin_validate(void); +int udev_builtin_add_property(struct udev_device *dev, bool test, const char *key, const char *val); +int udev_builtin_hwdb_lookup(struct udev_device *dev, const char *prefix, const char *modalias, + const char *filter, bool test); diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c index a9b19051bf..64024100fe 100644 --- a/src/udev/udev-ctrl.c +++ b/src/udev/udev-ctrl.c @@ -21,7 +21,8 @@ #include "fd-util.h" #include "format-util.h" #include "socket-util.h" -#include "udev.h" +#include "strxcpyx.h" +#include "udev-ctrl.h" /* wire protocol magic must match */ #define UDEV_CTRL_MAGIC 0xdead1dea diff --git a/src/udev/udev-ctrl.h b/src/udev/udev-ctrl.h new file mode 100644 index 0000000000..87021cb880 --- /dev/null +++ b/src/udev/udev-ctrl.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +#pragma once + +#include "macro.h" + +struct udev_ctrl; +struct udev_ctrl *udev_ctrl_new(void); +struct udev_ctrl *udev_ctrl_new_from_fd(int fd); +int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl); +struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl); +int udev_ctrl_cleanup(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_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); + +DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl*, udev_ctrl_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl_connection*, udev_ctrl_connection_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl_msg*, udev_ctrl_msg_unref); diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index e46cf1563f..f732913d17 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -18,11 +18,15 @@ #include "alloc-util.h" #include "fd-util.h" #include "format-util.h" +#include "libudev-device-internal.h" #include "netlink-util.h" #include "path-util.h" #include "process-util.h" #include "signal-util.h" #include "string-util.h" +#include "udev-builtin.h" +#include "udev-node.h" +#include "udev-watch.h" #include "udev.h" typedef struct Spawn { @@ -697,41 +701,6 @@ static int spawn_wait(struct udev_event *event, return ret; } -int udev_build_argv(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 (IN_SET(pos[0], '\'', '"')) { - /* do not separate quotes or double quotes */ - char delim[2] = { pos[0], '\0' }; - - pos++; - argv[i] = strsep(&pos, delim); - if (pos != NULL) - while (pos[0] == ' ') - pos++; - } else { - argv[i] = strsep(&pos, " "); - if (pos != NULL) - while (pos[0] == ' ') - pos++; - } - i++; - } -out: - argv[i] = NULL; - if (argc) - *argc = i; - return 0; -} - int udev_event_spawn(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec, @@ -834,20 +803,20 @@ void udev_event_execute_rules(struct udev_event *event, udev_device_delete_db(dev); if (major(udev_device_get_devnum(dev)) != 0) - udev_watch_end(dev); + udev_watch_end(dev->device); udev_rules_apply_to_event(rules, event, timeout_usec, timeout_warn_usec, properties_list); if (major(udev_device_get_devnum(dev)) != 0) - udev_node_remove(dev); + udev_node_remove(dev->device); } else { event->dev_db = udev_device_clone_with_db(dev); if (event->dev_db != NULL) { /* disable watch during event processing */ if (major(udev_device_get_devnum(dev)) != 0) - udev_watch_end(event->dev_db); + udev_watch_end(event->dev_db->device); if (major(udev_device_get_devnum(dev)) == 0 && streq(udev_device_get_action(dev), "move")) @@ -882,7 +851,7 @@ void udev_event_execute_rules(struct udev_event *event, /* remove/update possible left-over symlinks from old database entry */ if (event->dev_db != NULL) - udev_node_update_old_links(dev, event->dev_db); + udev_node_update_old_links(dev->device, event->dev_db->device); if (!event->owner_set) event->uid = udev_device_get_devnode_uid(dev); @@ -904,7 +873,7 @@ void udev_event_execute_rules(struct udev_event *event, } apply = streq(udev_device_get_action(dev), "add") || event->owner_set || event->group_set || event->mode_set; - udev_node_add(dev, apply, event->mode, event->uid, event->gid, &event->seclabel_list); + udev_node_add(dev->device, apply, event->mode, event->uid, event->gid, &event->seclabel_list); } /* preserve old, or get new initialization timestamp */ diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c index be253ccefe..7a883564b1 100644 --- a/src/udev/udev-node.c +++ b/src/udev/udev-node.c @@ -9,21 +9,30 @@ #include #include +#include "alloc-util.h" #include "device-nodes.h" +#include "device-private.h" +#include "device-util.h" #include "dirent-util.h" +#include "fd-util.h" #include "format-util.h" #include "fs-util.h" +#include "path-util.h" #include "selinux-util.h" #include "smack-util.h" #include "stdio-util.h" #include "string-util.h" -#include "udev.h" +#include "udev-node.h" -static int node_symlink(struct udev_device *dev, const char *node, const char *slink) { +static int node_symlink(sd_device *dev, const char *node, const char *slink) { _cleanup_free_ char *slink_dirname = NULL, *target = NULL; - char slink_tmp[UTIL_PATH_SIZE + 32]; + const char *id_filename, *slink_tmp; struct stat stats; - int r, err = 0; + int r; + + assert(dev); + assert(node); + assert(slink); slink_dirname = dirname_malloc(slink); if (!slink_dirname) @@ -37,233 +46,283 @@ static int node_symlink(struct udev_device *dev, const char *node, const char *s /* 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)) { - log_error("conflicting device node '%s' found, link to '%s' will not be created", slink, node); - goto exit; + log_error("Conflicting device node '%s' found, link to '%s' will not be created.", slink, node); + return -EOPNOTSUPP; } else if (S_ISLNK(stats.st_mode)) { - char buf[UTIL_PATH_SIZE]; - int len; + char buf[PATH_MAX]; + ssize_t len; len = readlink(slink, buf, sizeof(buf)); - if (len > 0 && len < (int)sizeof(buf)) { + if (len > 0 && len < (ssize_t) sizeof(buf)) { buf[len] = '\0'; if (streq(target, buf)) { - log_debug("preserve already existing symlink '%s' to '%s'", slink, target); + log_debug("Preserve already existing symlink '%s' to '%s'", slink, target); (void) label_fix(slink, LABEL_IGNORE_ENOENT); - utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW); - goto exit; + (void) utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW); + return 0; } } } } else { - log_debug("creating symlink '%s' to '%s'", slink, target); + log_debug("Creating symlink '%s' to '%s'", slink, target); do { - err = mkdir_parents_label(slink, 0755); - if (!IN_SET(err, 0, -ENOENT)) + r = mkdir_parents_label(slink, 0755); + if (!IN_SET(r, 0, -ENOENT)) break; mac_selinux_create_file_prepare(slink, S_IFLNK); - err = symlink(target, slink); - if (err != 0) - err = -errno; + if (symlink(target, slink) < 0) + r = -errno; mac_selinux_create_file_clear(); - } while (err == -ENOENT); - if (err == 0) - goto exit; + } while (r == -ENOENT); + if (r == 0) + return 0; } - log_debug("atomically replace '%s'", slink); - strscpyl(slink_tmp, sizeof(slink_tmp), slink, ".tmp-", udev_device_get_id_filename(dev), NULL); - unlink(slink_tmp); + log_debug("Atomically replace '%s'", slink); + r = device_get_id_filename(dev, &id_filename); + if (r < 0) + return log_error_errno(r, "Failed to get id_filename: %m"); + slink_tmp = strjoina(slink, ".tmp-", id_filename); + (void) unlink(slink_tmp); do { - err = mkdir_parents_label(slink_tmp, 0755); - if (!IN_SET(err, 0, -ENOENT)) + r = mkdir_parents_label(slink_tmp, 0755); + if (!IN_SET(r, 0, -ENOENT)) break; mac_selinux_create_file_prepare(slink_tmp, S_IFLNK); - err = symlink(target, slink_tmp); - if (err != 0) - err = -errno; + if (symlink(target, slink_tmp) < 0) + r = -errno; mac_selinux_create_file_clear(); - } while (err == -ENOENT); - if (err != 0) { - log_error_errno(errno, "symlink '%s' '%s' failed: %m", target, slink_tmp); - goto exit; + } while (r == -ENOENT); + if (r < 0) + return log_error_errno(r, "Failed to create symlink '%s' to '%s': %m", slink_tmp, target); + + if (rename(slink_tmp, slink) < 0) { + r = log_error_errno(errno, "Failed to rename '%s' to '%s' failed: %m", slink_tmp, slink); + (void) unlink(slink_tmp); } - err = rename(slink_tmp, slink); - if (err != 0) { - log_error_errno(errno, "rename '%s' '%s' failed: %m", slink_tmp, slink); - unlink(slink_tmp); - } -exit: - return err; + + return r; } /* 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) { - DIR *dir; +static int link_find_prioritized(sd_device *dev, bool add, const char *stackdir, char **ret) { + _cleanup_closedir_ DIR *dir = NULL; + _cleanup_free_ char *target = NULL; struct dirent *dent; - int priority = 0; - const char *target = NULL; + int r, priority = 0; + + assert(!add || dev); + assert(stackdir); + assert(ret); if (add) { - priority = udev_device_get_devlink_priority(dev); - strscpy(buf, bufsize, udev_device_get_devnode(dev)); - target = buf; + const char *devnode; + + r = device_get_devlink_priority(dev, &priority); + if (r < 0) + return r; + + r = sd_device_get_devname(dev, &devnode); + if (r < 0) + return r; + + target = strdup(devnode); + if (!target) + return -ENOMEM; } dir = opendir(stackdir); - if (dir == NULL) - return target; + if (!dir) { + if (target) { + *ret = TAKE_PTR(target); + return 0; + } + + return -errno; + } + FOREACH_DIRENT_ALL(dent, dir, break) { - struct udev_device *dev_db; + _cleanup_(sd_device_unrefp) sd_device *dev_db = NULL; + const char *devnode, *id_filename; + int db_prio = 0; if (dent->d_name[0] == '\0') break; if (dent->d_name[0] == '.') continue; - log_debug("found '%s' claiming '%s'", dent->d_name, stackdir); + log_debug("Found '%s' claiming '%s'", dent->d_name, stackdir); - /* did we find ourself? */ - if (streq(dent->d_name, udev_device_get_id_filename(dev))) + if (device_get_id_filename(dev, &id_filename) < 0) continue; - dev_db = udev_device_new_from_device_id(NULL, dent->d_name); - if (dev_db != NULL) { - const char *devnode; + /* did we find ourself? */ + if (streq(dent->d_name, id_filename)) + continue; - devnode = udev_device_get_devnode(dev_db); - if (devnode != NULL) { - if (target == NULL || udev_device_get_devlink_priority(dev_db) > priority) { - log_debug("'%s' claims priority %i for '%s'", - udev_device_get_syspath(dev_db), udev_device_get_devlink_priority(dev_db), stackdir); - priority = udev_device_get_devlink_priority(dev_db); - strscpy(buf, bufsize, devnode); - target = buf; - } - } - udev_device_unref(dev_db); + if (sd_device_new_from_device_id(&dev_db, dent->d_name) < 0) + continue; + + if (sd_device_get_devname(dev_db, &devnode) < 0) + continue; + + if (device_get_devlink_priority(dev_db, &db_prio) < 0) + continue; + + if (target && db_prio <= priority) + continue; + + if (DEBUG_LOGGING) { + const char *syspath = NULL; + + (void) sd_device_get_syspath(dev_db, &syspath); + log_debug("Device '%s' claims priority %i for '%s'", strnull(syspath), db_prio, stackdir); } + + r = free_and_strdup(&target, devnode); + if (r < 0) + return r; + priority = db_prio; } - closedir(dir); - return target; + + *ret = TAKE_PTR(target); + return 0; } /* manage "stack of names" with possibly specified device priorities */ -static void link_update(struct udev_device *dev, const char *slink, bool add) { - 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]; +static int link_update(sd_device *dev, const char *slink, bool add) { + _cleanup_free_ char *target = NULL, *filename = NULL, *dirname = NULL; + char name_enc[PATH_MAX]; + const char *id_filename; + int r; + + assert(dev); + assert(slink); + + r = device_get_id_filename(dev, &id_filename); + if (r < 0) + return log_debug_errno(r, "Failed to get id_filename: %m"); util_path_encode(slink + STRLEN("/dev"), name_enc, sizeof(name_enc)); - strscpyl(dirname, sizeof(dirname), "/run/udev/links/", name_enc, NULL); - strscpyl(filename, sizeof(filename), dirname, "/", udev_device_get_id_filename(dev), NULL); + dirname = path_join(NULL, "/run/udev/links/", name_enc); + if (!dirname) + return log_oom(); + filename = path_join(NULL, dirname, id_filename); + if (!filename) + return log_oom(); if (!add && unlink(filename) == 0) - rmdir(dirname); + (void) rmdir(dirname); - target = link_find_prioritized(dev, add, dirname, buf, sizeof(buf)); - if (target == NULL) { - log_debug("no reference left, remove '%s'", slink); + r = link_find_prioritized(dev, add, dirname, &target); + if (r < 0) { + log_debug("No reference left, removing '%s'", slink); if (unlink(slink) == 0) - rmdir_parents(slink, "/"); + (void) rmdir_parents(slink, "/"); } else { - log_debug("creating link '%s' to '%s'", slink, target); - node_symlink(dev, target, slink); + log_debug("Creating link '%s' to '%s'", slink, target); + (void) node_symlink(dev, target, slink); } - if (add) { - int err; - + if (add) do { - int fd; + _cleanup_close_ int fd = -1; - err = mkdir_parents(filename, 0755); - if (!IN_SET(err, 0, -ENOENT)) + r = mkdir_parents(filename, 0755); + if (!IN_SET(r, 0, -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); - } + if (fd < 0) + r = -errno; + } while (r == -ENOENT); + + return r; } -void udev_node_update_old_links(struct udev_device *dev, struct udev_device *dev_old) { - struct udev_list_entry *list_entry; +int udev_node_update_old_links(sd_device *dev, sd_device *dev_old) { + const char *name, *devpath; + int r; + + assert(dev); + assert(dev_old); + + r = sd_device_get_devpath(dev, &devpath); + if (r < 0) + return log_debug_errno(r, "Failed to get devpath: %m"); /* 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; + FOREACH_DEVICE_DEVLINK(dev_old, name) { + const char *name_current; + bool found = false; /* 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); - + FOREACH_DEVICE_DEVLINK(dev, name_current) if (streq(name, name_current)) { - found = 1; + found = true; break; } - } + if (found) continue; - log_debug("update old name, '%s' no longer belonging to '%s'", - name, udev_device_get_devpath(dev)); + log_debug("Updating old name, '%s' no longer belonging to '%s'", + name, devpath); link_update(dev, name, false); } + + return 0; } -static int node_permissions_apply(struct udev_device *dev, bool apply, +static int node_permissions_apply(sd_device *dev, bool apply, mode_t mode, uid_t uid, gid_t gid, struct udev_list *seclabel_list) { - const char *devnode = udev_device_get_devnode(dev); - dev_t devnum = udev_device_get_devnum(dev); - struct stat stats; + const char *devnode, *subsystem, *id_filename = NULL; struct udev_list_entry *entry; - int err = 0; + struct stat stats; + dev_t devnum; + int r = 0; - if (streq(udev_device_get_subsystem(dev), "block")) + assert(dev); + + r = sd_device_get_devname(dev, &devnode); + if (r < 0) + return log_debug_errno(r, "Failed to get devname: %m"); + r = sd_device_get_subsystem(dev, &subsystem); + if (r < 0) + return log_debug_errno(r, "Failed to get subsystem: %m"); + r = sd_device_get_devnum(dev, &devnum); + if (r < 0) + return log_debug_errno(r, "Failed to get devnum: %m"); + (void) device_get_id_filename(dev, &id_filename); + + if (streq(subsystem, "block")) mode |= S_IFBLK; else mode |= S_IFCHR; - if (lstat(devnode, &stats) != 0) { - err = log_debug_errno(errno, "cannot stat() node '%s' (%m)", devnode); - goto out; - } + if (lstat(devnode, &stats) < 0) + return log_debug_errno(errno, "cannot stat() node '%s' (%m)", devnode); - if (((stats.st_mode & S_IFMT) != (mode & S_IFMT)) || (stats.st_rdev != devnum)) { - err = -EEXIST; - log_debug("found node '%s' with non-matching devnum %s, skip handling", - udev_device_get_devnode(dev), udev_device_get_id_filename(dev)); - goto out; - } + if (((stats.st_mode & S_IFMT) != (mode & S_IFMT)) || (stats.st_rdev != devnum)) + return log_debug_errno(EEXIST, "Found node '%s' with non-matching devnum %s, skip handling", + devnode, id_filename); if (apply) { - bool selinux = false; - bool smack = false; + bool selinux = false, smack = false; if ((stats.st_mode & 0777) != (mode & 0777) || stats.st_uid != uid || stats.st_gid != gid) { - log_debug("set permissions %s, %#o, uid=%u, gid=%u", devnode, mode, uid, gid); - err = chmod(devnode, mode); - if (err < 0) - log_warning_errno(errno, "setting mode of %s to %#o failed: %m", devnode, mode); - err = chown(devnode, uid, gid); - if (err < 0) - log_warning_errno(errno, "setting owner of %s to uid=%u, gid=%u failed: %m", devnode, uid, gid); - } else { - log_debug("preserve permissions %s, %#o, uid=%u, gid=%u", devnode, mode, uid, gid); - } + log_debug("Setting permissions %s, %#o, uid=%u, gid=%u", devnode, mode, uid, gid); + if (chmod(devnode, mode) < 0) + r = log_warning_errno(errno, "Failed to set mode of %s to %#o: %m", devnode, mode); + if (chown(devnode, uid, gid) < 0) + r = log_warning_errno(errno, "Failed to set owner of %s to uid=%u, gid=%u: %m", devnode, uid, gid); + } else + log_debug("Preserve permissions of %s, %#o, uid=%u, gid=%u", devnode, mode, uid, gid); /* apply SECLABEL{$module}=$label */ udev_list_entry_foreach(entry, udev_list_get_entry(seclabel_list)) { const char *name, *label; - int r; + int q; name = udev_list_entry_get_name(entry); label = udev_list_entry_get_value(entry); @@ -271,18 +330,18 @@ static int node_permissions_apply(struct udev_device *dev, bool apply, if (streq(name, "selinux")) { selinux = true; - r = mac_selinux_apply(devnode, label); - if (r < 0) - log_error_errno(r, "SECLABEL: failed to set SELinux label '%s': %m", label); + q = mac_selinux_apply(devnode, label); + if (q < 0) + log_error_errno(q, "SECLABEL: failed to set SELinux label '%s': %m", label); else log_debug("SECLABEL: set SELinux label '%s'", label); } else if (streq(name, "smack")) { smack = true; - r = mac_smack_apply(devnode, SMACK_ATTR_ACCESS, label); - if (r < 0) - log_error_errno(r, "SECLABEL: failed to set SMACK label '%s': %m", label); + q = mac_smack_apply(devnode, SMACK_ATTR_ACCESS, label); + if (q < 0) + log_error_errno(q, "SECLABEL: failed to set SMACK label '%s': %m", label); else log_debug("SECLABEL: set SMACK label '%s'", label); @@ -294,49 +353,99 @@ static int node_permissions_apply(struct udev_device *dev, bool apply, if (!selinux) (void) mac_selinux_fix(devnode, LABEL_IGNORE_ENOENT); if (!smack) - mac_smack_apply(devnode, SMACK_ATTR_ACCESS, NULL); + (void) mac_smack_apply(devnode, SMACK_ATTR_ACCESS, NULL); } /* always update timestamp when we re-use the node, like on media change events */ - utimensat(AT_FDCWD, devnode, NULL, 0); -out: - return err; + (void) utimensat(AT_FDCWD, devnode, NULL, 0); + + return r; } -void udev_node_add(struct udev_device *dev, bool apply, - mode_t mode, uid_t uid, gid_t gid, - struct udev_list *seclabel_list) { - char filename[DEV_NUM_PATH_MAX]; - struct udev_list_entry *list_entry; +static int xsprintf_dev_num_path_from_sd_device(sd_device *dev, char **ret) { + char filename[DEV_NUM_PATH_MAX], *s; + const char *subsystem; + dev_t devnum; + int r; - log_debug("handling device node '%s', devnum=%s, mode=%#o, uid="UID_FMT", gid="GID_FMT, - udev_device_get_devnode(dev), udev_device_get_id_filename(dev), mode, uid, gid); + assert(ret); - if (node_permissions_apply(dev, apply, mode, uid, gid, seclabel_list) < 0) - return; + r = sd_device_get_subsystem(dev, &subsystem); + if (r < 0) + return r; + + r = sd_device_get_devnum(dev, &devnum); + if (r < 0) + return r; + + xsprintf_dev_num_path(filename, + streq(subsystem, "block") ? "block" : "char", + devnum); + + s = strdup(filename); + if (!s) + return -ENOMEM; + + *ret = s; + return 0; +} + +int udev_node_add(sd_device *dev, bool apply, + mode_t mode, uid_t uid, gid_t gid, + struct udev_list *seclabel_list) { + const char *devnode, *devlink; + _cleanup_free_ char *filename = NULL; + int r; + + assert(dev); + + r = sd_device_get_devname(dev, &devnode); + if (r < 0) + return log_debug_errno(r, "Failed to get devnode: %m"); + + if (DEBUG_LOGGING) { + const char *id_filename = NULL; + + (void) device_get_id_filename(dev, &id_filename); + log_debug("Handling device node '%s', devnum=%s, mode=%#o, uid="UID_FMT", gid="GID_FMT, + devnode, strnull(id_filename), mode, uid, gid); + } + + r = node_permissions_apply(dev, apply, mode, uid, gid, seclabel_list); + if (r < 0) + return r; + + r = xsprintf_dev_num_path_from_sd_device(dev, &filename); + if (r < 0) + return log_debug_errno(r, "Failed to get device path: %m"); /* always add /dev/{block,char}/$major:$minor */ - xsprintf_dev_num_path(filename, - streq(udev_device_get_subsystem(dev), "block") ? "block" : "char", - udev_device_get_devnum(dev)); - node_symlink(dev, udev_device_get_devnode(dev), filename); + (void) node_symlink(dev, devnode, filename); /* create/update symlinks, add symlinks to 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), true); + FOREACH_DEVICE_DEVLINK(dev, devlink) + (void) link_update(dev, devlink, true); + + return 0; } -void udev_node_remove(struct udev_device *dev) { - struct udev_list_entry *list_entry; - char filename[DEV_NUM_PATH_MAX]; +int udev_node_remove(sd_device *dev) { + _cleanup_free_ char *filename = NULL; + const char *devlink; + int r; + + assert(dev); /* 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), false); + FOREACH_DEVICE_DEVLINK(dev, devlink) + (void) link_update(dev, devlink, false); + + r = xsprintf_dev_num_path_from_sd_device(dev, &filename); + if (r < 0) + return log_debug_errno(r, "Failed to get device path: %m"); /* remove /dev/{block,char}/$major:$minor */ - xsprintf_dev_num_path(filename, - streq(udev_device_get_subsystem(dev), "block") ? "block" : "char", - udev_device_get_devnum(dev)); - unlink(filename); + (void) unlink(filename); + + return 0; } diff --git a/src/udev/udev-node.h b/src/udev/udev-node.h new file mode 100644 index 0000000000..868549e492 --- /dev/null +++ b/src/udev/udev-node.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +#pragma once + +#include +#include + +#include "libudev.h" +#include "sd-device.h" + +#include "libudev-private.h" + +int udev_node_add(sd_device *dev, bool apply, + mode_t mode, uid_t uid, gid_t gid, + struct udev_list *seclabel_list); +int udev_node_remove(sd_device *dev); +int udev_node_update_old_links(sd_device *dev, sd_device *dev_old); diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index 76baa0322b..4d87754042 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -28,6 +28,7 @@ #include "string-util.h" #include "strv.h" #include "sysctl-util.h" +#include "udev-builtin.h" #include "udev.h" #include "user-util.h" #include "util.h" diff --git a/src/udev/udev-watch.c b/src/udev/udev-watch.c index 439117181a..d3e4391ee9 100644 --- a/src/udev/udev-watch.c +++ b/src/udev/udev-watch.c @@ -4,136 +4,179 @@ * Copyright © 2009 Scott James Remnant */ -#include -#include -#include #include #include +#include "device-private.h" #include "dirent-util.h" +#include "mkdir.h" #include "stdio-util.h" -#include "udev.h" +#include "udev-watch.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 - */ + * watches for us. */ int udev_watch_init(void) { inotify_fd = inotify_init1(IN_CLOEXEC); if (inotify_fd < 0) - log_error_errno(errno, "inotify_init failed: %m"); + return log_error_errno(errno, "Failed to create inotify descriptor: %m"); + return inotify_fd; } -/* move any old watches directory out of the way, and then restore - * the watches - */ -void udev_watch_restore(void) { - if (inotify_fd < 0) - return; - - if (rename("/run/udev/watch", "/run/udev/watch.old") == 0) { - DIR *dir; - struct dirent *ent; - - dir = opendir("/run/udev/watch.old"); - if (dir == NULL) { - log_error_errno(errno, "unable to open old watches dir /run/udev/watch.old; old watches will not be restored: %m"); - return; - } - - FOREACH_DIRENT_ALL(ent, dir, break) { - char device[UTIL_PATH_SIZE]; - ssize_t len; - struct udev_device *dev; - - if (ent->d_name[0] == '.') - continue; - - len = readlinkat(dirfd(dir), ent->d_name, device, sizeof(device)); - if (len <= 0 || len == (ssize_t)sizeof(device)) - goto unlink; - device[len] = '\0'; - - dev = udev_device_new_from_device_id(NULL, device); - if (dev == NULL) - goto unlink; - - log_debug("restoring old watch on '%s'", udev_device_get_devnode(dev)); - udev_watch_begin(dev); - udev_device_unref(dev); -unlink: - (void) unlinkat(dirfd(dir), ent->d_name, 0); - } - - closedir(dir); - rmdir("/run/udev/watch.old"); - - } else if (errno != ENOENT) - log_error_errno(errno, "unable to move watches dir /run/udev/watch; old watches will not be restored: %m"); -} - -void udev_watch_begin(struct udev_device *dev) { - char filename[sizeof("/run/udev/watch/") + DECIMAL_STR_MAX(int)]; - int wd; +/* Move any old watches directory out of the way, and then restore the watches. */ +int udev_watch_restore(void) { + struct dirent *ent; + DIR *dir; int r; if (inotify_fd < 0) - return; + return log_error_errno(EINVAL, "Invalid inotify descriptor."); - log_debug("adding watch on '%s'", udev_device_get_devnode(dev)); - wd = inotify_add_watch(inotify_fd, udev_device_get_devnode(dev), IN_CLOSE_WRITE); - if (wd < 0) { - log_error_errno(errno, "inotify_add_watch(%d, %s, %o) failed: %m", - inotify_fd, udev_device_get_devnode(dev), IN_CLOSE_WRITE); - return; + if (rename("/run/udev/watch", "/run/udev/watch.old") < 0) { + if (errno != ENOENT) + return log_error_errno(errno, "Failed to move watches directory /run/udev/watch. Old watches will not be restored: %m"); + + return 0; } - xsprintf(filename, "/run/udev/watch/%d", wd); - mkdir_parents(filename, 0755); - unlink(filename); - r = symlink(udev_device_get_id_filename(dev), filename); - if (r < 0) - log_error_errno(errno, "Failed to create symlink %s: %m", filename); + dir = opendir("/run/udev/watch.old"); + if (!dir) + return log_error_errno(errno, "Failed to open old watches directory /run/udev/watch.old. Old watches will not be restored: %m"); - udev_device_set_watch_handle(dev, wd); + FOREACH_DIRENT_ALL(ent, dir, break) { + _cleanup_(sd_device_unrefp) sd_device *dev = NULL; + char device[PATH_MAX]; + ssize_t len; + + if (ent->d_name[0] == '.') + continue; + + len = readlinkat(dirfd(dir), ent->d_name, device, sizeof(device)); + if (len <= 0) { + log_error_errno(errno, "Failed to read link '/run/udev/watch.old/%s', ignoring: %m", ent->d_name); + goto unlink; + } else if (len >= (ssize_t) sizeof(device)) { + log_error("Path specified by link '/run/udev/watch.old/%s' is truncated, ignoring.", ent->d_name); + goto unlink; + } + device[len] = '\0'; + + r = sd_device_new_from_device_id(&dev, device); + if (r < 0) { + log_error_errno(r, "Failed to create sd_device object for '%s', ignoring: %m", device); + goto unlink; + } + + if (DEBUG_LOGGING) { + const char *devnode = NULL; + + (void) sd_device_get_devname(dev, &devnode); + log_debug("Restoring old watch on '%s'", strnull(devnode)); + } + (void) udev_watch_begin(dev); +unlink: + (void) unlinkat(dirfd(dir), ent->d_name, 0); + } + + (void) closedir(dir); + (void) rmdir("/run/udev/watch.old"); + + return 0; } -void udev_watch_end(struct udev_device *dev) { - int wd; - char filename[sizeof("/run/udev/watch/") + DECIMAL_STR_MAX(int)]; +int udev_watch_begin(sd_device *dev) { + char filename[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)]; + const char *devnode, *id_filename; + int wd, r; if (inotify_fd < 0) - return; + return log_error_errno(EINVAL, "Invalid inotify descriptor."); - wd = udev_device_get_watch_handle(dev); + r = sd_device_get_devname(dev, &devnode); + if (r < 0) + return log_error_errno(r, "Failed to get device name: %m"); + + log_debug("Adding watch on '%s'", devnode); + wd = inotify_add_watch(inotify_fd, devnode, IN_CLOSE_WRITE); if (wd < 0) - return; + return log_error_errno(errno, "Failed to add device '%s' to watch: %m", devnode); - log_debug("removing watch on '%s'", udev_device_get_devnode(dev)); - inotify_rm_watch(inotify_fd, wd); + device_set_watch_handle(dev, wd); xsprintf(filename, "/run/udev/watch/%d", wd); - unlink(filename); + r = mkdir_parents(filename, 0755); + if (r < 0) + return log_error_errno(r, "Failed to create parent directory of '%s': %m", filename); + (void) unlink(filename); - udev_device_set_watch_handle(dev, -1); + r = device_get_id_filename(dev, &id_filename); + if (r < 0) + return log_error_errno(r, "Failed to get device id-filename: %m"); + + if (symlink(id_filename, filename) < 0) + return log_error_errno(errno, "Failed to create symlink %s: %m", filename); + + return 0; } -struct udev_device *udev_watch_lookup(int wd) { - char filename[sizeof("/run/udev/watch/") + DECIMAL_STR_MAX(int)]; - char device[UTIL_NAME_SIZE]; - ssize_t len; +int udev_watch_end(sd_device *dev) { + char filename[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)]; + const char *devnode; + int wd, r; - if (inotify_fd < 0 || wd < 0) - return NULL; + if (inotify_fd < 0) + return log_error_errno(EINVAL, "Invalid inotify descriptor."); + + r = device_get_watch_handle(dev, &wd); + if (r == -ENOENT) + return 0; + if (r < 0) + return log_error_errno(r, "Failed to get watch handle for device '%s', ignoring: %m", devnode); + + r = sd_device_get_devname(dev, &devnode); + if (r < 0) + return log_error_errno(r, "Failed to get device name: %m"); + + log_debug("Removing watch on '%s'", devnode); + (void) inotify_rm_watch(inotify_fd, wd); + + xsprintf(filename, "/run/udev/watch/%d", wd); + (void) unlink(filename); + + device_set_watch_handle(dev, -1); + + return 0; +} + +int udev_watch_lookup(int wd, sd_device **ret) { + char filename[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)], device[PATH_MAX]; + ssize_t len; + int r; + + assert(ret); + + if (inotify_fd < 0) + return log_error_errno(EINVAL, "Invalid inotify descriptor."); + + if (wd < 0) + return log_error_errno(EINVAL, "Invalid watch handle."); xsprintf(filename, "/run/udev/watch/%d", wd); len = readlink(filename, device, sizeof(device)); - if (len <= 0 || (size_t)len == sizeof(device)) - return NULL; + if (len <= 0) { + if (errno != ENOENT) + return log_error_errno(errno, "Failed to read link '%s': %m", filename); + return 0; + } else if (len >= (ssize_t) sizeof(device)) + return log_error_errno(ENAMETOOLONG, "Path specified by link '%s' is truncated.", filename); device[len] = '\0'; - return udev_device_new_from_device_id(NULL, device); + r = sd_device_new_from_device_id(ret, device); + if (r < 0) + return log_error_errno(r, "Failed to create sd_device object for '%s': %m", device); + + return 0; } diff --git a/src/udev/udev-watch.h b/src/udev/udev-watch.h new file mode 100644 index 0000000000..24a136d261 --- /dev/null +++ b/src/udev/udev-watch.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +#pragma once + +#include "sd-device.h" + +int udev_watch_init(void); +int udev_watch_restore(void); +int udev_watch_begin(sd_device *dev); +int udev_watch_end(sd_device *dev); +int udev_watch_lookup(int wd, sd_device **ret); diff --git a/src/udev/udev.h b/src/udev/udev.h index b7b2c0420c..09bd54e965 100644 --- a/src/udev/udev.h +++ b/src/udev/udev.h @@ -10,6 +10,7 @@ #include #include "libudev.h" +#include "sd-device.h" #include "sd-netlink.h" #include "label.h" @@ -75,114 +76,7 @@ void udev_event_execute_rules(struct udev_event *event, struct udev_list *properties_list, struct udev_rules *rules); void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec); -int udev_build_argv(char *cmd, int *argc, char *argv[]); - -/* udev-watch.c */ -int udev_watch_init(void); -void udev_watch_restore(void); -void udev_watch_begin(struct udev_device *dev); -void udev_watch_end(struct udev_device *dev); -struct udev_device *udev_watch_lookup(int wd); - -/* udev-node.c */ -void udev_node_add(struct udev_device *dev, bool apply, - mode_t mode, uid_t uid, gid_t gid, - struct udev_list *seclabel_list); -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(void); -struct udev_ctrl *udev_ctrl_new_from_fd(int fd); -int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl); -struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl); -int udev_ctrl_cleanup(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_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 { -#if HAVE_BLKID - UDEV_BUILTIN_BLKID, -#endif - UDEV_BUILTIN_BTRFS, - UDEV_BUILTIN_HWDB, - UDEV_BUILTIN_INPUT_ID, - UDEV_BUILTIN_KEYBOARD, -#if HAVE_KMOD - UDEV_BUILTIN_KMOD, -#endif - UDEV_BUILTIN_NET_ID, - UDEV_BUILTIN_NET_LINK, - UDEV_BUILTIN_PATH_ID, - UDEV_BUILTIN_USB_ID, -#if HAVE_ACL - UDEV_BUILTIN_UACCESS, -#endif - 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)(void); - void (*exit)(void); - bool (*validate)(void); - bool run_once; -}; -#if HAVE_BLKID -extern const struct udev_builtin udev_builtin_blkid; -#endif -extern const struct udev_builtin udev_builtin_btrfs; -extern const struct udev_builtin udev_builtin_hwdb; -extern const struct udev_builtin udev_builtin_input_id; -extern const struct udev_builtin udev_builtin_keyboard; -#if HAVE_KMOD -extern const struct udev_builtin udev_builtin_kmod; -#endif -extern const struct udev_builtin udev_builtin_net_id; -extern const struct udev_builtin udev_builtin_net_setup_link; -extern const struct udev_builtin udev_builtin_path_id; -extern const struct udev_builtin udev_builtin_usb_id; -extern const struct udev_builtin udev_builtin_uaccess; -void udev_builtin_init(void); -void udev_builtin_exit(void); -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(void); -bool udev_builtin_validate(void); -int udev_builtin_add_property(struct udev_device *dev, bool test, const char *key, const char *val); -int udev_builtin_hwdb_lookup(struct udev_device *dev, const char *prefix, const char *modalias, - const char *filter, bool test); /* Cleanup functions */ DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_event*, udev_event_unref); DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_rules*, udev_rules_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl*, udev_ctrl_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl_connection*, udev_ctrl_connection_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl_msg*, udev_ctrl_msg_unref); diff --git a/src/udev/udevadm-control.c b/src/udev/udevadm-control.c index 3125a18088..22ac4962ed 100644 --- a/src/udev/udevadm-control.c +++ b/src/udev/udevadm-control.c @@ -19,11 +19,13 @@ #include #include +#include "libudev-private.h" #include "parse-util.h" #include "process-util.h" #include "time-util.h" -#include "udev.h" #include "udevadm.h" +#include "udev-ctrl.h" +#include "util.h" static int help(void) { printf("%s control OPTION\n\n" diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c index 7e02275ba4..6960324516 100644 --- a/src/udev/udevadm-settle.c +++ b/src/udev/udevadm-settle.c @@ -13,9 +13,11 @@ #include #include +#include "libudev-private.h" #include "time-util.h" #include "udevadm.h" -#include "udev.h" +#include "udev-ctrl.h" +#include "util.h" static usec_t arg_timeout = 120 * USEC_PER_SEC; static const char *arg_exists = NULL; diff --git a/src/udev/udevadm-test-builtin.c b/src/udev/udevadm-test-builtin.c index 940d691dd7..d516492ade 100644 --- a/src/udev/udevadm-test-builtin.c +++ b/src/udev/udevadm-test-builtin.c @@ -6,9 +6,11 @@ #include #include +#include "libudev-private.h" #include "path-util.h" #include "string-util.h" -#include "udev.h" +#include "strxcpyx.h" +#include "udev-builtin.h" #include "udevadm.h" static const char *arg_command = NULL; diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c index 462c5818f4..89d51c7775 100644 --- a/src/udev/udevadm-test.c +++ b/src/udev/udevadm-test.c @@ -13,6 +13,7 @@ #include #include "string-util.h" +#include "udev-builtin.h" #include "udev.h" #include "udevadm.h" diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 40aa9650af..ea1476e7dd 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -34,12 +34,14 @@ #include "cgroup-util.h" #include "cpu-set-util.h" #include "dev-setup.h" +#include "device-util.h" #include "fd-util.h" #include "fileio.h" #include "format-util.h" #include "fs-util.h" #include "hashmap.h" #include "io-util.h" +#include "libudev-device-internal.h" #include "list.h" #include "netlink-util.h" #include "parse-util.h" @@ -50,7 +52,10 @@ #include "socket-util.h" #include "string-util.h" #include "terminal-util.h" +#include "udev-builtin.h" +#include "udev-ctrl.h" #include "udev-util.h" +#include "udev-watch.h" #include "udev.h" #include "user-util.h" @@ -451,7 +456,7 @@ static void worker_spawn(Manager *manager, struct event *event) { /* apply/restore inotify watch */ if (udev_event->inotify_watch) { - udev_watch_begin(dev); + udev_watch_begin(dev->device); udev_device_update_db(dev); } @@ -997,18 +1002,38 @@ static int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userd return 1; } -static int synthesize_change(struct udev_device *dev) { - char filename[UTIL_PATH_SIZE]; +static int synthesize_change(sd_device *dev) { + const char *subsystem, *sysname, *devname, *syspath, *devtype; + char filename[PATH_MAX]; int r; - if (streq_ptr("block", udev_device_get_subsystem(dev)) && - streq_ptr("disk", udev_device_get_devtype(dev)) && - !startswith(udev_device_get_sysname(dev), "dm-")) { - bool part_table_read = false; - bool has_partitions = false; + r = sd_device_get_subsystem(dev, &subsystem); + if (r < 0) + return r; + + r = sd_device_get_sysname(dev, &sysname); + if (r < 0) + return r; + + r = sd_device_get_devname(dev, &devname); + if (r < 0) + return r; + + r = sd_device_get_syspath(dev, &syspath); + if (r < 0) + return r; + + r = sd_device_get_devtype(dev, &devtype); + if (r < 0) + return r; + + if (streq_ptr("block", subsystem) && + streq_ptr("disk", devtype) && + !startswith(sysname, "dm-")) { + _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; + bool part_table_read = false, has_partitions = false; + sd_device *d; int fd; - _cleanup_(udev_enumerate_unrefp) struct udev_enumerate *e = NULL; - struct udev_list_entry *item; /* * Try to re-read the partition table. This only succeeds if @@ -1016,7 +1041,7 @@ static int synthesize_change(struct udev_device *dev) { * partition table is found, and we will not get an event for * the disk. */ - fd = open(udev_device_get_devnode(dev), O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK); + fd = open(devname, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK); if (fd >= 0) { r = flock(fd, LOCK_EX|LOCK_NB); if (r >= 0) @@ -1028,30 +1053,27 @@ static int synthesize_change(struct udev_device *dev) { } /* search for partitions */ - e = udev_enumerate_new(NULL); - if (!e) - return -ENOMEM; - - r = udev_enumerate_add_match_parent(e, dev); + r = sd_device_enumerator_new(&e); if (r < 0) return r; - r = udev_enumerate_add_match_subsystem(e, "block"); + r = sd_device_enumerator_allow_uninitialized(e); if (r < 0) return r; - r = udev_enumerate_scan_devices(e); + r = sd_device_enumerator_add_match_parent(e, dev); if (r < 0) return r; - udev_list_entry_foreach(item, udev_enumerate_get_list_entry(e)) { - _cleanup_(udev_device_unrefp) struct udev_device *d = NULL; + r = sd_device_enumerator_add_match_subsystem(e, "block", true); + if (r < 0) + return r; - d = udev_device_new_from_syspath(NULL, udev_list_entry_get_name(item)); - if (!d) - continue; + FOREACH_DEVICE(e, d) { + const char *t; - if (!streq_ptr("partition", udev_device_get_devtype(d))) + if (sd_device_get_devtype(d, &t) < 0 || + !streq("partition", t)) continue; has_partitions = true; @@ -1070,31 +1092,31 @@ static int synthesize_change(struct udev_device *dev) { * We have partitions but re-reading the partition table did not * work, synthesize "change" for the disk and all partitions. */ - log_debug("device %s closed, synthesising 'change'", udev_device_get_devnode(dev)); - strscpyl(filename, sizeof(filename), udev_device_get_syspath(dev), "/uevent", NULL); + log_debug("Device '%s' is closed, synthesising 'change'", devname); + strscpyl(filename, sizeof(filename), syspath, "/uevent", NULL); write_string_file(filename, "change", WRITE_STRING_FILE_CREATE); - udev_list_entry_foreach(item, udev_enumerate_get_list_entry(e)) { - _cleanup_(udev_device_unrefp) struct udev_device *d = NULL; + FOREACH_DEVICE(e, d) { + const char *t, *n, *s; - d = udev_device_new_from_syspath(NULL, udev_list_entry_get_name(item)); - if (!d) + if (sd_device_get_devtype(d, &t) < 0 || + !streq("partition", t)) continue; - if (!streq_ptr("partition", udev_device_get_devtype(d))) + if (sd_device_get_devname(d, &n) < 0 || + sd_device_get_syspath(d, &s) < 0) continue; - log_debug("device %s closed, synthesising partition '%s' 'change'", - udev_device_get_devnode(dev), udev_device_get_devnode(d)); - strscpyl(filename, sizeof(filename), udev_device_get_syspath(d), "/uevent", NULL); + log_debug("Device '%s' is closed, synthesising partition '%s' 'change'", devname, n); + strscpyl(filename, sizeof(filename), s, "/uevent", NULL); write_string_file(filename, "change", WRITE_STRING_FILE_CREATE); } return 0; } - log_debug("device %s closed, synthesising 'change'", udev_device_get_devnode(dev)); - strscpyl(filename, sizeof(filename), udev_device_get_syspath(dev), "/uevent", NULL); + log_debug("Device %s is closed, synthesising 'change'", devname); + strscpyl(filename, sizeof(filename), syspath, "/uevent", NULL); write_string_file(filename, "change", WRITE_STRING_FILE_CREATE); return 0; @@ -1117,13 +1139,16 @@ static int on_inotify(sd_event_source *s, int fd, uint32_t revents, void *userda } FOREACH_INOTIFY_EVENT(e, buffer, l) { - _cleanup_(udev_device_unrefp) struct udev_device *dev = NULL; + _cleanup_(sd_device_unrefp) sd_device *dev = NULL; + const char *devnode; - dev = udev_watch_lookup(e->wd); - if (!dev) + if (udev_watch_lookup(e->wd, &dev) < 0) continue; - log_debug("inotify event: %x for %s", e->mask, udev_device_get_devnode(dev)); + if (sd_device_get_devname(dev, &devnode) < 0) + continue; + + log_debug("inotify event: %x for %s", e->mask, devnode); if (e->mask & IN_CLOSE_WRITE) { synthesize_change(dev);