Example #1
0
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;
    int maj, min;
    char type;
    dev_t devnum;

    if (inotify_fd < 0 || wd < 0)
        return NULL;

    snprintf(filename, sizeof(filename), "%s/.udev/watch/%d", udev_get_dev_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';

    if (sscanf(s, "%c%i:%i", &type, &maj, &min) != 3)
        return NULL;
    devnum = makedev(maj, min);
    return udev_device_new_from_devnum(udev, type, devnum);
}
Example #2
0
/* 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_dev_path(udev), "/.udev/watch.old", NULL);
    util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.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;
            int maj, min;
            char type;

            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';

            if (sscanf(s, "%c%i:%i", &type, &maj, &min) != 3)
                goto unlink;
            dev = udev_device_new_from_devnum(udev, type, makedev(maj, min));
            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);
    }
}
Example #3
0
int main (int argc, char** argv)
{
	struct udev *udev;
	struct udev_device *dev;

	char devpath[PATH_MAX];
	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)];

	if (argc != 2) {
		fprintf(stderr, "Usage: %s <device path (without /sys)>\n", argv[0]);
		exit(1);
	}

	/* get the device */
	udev = udev_new();
	if (udev == NULL)
		return 1;

	snprintf(devpath, sizeof(devpath), "%s/%s", udev_get_sys_path(udev), argv[1]);
	dev = udev_device_new_from_syspath(udev, devpath);
	if (dev == NULL) {
		fprintf(stderr, "unable to access '%s'\n", devpath);
		return 1;
	}

	/* walk up the parental chain until we find the real input device; the
	 * argument is very likely a subdevice of this, like eventN */
	while (dev != NULL && udev_device_get_sysattr_value(dev, "capabilities/ev") == NULL)
		dev = udev_device_get_parent_with_subsystem_devtype(dev, "input", NULL);

	/* not an "input" class device */
	if (dev == NULL)
		return 0;

	/* 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 */
	puts("ID_INPUT=1");

	get_cap_mask (dev, "capabilities/ev", bitmask_ev, sizeof (bitmask_ev));
	get_cap_mask (dev, "capabilities/abs", bitmask_abs, sizeof (bitmask_abs));
	get_cap_mask (dev, "capabilities/rel", bitmask_rel, sizeof (bitmask_rel));
	get_cap_mask (dev, "capabilities/key", bitmask_key, sizeof (bitmask_key));

	test_pointers(bitmask_ev, bitmask_abs, bitmask_key, bitmask_rel);

	test_key(bitmask_ev, bitmask_key);

	return 0;
}
Example #4
0
struct udev_device *udev_watch_lookup(struct udev *udev, int wd)
{
    char filename[UTIL_PATH_SIZE];
    char buf[UTIL_PATH_SIZE];
    ssize_t syslen;
    ssize_t len;

    if (inotify_fd < 0 || wd < 0)
        return NULL;

    snprintf(filename, sizeof(filename), "%s/.udev/watch/%d", udev_get_dev_path(udev), wd);
    syslen = util_strlcpy(buf, udev_get_sys_path(udev), sizeof(buf));
    len = readlink(filename, &buf[syslen], sizeof(buf)-syslen);
    if (len > 0 || len < (ssize_t)(sizeof(buf)-syslen)) {
        buf[syslen + len] = '\0';
        return udev_device_new_from_syspath(udev, buf);
    }

