Exemplo n.º 1
0
/* reverse mapping from the device file name to the devpath */
static int name_index(struct udev *udev, const char *devpath, const char *name, int add, int test)
{
	char device[UTIL_PATH_SIZE];
	char filename[UTIL_PATH_SIZE * 2];
	size_t devlen = strlen(udev_get_dev_path(udev))+1;
	size_t start;
	int fd;

	/* directory with device name */
	util_strlcpy(filename, udev_get_dev_path(udev), sizeof(filename));
	start = util_strlcat(filename, "/.udev/names/", sizeof(filename));
	util_strlcat(filename, &name[devlen], sizeof(filename));
	util_path_encode(&filename[start], sizeof(filename) - start);
	/* entry with the devpath */
	util_strlcpy(device, devpath, sizeof(device));
	util_path_encode(device, sizeof(device));
	util_strlcat(filename, "/", sizeof(filename));
	util_strlcat(filename, device, sizeof(filename));

	if (add) {
		dbg(udev, "creating index: '%s'\n", filename);
		util_create_path(udev, filename);
		fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0644);
		if (fd > 0)
			close(fd);
	} else {
		dbg(udev, "removing index: '%s'\n", filename);
		unlink(filename);
		util_delete_path(udev, filename);
	}
	return 0;
}
Exemplo n.º 2
0
/**
 * Logs a text to the console; it uses a printf-like format
 *
 * @param[in]       fmt     printf-like format
 * @param[in]       ...     Additional arguments
 */
void con_printf(char *fmt, ...)
{
    char curstr[CON_STR_SZ];
    va_list vargs;

    va_start(vargs, fmt);
    vsnprintf(curstr, sizeof(curstr), fmt, vargs);
    va_end(vargs);

    if (strcmp(curstr, con_str) == 0)
    {
        con_str_rep++;
        return;
    }

    if (con_str_rep > 0)
    {
        char rep_str[CON_STR_SZ];
        snprintf(rep_str, sizeof(rep_str), "Last message was repeated %d more time/s.\n", con_str_rep);
        con_str_rep = 0;

        tb_strput(&con_tb, rep_str);
#ifdef CON_DEBUG
        fputs(rep_str, stdout);
#endif
    }

    util_strlcpy(con_str, curstr, sizeof(con_str));

#ifdef CON_DEBUG
    fputs(con_str, stdout);
#endif
    tb_strput(&con_tb, con_str);
}
Exemplo n.º 3
0
Arquivo: util.c Projeto: CeeJay79/apme
/**
 * Copy @p text to the clipboard
 *
 * @param[in]       text        Text to copy to the clipboard
 *
 * @retval          true        On success
 * @retval          false       If any of the Windows clipboard functions failed
 */
bool clipboard_set_text(char *text)
{
    bool retval;
    HGLOBAL hdst;
    char *dst;

    DWORD dst_sz = strlen(text) + sizeof('\0');

    /* Allocate and copy the string to the global memory */
    hdst = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, dst_sz);
    dst = (char *)GlobalLock(hdst);
    util_strlcpy(dst, text, dst_sz);
    GlobalUnlock(hdst);

    /* Set clipboard data */
    retval = OpenClipboard(NULL);
    if (!retval)
    {
        con_printf("Error opening clipboard\n");
        return false;
    }

    EmptyClipboard();

    retval = SetClipboardData(CF_TEXT, hdst);
    if (!retval)
    {
        con_printf("Error pasting to clipboard\n");
        return false;
    }

    CloseClipboard();
    return true;
}
Exemplo n.º 4
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;
}
Exemplo n.º 5
0
Arquivo: util.c Projeto: CeeJay79/apme
/**
 * Find out the path to the executable of the current process
 *
 * @param[out]  path        The path to our executable
 * @param[in]   pathsz      Maximum size of @p path in bytes
 *
 * @retval      true        On success
 * @retval      false       On error
 */
bool sys_self_exe(char *path, size_t pathsz)
{
    char exepath[MAX_PATH];
    DWORD retval;

    retval =  GetModuleFileName(NULL, exepath, sizeof(exepath));
    if (retval == 0)
    {
        con_printf("GetModuleFileName() failed.\n");
        return false;
    }

    con_printf("Our executable path is %s\n", exepath);
    util_strlcpy(path, exepath, pathsz);

    return true;
}
Exemplo n.º 6
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;
}
Exemplo n.º 7
0
/**
 * udev_monitor_new_from_socket:
 * @udev: udev library context
 * @socket_path: unix socket path
 *
 * Create new udev monitor and connect to a specified socket. The
 * path to a socket either points to an existing socket file, or if
 * the socket path starts with a '@' character, an abstract namespace
 * socket will be used.
 *
 * A socket file will not be created. If it does not already exist,
 * it will fall-back and connect to an abstract namespace socket with
 * the given path. The permissions adjustment of a socket file, as
 * well as the later cleanup, needs to be done by the caller.
 *
 * The initial refcount is 1, and needs to be decremented to
 * release the resources of the udev monitor.
 *
 * Returns: a new udev monitor, or #NULL, in case of an error
 **/
struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path)
{
	struct udev_monitor *udev_monitor;
	struct stat statbuf;

	if (udev == NULL)
		return NULL;
	if (socket_path == NULL)
		return NULL;
	udev_monitor = udev_monitor_new(udev);
	if (udev_monitor == NULL)
		return NULL;

	udev_monitor->sun.sun_family = AF_LOCAL;
	if (socket_path[0] == '@') {
		/* translate leading '@' to abstract namespace */
		util_strlcpy(udev_monitor->sun.sun_path, socket_path, sizeof(udev_monitor->sun.sun_path));
		udev_monitor->sun.sun_path[0] = '\0';
		udev_monitor->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(socket_path);
	} else if (stat(socket_path, &statbuf) == 0 && S_ISSOCK(statbuf.st_mode)) {
Exemplo n.º 8
0
Arquivo: util.c Projeto: CeeJay79/apme
/**
 * Return the local APPDATA directory for APme.
 *
 * Create the folder if it does not exist.
 *
 * @param[out]      path    Path to the APPDATA directory
 * @param[in]       pathsz  Maximum number of characters that @p path can hold
 *
 * @retval          true    On success
 * @Retval          false   On error
 */
bool sys_appdata_path(char *path, size_t pathsz)
{
    char appdata_path[MAX_PATH];
    char *pstr;
    HRESULT hres;
    
    /* Retrieve the APP data path */
    hres = SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, appdata_path);
    if (!SUCCEEDED(hres))
    {
        con_printf("Error retrieving the LOCAL APPDATA path\n");
        return false;
    }

    /* Replace '\' with '/' */
    pstr = appdata_path;
    while (*pstr != '\0')
    {
        if (*pstr == '\\') *pstr = '/';
        pstr++;
    }

    util_strlcat(appdata_path, "/APme", sizeof(appdata_path));

    con_printf("APPDATA directory: %s\n", appdata_path);

    /* Check if the directory exists, otherwise create it */
    if (!CreateDirectory(appdata_path, NULL))
    {
        if (GetLastError() != ERROR_ALREADY_EXISTS)
        {
            con_printf("Create directory on '%s' failed\n", appdata_path);
            return false;
        }
    }

    util_strlcpy(path, appdata_path, pathsz);

    return true;
}
Exemplo n.º 9
0
Arquivo: util.c Projeto: CeeJay79/apme
/**
 * Store the content of the clipboard to @p text
 *
 * @param[out]      text        Buffer that will receive the buffer data
 * @param[in]       text_sz     Maximum size of @p text
 *
 * @retval          true        On success
 * @retval          false       On error
 */
bool clipboard_get_text(char *text, size_t text_sz)
{
    HGLOBAL hsrc;
    char *src;

    bool status = false;

    // Set clipboard data
    if (!OpenClipboard(NULL))
    {
        con_printf("Error opening clipboard\n");
        return false;
    }

    hsrc = GetClipboardData(CF_TEXT);
    if (hsrc == NULL)
    {
        // Nothing to retrieve
        goto error;
    }

    src = GlobalLock(hsrc);
    if (src == NULL)
    {
        con_printf("Error locking clipboard data\n");
        goto error;
    }

    util_strlcpy(text, src, text_sz);

    GlobalUnlock(hsrc);

    status = true;

error:
    CloseClipboard();
    return status;

}
Exemplo n.º 10
0
static void exec_list(struct udev_enumerate *udev_enumerate, const char *action)
{
    struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
    struct udev_list_entry *entry;

    udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(udev_enumerate)) {
        char filename[UTIL_PATH_SIZE];
        int fd;

        if (verbose)
            printf("%s\n", udev_list_entry_get_name(entry));
        if (dry_run)
            continue;
        util_strlcpy(filename, udev_list_entry_get_name(entry), sizeof(filename));
        util_strlcat(filename, "/uevent", sizeof(filename));
        fd = open(filename, O_WRONLY);
        if (fd < 0) {
            dbg(udev, "error on opening %s: %m\n", filename);
            continue;
        }
        if (write(fd, action, strlen(action)) < 0)
            info(udev, "error writing '%s' to '%s': %m\n", action, filename);
        close(fd);
    }
Exemplo n.º 11
0
int udev_node_mknod(struct udev_device *dev, const char *file, dev_t devnum, mode_t mode, uid_t uid, gid_t gid)
{
	struct udev *udev = udev_device_get_udev(dev);
	char file_tmp[UTIL_PATH_SIZE + sizeof(TMP_FILE_EXT)];
	struct stat stats;
	int preserve = 0;
	int err = 0;

	if (major(devnum) == 0)
		devnum = udev_device_get_devnum(dev);

	if (strcmp(udev_device_get_subsystem(dev), "block") == 0)
		mode |= S_IFBLK;
	else
		mode |= S_IFCHR;

	if (file == NULL)
		file = udev_device_get_devnode(dev);

	if (lstat(file, &stats) == 0) {
		if (((stats.st_mode & S_IFMT) == (mode & S_IFMT)) && (stats.st_rdev == devnum)) {
			info(udev, "preserve file '%s', because it has correct dev_t\n", file);
			preserve = 1;
			udev_selinux_lsetfilecon(udev, file, mode);
		} else {
			info(udev, "atomically replace existing file '%s'\n", file);
			util_strlcpy(file_tmp, file, sizeof(file_tmp));
			util_strlcat(file_tmp, TMP_FILE_EXT, sizeof(file_tmp));
			unlink(file_tmp);
			udev_selinux_setfscreatecon(udev, file_tmp, mode);
			err = mknod(file_tmp, mode, devnum);
			udev_selinux_resetfscreatecon(udev);
			if (err != 0) {
				err(udev, "mknod(%s, %#o, %u, %u) failed: %m\n",
				    file_tmp, mode, major(devnum), minor(devnum));
				goto exit;
			}
			err = rename(file_tmp, file);
			if (err != 0) {
				err(udev, "rename(%s, %s) failed: %m\n", file_tmp, file);
				unlink(file_tmp);
			}
		}
	} else {
		info(udev, "mknod(%s, %#o, (%u,%u))\n", file, mode, major(devnum), minor(devnum));
		udev_selinux_setfscreatecon(udev, file, mode);
		err = mknod(file, mode, devnum);
		udev_selinux_resetfscreatecon(udev);
		if (err != 0) {
			err(udev, "mknod(%s, %#o, (%u,%u) failed: %m\n", file, mode, major(devnum), minor(devnum));
			goto exit;
		}
	}

	if (!preserve || stats.st_mode != mode) {
		info(udev, "chmod(%s, %#o)\n", file, mode);
		err = chmod(file, mode);
		if (err != 0) {
			err(udev, "chmod(%s, %#o) failed: %m\n", file, mode);
			goto exit;
		}
	}

	if (!preserve || stats.st_uid != uid || stats.st_gid != gid) {
		info(udev, "chown(%s, %u, %u)\n", file, uid, gid);
		err = chown(file, uid, gid);
		if (err != 0) {
			err(udev, "chown(%s, %u, %u) failed: %m\n", file, uid, gid);
			goto exit;
		}
	}
exit:
	return err;
}
Exemplo n.º 12
0
static int update_link(struct udev_device *dev, const char *slink, int test)
{
	struct udev *udev = udev_device_get_udev(dev);
	struct udev_list_node dev_list;
	struct udev_list_entry *dev_entry;
	char target[UTIL_PATH_SIZE];
	int count;
	int priority = 0;
	int rc = 0;

	dbg(udev, "update symlink '%s' of '%s'\n", slink, udev_device_get_syspath(dev));

	udev_list_init(&dev_list);
	count = name_index_get_devices(udev, slink, &dev_list);
	if (count > 1)
		info(udev, "found %i devices with name '%s'\n", count, slink);

	/* if we don't have a reference, delete it */
	if (count <= 0) {
		info(udev, "no reference left, remove '%s'\n", slink);
		if (!test) {
			unlink(slink);
			util_delete_path(udev, slink);
		}
		goto out;
	}

	/* find the device with the highest priority */
	target[0] = '\0';
	udev_list_entry_foreach(dev_entry, udev_list_get_entry(&dev_list)) {
		const char *syspath;
		struct udev_device *dev_db;
		const char *devnode;

		syspath = udev_list_entry_get_name(dev_entry);
		dbg(udev, "found '%s' for '%s'\n", syspath, slink);

		/* did we find ourself? we win, if we have the same priority */
		if (strcmp(udev_device_get_syspath(dev), syspath) == 0) {
			dbg(udev, "compare (our own) priority of '%s' %i >= %i\n",
			    udev_device_get_devpath(dev), udev_device_get_devlink_priority(dev), priority);
			if (strcmp(udev_device_get_devnode(dev), slink) == 0) {
				info(udev, "'%s' is our device node, database inconsistent, skip link update\n",
				     udev_device_get_devnode(dev));
			} else if (target[0] == '\0' || udev_device_get_devlink_priority(dev) >= priority) {
				priority = udev_device_get_devlink_priority(dev);
				util_strlcpy(target, udev_device_get_devnode(dev), sizeof(target));
			}
			continue;
		}

		/* another device, read priority from database */
		dev_db = udev_device_new_from_syspath(udev, syspath);
		if (dev_db == NULL)
			continue;
		devnode = udev_device_get_devnode(dev_db);
		if (devnode != NULL) {
			if (strcmp(devnode, slink) == 0) {
				info(udev, "'%s' is a device node of '%s', skip link update\n",
				     devnode, syspath);
			} else {
				dbg(udev, "compare priority of '%s' %i > %i\n",
				    udev_device_get_devpath(dev_db),
				    udev_device_get_devlink_priority(dev_db),
				    priority);
				if (target[0] == '\0' || udev_device_get_devlink_priority(dev_db) > priority) {
					priority = udev_device_get_devlink_priority(dev_db);
					util_strlcpy(target, devnode, sizeof(target));
				}
			}
		}
		udev_device_unref(dev_db);
	}
	udev_list_cleanup_entries(udev, &dev_list);

	if (target[0] == '\0') {
		info(udev, "no current target for '%s' found\n", slink);
		rc = 1;
		goto out;
	}

	/* create symlink to the target with the highest priority */
	info(udev, "'%s' with target '%s' has the highest priority %i, create it\n", slink, target, priority);
	if (!test) {
		util_create_path(udev, slink);
		node_symlink(udev, target, slink);
	}
out:
	return rc;
}
Exemplo n.º 13
0
static int node_symlink(struct udev *udev, const char *node, const char *slink)
{
	struct stat stats;
	char target[UTIL_PATH_SIZE];
	char slink_tmp[UTIL_PATH_SIZE + sizeof(TMP_FILE_EXT)];
	int i = 0;
	int tail = 0;
	int len;
	int err = 0;

	/* use relative link */
	target[0] = '\0';
	while (node[i] && (node[i] == slink[i])) {
		if (node[i] == '/')
			tail = i+1;
		i++;
	}
	while (slink[i] != '\0') {
		if (slink[i] == '/')
			util_strlcat(target, "../", sizeof(target));
		i++;
	}
	util_strlcat(target, &node[tail], sizeof(target));

	/* 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)) {
			struct stat stats2;

			info(udev, "found existing node instead of symlink '%s'\n", slink);
			if (lstat(node, &stats2) == 0) {
				if ((stats.st_mode & S_IFMT) == (stats2.st_mode & S_IFMT) &&
				    stats.st_rdev == stats2.st_rdev) {
					info(udev, "replace device node '%s' with symlink to our node '%s'\n",
					     slink, node);
				} else {
					err(udev, "device node '%s' already exists, "
					    "link to '%s' will not overwrite it\n",
					    slink, node);
					goto exit;
				}
			}
		} else if (S_ISLNK(stats.st_mode)) {
			char buf[UTIL_PATH_SIZE];

			dbg(udev, "found existing symlink '%s'\n", slink);
			len = readlink(slink, buf, sizeof(buf));
			if (len > 0) {
				buf[len] = '\0';
				if (strcmp(target, buf) == 0) {
					info(udev, "preserve already existing symlink '%s' to '%s'\n",
					     slink, target);
					udev_selinux_lsetfilecon(udev, slink, S_IFLNK);
					goto exit;
				}
			}
		}
	} else {
		info(udev, "creating symlink '%s' to '%s'\n", slink, target);
		udev_selinux_setfscreatecon(udev, slink, S_IFLNK);
		err = symlink(target, slink);
		udev_selinux_resetfscreatecon(udev);
		if (err == 0)
			goto exit;
	}

	info(udev, "atomically replace '%s'\n", slink);
	util_strlcpy(slink_tmp, slink, sizeof(slink_tmp));
	util_strlcat(slink_tmp, TMP_FILE_EXT, sizeof(slink_tmp));
	unlink(slink_tmp);
	udev_selinux_setfscreatecon(udev, slink, S_IFLNK);
	err = symlink(target, slink_tmp);
	udev_selinux_resetfscreatecon(udev);
	if (err != 0) {
		err(udev, "symlink(%s, %s) failed: %m\n", target, slink_tmp);
		goto exit;
	}
	err = rename(slink_tmp, slink);
	if (err != 0) {
		err(udev, "rename(%s, %s) failed: %m\n", slink_tmp, slink);
		unlink(slink_tmp);
		goto exit;
	}
exit:
	return err;
}
Exemplo n.º 14
0
Arquivo: util.c Projeto: CeeJay79/apme
bool sys_appdata_path(char *path, size_t pathsz)
{
    util_strlcpy(path, "./", pathsz);
    return true;
}
Exemplo n.º 15
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);
    }
}
Exemplo n.º 16
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;
}