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
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 #4
0
static int node_symlink(struct udev *udev, const char *node, const char *slink)
{
        struct stat stats;
        char target[UTIL_PATH_SIZE];
        char *s;
        size_t l;
        char slink_tmp[UTIL_PATH_SIZE + sizeof(TMP_FILE_EXT)];
        int i = 0;
        int tail = 0;
        int err = 0;

        /* use relative link */
        target[0] = '\0';
        while (node[i] && (node[i] == slink[i])) {
                if (node[i] == '/')
                        tail = i+1;
                i++;
        }
        s = target;
        l = sizeof(target);
        while (slink[i] != '\0') {
                if (slink[i] == '/')
                        l = util_strpcpy(&s, l, "../");
                i++;
        }
        l = util_strscpy(s, l, &node[tail]);
        if (l == 0) {
                err = -EINVAL;
                goto exit;
        }

        /* 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 && stats.st_ino != stats2.st_ino) {
                                        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];
                        int len;

                        dbg(udev, "found existing symlink '%s'\n", slink);
                        len = readlink(slink, buf, sizeof(buf));
                        if (len > 0 && len < (int)sizeof(buf)) {
                                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);
                                        utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW);
                                        goto exit;
                                }
                        }
                }
        } else {
                info(udev, "creating symlink '%s' to '%s'\n", slink, target);
                do {
                        err = util_create_path_selinux(udev, slink);
                        if (err != 0 && err != -ENOENT)
                                break;
                        udev_selinux_setfscreatecon(udev, slink, S_IFLNK);
                        err = symlink(target, slink);
                        if (err != 0)
                                err = -errno;
                        udev_selinux_resetfscreatecon(udev);
                } while (err == -ENOENT);
                if (err == 0)
                        goto exit;
        }

        info(udev, "atomically replace '%s'\n", slink);
        util_strscpyl(slink_tmp, sizeof(slink_tmp), slink, TMP_FILE_EXT, NULL);
        unlink(slink_tmp);
        do {
                err = util_create_path_selinux(udev, slink_tmp);
                if (err != 0 && err != -ENOENT)
                        break;
                udev_selinux_setfscreatecon(udev, slink_tmp, S_IFLNK);
                err = symlink(target, slink_tmp);
                if (err != 0)
                        err = -errno;
                udev_selinux_resetfscreatecon(udev);
        } while (err == -ENOENT);
        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);
        }
exit:
        return err;
}
Example #5
0
static int node_symlink(struct udev *udev, const char *node, const char *slink)
{
        struct stat stats;
        char target[UTIL_PATH_SIZE];
        char *s;
        size_t l;
        char slink_tmp[UTIL_PATH_SIZE + sizeof(TMP_FILE_EXT)];
        int i = 0;
        int tail = 0;
        int err = 0;

        /* use relative link */
        target[0] = '\0';
        while (node[i] && (node[i] == slink[i])) {
                if (node[i] == '/')
                        tail = i+1;
                i++;
        }
        s = target;
        l = sizeof(target);
        while (slink[i] != '\0') {
                if (slink[i] == '/')
                        l = util_strpcpy(&s, l, "../");
                i++;
        }
        l = util_strscpy(s, l, &node[tail]);
        if (l == 0) {
                err = -EINVAL;
                goto exit;
        }

        /* 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\n", slink, node);
                        goto exit;
                } else if (S_ISLNK(stats.st_mode)) {
                        char buf[UTIL_PATH_SIZE];
                        int len;

                        len = readlink(slink, buf, sizeof(buf));
                        if (len > 0 && len < (int)sizeof(buf)) {
                                buf[len] = '\0';
                                if (strcmp(target, buf) == 0) {
                                        log_debug("preserve already existing symlink '%s' to '%s'\n", slink, target);
                                        label_fix(slink, true, false);
                                        utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW);
                                        goto exit;
                                }
                        }
                }
        } else {
                log_debug("creating symlink '%s' to '%s'\n", slink, target);
                do {
                        err = mkdir_parents_label(slink, 0755);
                        if (err != 0 && err != -ENOENT)
                                break;
                        label_context_set(slink, S_IFLNK);
                        err = symlink(target, slink);
                        if (err != 0)
                                err = -errno;
                        label_context_clear();
                } while (err == -ENOENT);
                if (err == 0)
                        goto exit;
        }

        log_debug("atomically replace '%s'\n", slink);
        util_strscpyl(slink_tmp, sizeof(slink_tmp), slink, TMP_FILE_EXT, NULL);
        unlink(slink_tmp);
        do {
                err = mkdir_parents_label(slink_tmp, 0755);
                if (err != 0 && err != -ENOENT)
                        break;
                label_context_set(slink_tmp, S_IFLNK);
                err = symlink(target, slink_tmp);
                if (err != 0)
                        err = -errno;
                label_context_clear();
        } while (err == -ENOENT);
        if (err != 0) {
                log_error("symlink '%s' '%s' failed: %m\n", target, slink_tmp);
                goto exit;
        }
        err = rename(slink_tmp, slink);
        if (err != 0) {
                log_error("rename '%s' '%s' failed: %m\n", slink_tmp, slink);
                unlink(slink_tmp);
        }
exit:
        return err;
}