    return NULL;
}
Example #5
0
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_device_id(udev, s);
}
Example #6
0
static int name_index_get_devices(struct udev *udev, const char *name, struct udev_list_node *dev_list)
{
	char dirname[PATH_MAX];
	size_t devlen = strlen(udev_get_dev_path(udev))+1;
	size_t start;
	DIR *dir;
	int count = 0;

	util_strlcpy(dirname, udev_get_dev_path(udev), sizeof(dirname));
	start = util_strlcat(dirname, "/.udev/names/", sizeof(dirname));
	util_strlcat(dirname, &name[devlen], sizeof(dirname));
	util_path_encode(&dirname[start], sizeof(dirname) - start);
	dir = opendir(dirname);
	if (dir == NULL) {
		dbg(udev, "no index directory '%s': %m\n", dirname);
		count = -1;
		goto out;
	}
	dbg(udev, "found index directory '%s'\n", dirname);

	while (1) {
		struct dirent *ent;
		char device[UTIL_PATH_SIZE];

		ent = readdir(dir);
		if (ent == NULL || ent->d_name[0] == '\0')
			break;
		if (ent->d_name[0] == '.')
			continue;

		util_strlcpy(device, udev_get_sys_path(udev), sizeof(device));
		util_strlcat(device, ent->d_name, sizeof(device));
		util_path_decode(device);
		udev_list_entry_add(udev, dev_list, device, NULL, 1, 0);
		count++;
	}
	closedir(dir);
out:
	return count;
}
static char *card_get_sysattr(const char *card_idx, const char *name) {
    struct udev *udev;
    struct udev_device *card = NULL;
    char *t, *r = NULL;
    const char *v;

    pa_assert(card_idx);
    pa_assert(name);

    if (!(udev = udev_new())) {
        pa_log_error("Failed to allocate udev context.");
        goto finish;
    }

    t = pa_sprintf_malloc("%s/class/sound/card%s", udev_get_sys_path(udev), card_idx);
    card = udev_device_new_from_syspath(udev, t);
    pa_xfree(t);

    if (!card) {
        pa_log_error("Failed to get card object.");
        goto finish;
    }

    if ((v = udev_device_get_sysattr_value(card, name)) && *v)
        r = pa_xstrdup(v);

finish:

    if (card)
        udev_device_unref(card);

    if (udev)
        udev_unref(udev);

    return r;
}
Example #8
0
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;
}
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;
	}

	/* 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;
	}

	cmd = udev_builtin_lookup(command);
	if (cmd >= UDEV_BUILTIN_MAX) {
		fprintf(stderr, "unknown command '%s'\n", command);
		help(udev);
		rc = 5;
		goto out;
	}

	if (udev_builtin_run(dev, cmd, true) < 0) {
		fprintf(stderr, "error executing '%s'\n\n", command);
		rc = 6;
	}
out:
	udev_device_unref(dev);
	return rc;
}
Example #10
0
int main(int argc, char **argv)
{
	static const struct option options[] = {
		{ "debug", no_argument, NULL, 'd' },
		{ "help", no_argument, NULL, 'h' },
		{}
	};
	struct udev *udev;
	struct udev_device *dev;
	struct udev_device *parent;
	char syspath[UTIL_PATH_SIZE];
	const char *devpath;
	char *path;
	char *path_suffix;
	int rc = 1;

	udev = udev_new();
	if (udev == NULL)
		goto exit;

	udev_log_init("path_id");
	udev_set_log_fn(udev, log_fn);

	while (1) {
		int option;

		option = getopt_long(argc, argv, "dh", 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':
			printf("Usage: path_id [--debug] [--help] <devpath>\n"
			       "  --debug    print debug information\n"
			       "  --help      print this help text\n\n");
		default:
			rc = 1;
			goto exit;
		}
	}

	devpath = argv[optind];
	if (devpath == NULL) {
		fprintf(stderr, "No device specified\n");
		rc = 2;
		goto exit;
	}

	util_strscpyl(syspath, sizeof(syspath), udev_get_sys_path(udev), devpath, NULL);
	dev = udev_device_new_from_syspath(udev, syspath);
	if (dev == NULL) {
		fprintf(stderr, "unable to access '%s'\n", devpath);
		rc = 3;
		goto exit;
	}

	path = NULL;
	path_suffix = 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_suffix);
		} else if (strcmp(subsys, "scsi") == 0) {
			parent = handle_scsi(parent, &path);
		} else if (strcmp(subsys, "cciss") == 0) {
			handle_cciss(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, "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) {
		if (path_suffix != NULL) {
			printf("ID_PATH=%s%s\n", path, path_suffix);
			free(path_suffix);
		} else {
			printf("ID_PATH=%s\n", path);
		}
		free(path);
		rc = 0;
	}

	udev_device_unref(dev);
exit:
	udev_unref(udev);
	udev_log_close();
	return rc;
}
Example #11
0
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];
	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)];

	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;
	}

	/* walk up the parental chain until we find the real input device; the
	 * argument is very likely a subdevice of this, like eventN */
	while (dev != NULL && udev_device_get_sysattr_value(dev, "capabilities/ev") == NULL)
		dev = udev_device_get_parent_with_subsystem_devtype(dev, "input", NULL);

	/* not an "input" class device */
	if (dev == NULL)
		return 0;

	/* 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 */
	puts("ID_INPUT=1");

	get_cap_mask (dev, "capabilities/ev", bitmask_ev, sizeof (bitmask_ev));
	get_cap_mask (dev, "capabilities/abs", bitmask_abs, sizeof (bitmask_abs));
	get_cap_mask (dev, "capabilities/rel", bitmask_rel, sizeof (bitmask_rel));
	get_cap_mask (dev, "capabilities/key", bitmask_key, sizeof (bitmask_key));

	test_pointers(bitmask_ev, bitmask_abs, bitmask_key, bitmask_rel);

	test_key(udev, bitmask_ev, bitmask_key);

	return 0;
}
int main(int argc, char *argv[])
{
    static const struct option options[] = {
        { "export", no_argument, NULL, 'e' },
        { "debug", no_argument, NULL, 'd' },
        { "help", no_argument, NULL, 'h' },
        {}
    };
    struct udev *udev;
    struct stat buf;
    const char *devpath = NULL;
    char filename[UTIL_PATH_SIZE], devspec[256], devtype[256];
    int export = 0;
    int rc = 1;
    int i, fd, len;

    udev = udev_new();
    if (udev == NULL)
        goto exit;

    udev_log_init("vio_type");
    udev_set_log_fn(udev, log_fn);

    while (1) {
        int option;

        option = getopt_long(argc, argv, "edh", options, NULL);
        if (option == -1)
            break;

        switch (option) {
        case 'e':
            export = 1;
            break;
        case 'd':
            debug = 1;
            if (udev_get_log_priority(udev) < LOG_INFO)
                udev_set_log_priority(udev, LOG_INFO);
            break;
        case 'h':
            printf("Usage: vio_type [--debug] [--help] <devpath>\n"
                   "  --debug    print debug information\n"
                   "  --help     print this help text\n\n");
        default:
            goto exit;
        }
    }

    devpath = argv[optind];
    if (devpath == NULL) {
        err(udev, "No device specified");
        rc = 2;
        goto exit;
    }

    util_strscpyl(filename, sizeof(filename), udev_get_sys_path(udev),
                  devpath, "/devspec", NULL);

    fd = open(filename, O_RDONLY);
    if (fd < 0) {
        err(udev, "unable to open '%s'", filename);
        goto exit;
    }

    len = read(fd, devspec, sizeof(devspec));
    if (len <= 0) {
#if !defined(__sparc__) && !defined(__sparc64__)
        err(udev, "unable to read from '%s'", filename);
#endif
        goto close;
    }

    devspec[len] = '\0';
    if (devspec[len-1] == '\n')
        devspec[len-1] = '\0';

    close(fd);

#if !defined(__sparc__) && !defined(__sparc64__)
    /* now we look in /proc */

    util_strscpyl(filename, sizeof(filename), "/proc/device-tree",
                  devspec, "/device_type", NULL);

    /* hang around for /proc to catch up */
    for (i = 100; i; i--) {
        if (stat(filename, &buf) == 0)
            break;

        usleep(30000);
    }

    fd = open(filename, O_RDONLY);
    if (fd < 0) {
        err(udev, "unable to open '%s'", filename);
        goto exit;
    }

    len = read(fd, devtype, sizeof(devtype));
    if (len <= 0) {
        err(udev, "unable to read from '%s'", filename);
        goto close;
    }

    devtype[len] = '\0';
    if (devtype[len-1] == '\n')
        devtype[len-1] = '\0';
#else
    strncpy(devtype,devspec,strlen(devspec)+1);
#endif

    if (export) {
        printf("VIO_TYPE=%s\n", devtype);
    } else {
Example #13
0
/* 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_strlcpy(oldname, udev_get_dev_path(udev), sizeof(oldname));
    util_strlcat(oldname, "/.udev/watch.old", sizeof(oldname));

    util_strlcpy(filename, udev_get_dev_path(udev), sizeof(filename));
    util_strlcat(filename, "/.udev/watch", sizeof(filename));

    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;
        }

        while ((ent = readdir(dir)) != NULL) {
            char path[UTIL_PATH_SIZE];
            char buf[UTIL_PATH_SIZE];
            ssize_t syslen;
            ssize_t len;
            struct udev_device *dev;

            if (ent->d_name[0] < '0' || ent->d_name[0] > '9')
                continue;

            util_strlcpy(path, oldname, sizeof(path));
            util_strlcat(path, "/", sizeof(path));
            util_strlcat(path, ent->d_name, sizeof(path));

            syslen = util_strlcpy(buf, udev_get_sys_path(udev), sizeof(buf));
            len = readlink(path, &buf[syslen], sizeof(buf)-syslen);
            if (len <= 0 || len >= (ssize_t)(sizeof(buf)-syslen)) {
                unlink(path);
                continue;
            }
            buf[syslen + len] = '\0';
            dbg(udev, "old watch to '%s' found\n", buf);
            dev = udev_device_new_from_syspath(udev, buf);
            if (dev == NULL) {
                unlink(path);
                continue;
            }

            info(udev, "restoring old watch on '%s'\n", udev_device_get_devnode(dev));
            udev_watch_begin(udev, dev);

            udev_device_unref(dev);
            unlink(path);
        }

        closedir(dir);
        rmdir(oldname);

    } else if (errno != ENOENT) {
        err(udev, "unable to move watches dir '%s', old watches will not be restored: %m", filename);
    }
}
Example #14
0
int main(int argc, char *argv[])
{
	struct udev *udev;
	struct udev_event *event;
	struct udev_device *dev;
	struct udev_rules *rules;
	char syspath[UTIL_PATH_SIZE];
	const char *devpath;
	const char *action;
	const char *subsystem;
	struct sigaction act;
	int err = -EINVAL;

	udev = udev_new();
	if (udev == NULL)
		exit(1);
	info(udev, "version %s\n", VERSION);
	udev_selinux_init(udev);

	/* set signal handlers */
	memset(&act, 0x00, sizeof(act));
	act.sa_handler = (void (*)(int)) sig_handler;
	sigemptyset (&act.sa_mask);
	act.sa_flags = 0;
	sigaction(SIGALRM, &act, NULL);
	sigaction(SIGINT, &act, NULL);
	sigaction(SIGTERM, &act, NULL);

	/* trigger timeout to prevent hanging processes */
	alarm(UDEV_EVENT_TIMEOUT);

	action = getenv("ACTION");
	devpath = getenv("DEVPATH");
	subsystem = getenv("SUBSYSTEM");

	if (action == NULL || subsystem == NULL || devpath == NULL) {
		err(udev, "action, subsystem or devpath missing\n");
		goto exit;
	}

	rules = udev_rules_new(udev, 1);

	util_strlcpy(syspath, udev_get_sys_path(udev), sizeof(syspath));
	util_strlcat(syspath, devpath, sizeof(syspath));
	dev = udev_device_new_from_syspath(udev, syspath);
	if (dev == NULL) {
		info(udev, "unknown device '%s'\n", devpath);
		goto fail;
	}

	/* 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);
	err = udev_event_execute_rules(event, rules);

	/* rules may change/disable the timeout */
	if (udev_device_get_event_timeout(dev) >= 0)
		alarm(udev_device_get_event_timeout(dev));

	if (err == 0 && !event->ignore_device && udev_get_run(udev))
		udev_event_execute_run(event);

	udev_event_unref(event);
	udev_device_unref(dev);
fail:
	udev_rules_unref(rules);
exit:
	udev_selinux_exit(udev);
	udev_unref(udev);
	if (err != 0)
		return 1;
	return 0;
}
/* 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;
		char devpath[UTIL_PATH_SIZE];
		char syspath[UTIL_PATH_SIZE];
		ssize_t len;

		dent = readdir(dir);
		if (dent == NULL || dent->d_name[0] == '\0')
			break;
		if (dent->d_name[0] == '.')
			continue;
		dbg(udev, "found '%s/%s'\n", stackdir, dent->d_name);
		len = readlinkat(dirfd(dir), dent->d_name, devpath, sizeof(devpath));
		if (len <= 0 || len == (ssize_t)sizeof(devpath))
			continue;
		devpath[len] = '\0';
		util_strscpyl(syspath, sizeof(syspath), udev_get_sys_path(udev), devpath, NULL);
		info(udev, "found '%s' claiming '%s'\n", syspath, stackdir);

		/* did we find ourself? */
		if (strcmp(udev_device_get_syspath(dev), syspath) == 0)
			continue;

		dev_db = udev_device_new_from_syspath(udev, syspath);
		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",
					     syspath, 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;
}