Beispiel #1
0
static int create_item(Item *i) {
        int r, e;
        mode_t u;
        struct stat st;

        assert(i);

        switch (i->type) {

        case IGNORE_PATH:
        case REMOVE_PATH:
        case RECURSIVE_REMOVE_PATH:
                return 0;

        case CREATE_FILE:
        case TRUNCATE_FILE:
        case WRITE_FILE: {
                int fd, flags;

                flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND :
                        i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0;

                u = umask(0);
                label_context_set(i->path, S_IFREG);
                fd = open(i->path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode);
                e = errno;
                label_context_clear();
                umask(u);
                errno = e;

                if (fd < 0) {
                        if (i->type == WRITE_FILE && errno == ENOENT)
                                break;

                        log_error("Failed to create file %s: %m", i->path);
                        return -errno;
                }

                if (i->argument) {
                        ssize_t n;
                        size_t l;
                        struct iovec iovec[2];
                        static const char new_line = '\n';

                        l = strlen(i->argument);

                        zero(iovec);
                        iovec[0].iov_base = i->argument;
                        iovec[0].iov_len = l;

                        iovec[1].iov_base = (void*) &new_line;
                        iovec[1].iov_len = 1;

                        n = writev(fd, iovec, 2);

                        /* It's OK if we don't write the trailing
                         * newline, hence we check for l, instead of
                         * l+1 here. Files in /sys often refuse
                         * writing of the trailing newline. */
                        if (n < 0 || (size_t) n < l) {
                                log_error("Failed to write file %s: %s", i->path, n < 0 ? strerror(-n) : "Short write");
                                close_nointr_nofail(fd);
                                return n < 0 ? n : -EIO;
                        }
                }

                close_nointr_nofail(fd);

                if (stat(i->path, &st) < 0) {
                        log_error("stat(%s) failed: %m", i->path);
                        return -errno;
                }

                if (!S_ISREG(st.st_mode)) {
                        log_error("%s is not a file.", i->path);
                        return -EEXIST;
                }

                r = item_set_perms(i, i->path);
                if (r < 0)
                        return r;

                break;
        }

        case TRUNCATE_DIRECTORY:
        case CREATE_DIRECTORY:

                u = umask(0);
                mkdir_parents_label(i->path, 0755);
                r = mkdir(i->path, i->mode);
                umask(u);

                if (r < 0 && errno != EEXIST) {
                        log_error("Failed to create directory %s: %m", i->path);
                        return -errno;
                }

                if (stat(i->path, &st) < 0) {
                        log_error("stat(%s) failed: %m", i->path);
                        return -errno;
                }

                if (!S_ISDIR(st.st_mode)) {
                        log_error("%s is not a directory.", i->path);
                        return -EEXIST;
                }

                r = item_set_perms(i, i->path);
                if (r < 0)
                        return r;

                break;

        case CREATE_FIFO:

                u = umask(0);
                r = mkfifo(i->path, i->mode);
                umask(u);

                if (r < 0 && errno != EEXIST) {
                        log_error("Failed to create fifo %s: %m", i->path);
                        return -errno;
                }

                if (stat(i->path, &st) < 0) {
                        log_error("stat(%s) failed: %m", i->path);
                        return -errno;
                }

                if (!S_ISFIFO(st.st_mode)) {
                        log_error("%s is not a fifo.", i->path);
                        return -EEXIST;
                }

                r = item_set_perms(i, i->path);
                if (r < 0)
                        return r;

                break;

        case CREATE_SYMLINK: {
                char *x;

                label_context_set(i->path, S_IFLNK);
                r = symlink(i->argument, i->path);
                e = errno;
                label_context_clear();
                errno = e;

                if (r < 0 && errno != EEXIST) {
                        log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
                        return -errno;
                }

                r = readlink_malloc(i->path, &x);
                if (r < 0) {
                        log_error("readlink(%s) failed: %s", i->path, strerror(-r));
                        return -errno;
                }

                if (!streq(i->argument, x)) {
                        free(x);
                        log_error("%s is not the right symlinks.", i->path);
                        return -EEXIST;
                }

                free(x);
                break;
        }

        case CREATE_BLOCK_DEVICE:
        case CREATE_CHAR_DEVICE: {
                mode_t file_type = (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR);

                u = umask(0);
                label_context_set(i->path, file_type);
                r = mknod(i->path, i->mode | file_type, i->major_minor);
                e = errno;
                label_context_clear();
                umask(u);
                errno = e;

                if (r < 0 && errno != EEXIST) {
                        log_error("Failed to create device node %s: %m", i->path);
                        return -errno;
                }

                if (stat(i->path, &st) < 0) {
                        log_error("stat(%s) failed: %m", i->path);
                        return -errno;
                }

                if ((st.st_mode & S_IFMT) != file_type) {
                        log_error("%s is not a device node.", i->path);
                        return -EEXIST;
                }

                r = item_set_perms(i, i->path);
                if (r < 0)
                        return r;

                break;
        }

        case RELABEL_PATH:

                r = glob_item(i, item_set_perms);
                if (r < 0)
                        return 0;
                break;

        case RECURSIVE_RELABEL_PATH:

                r = glob_item(i, recursive_relabel);
                if (r < 0)
                        return r;
        }

        log_debug("%s created successfully.", i->path);

        return 0;
}
Beispiel #2
0
static int create_item(Item *i) {
        int r, e;
        mode_t u;
        struct stat st;

        assert(i);

        switch (i->type) {

        case IGNORE_PATH:
        case IGNORE_DIRECTORY_PATH:
        case REMOVE_PATH:
        case RECURSIVE_REMOVE_PATH:
                return 0;

        case CREATE_FILE:
        case TRUNCATE_FILE:
                r = write_one_file(i, i->path);
                if (r < 0)
                        return r;
                break;
        case WRITE_FILE:
                r = glob_item(i, write_one_file);
                if (r < 0)
                        return r;

                break;

        case TRUNCATE_DIRECTORY:
        case CREATE_DIRECTORY:

                u = umask(0);
                mkdir_parents_label(i->path, 0755);
                r = mkdir(i->path, i->mode);
                umask(u);

                if (r < 0 && errno != EEXIST) {
                        log_error("Failed to create directory %s: %m", i->path);
                        return -errno;
                }

                if (stat(i->path, &st) < 0) {
                        log_error("stat(%s) failed: %m", i->path);
                        return -errno;
                }

                if (!S_ISDIR(st.st_mode)) {
                        log_error("%s is not a directory.", i->path);
                        return -EEXIST;
                }

                r = item_set_perms(i, i->path);
                if (r < 0)
                        return r;

                break;

        case CREATE_FIFO:

                u = umask(0);
                r = mkfifo(i->path, i->mode);
                umask(u);

                if (r < 0 && errno != EEXIST) {
                        log_error("Failed to create fifo %s: %m", i->path);
                        return -errno;
                }

                if (stat(i->path, &st) < 0) {
                        log_error("stat(%s) failed: %m", i->path);
                        return -errno;
                }

                if (!S_ISFIFO(st.st_mode)) {
                        log_error("%s is not a fifo.", i->path);
                        return -EEXIST;
                }

                r = item_set_perms(i, i->path);
                if (r < 0)
                        return r;

                break;

        case CREATE_SYMLINK: {
                char *x;

                label_context_set(i->path, S_IFLNK);
                r = symlink(i->argument, i->path);
                e = errno;
                label_context_clear();
                errno = e;

                if (r < 0 && errno != EEXIST) {
                        log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
                        return -errno;
                }

                r = readlink_malloc(i->path, &x);
                if (r < 0) {
                        log_error("readlink(%s) failed: %s", i->path, strerror(-r));
                        return -errno;
                }

                if (!streq(i->argument, x)) {
                        free(x);
                        log_error("%s is not the right symlinks.", i->path);
                        return -EEXIST;
                }

                free(x);
                break;
        }

        case CREATE_BLOCK_DEVICE:
        case CREATE_CHAR_DEVICE: {
                mode_t file_type;

                if (have_effective_cap(CAP_MKNOD) == 0) {
                        /* In a container we lack CAP_MKNOD. We
                        shouldnt attempt to create the device node in
                        that case to avoid noise, and we don't support
                        virtualized devices in containers anyway. */

                        log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
                        return 0;
                }

                file_type = (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR);

                u = umask(0);
                label_context_set(i->path, file_type);
                r = mknod(i->path, i->mode | file_type, i->major_minor);
                e = errno;
                label_context_clear();
                umask(u);
                errno = e;

                if (r < 0 && errno != EEXIST) {
                        log_error("Failed to create device node %s: %m", i->path);
                        return -errno;
                }

                if (stat(i->path, &st) < 0) {
                        log_error("stat(%s) failed: %m", i->path);
                        return -errno;
                }

                if ((st.st_mode & S_IFMT) != file_type) {
                        log_error("%s is not a device node.", i->path);
                        return -EEXIST;
                }

                r = item_set_perms(i, i->path);
                if (r < 0)
                        return r;

                break;
        }

        case RELABEL_PATH:

                r = glob_item(i, item_set_perms);
                if (r < 0)
                        return 0;
                break;

        case RECURSIVE_RELABEL_PATH:

                r = glob_item(i, recursive_relabel);
                if (r < 0)
                        return r;
        }

        log_debug("%s created successfully.", i->path);

        return 0;
}
Beispiel #3
0
static int node_symlink(struct udev_device *dev, 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 + 32];
        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 = strpcpy(&s, l, "../");
                i++;
        }
        l = 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", 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 (streq(target, buf)) {
                                        log_debug("preserve already existing symlink '%s' to '%s'", 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'", 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'", slink);
        strscpyl(slink_tmp, sizeof(slink_tmp), slink, ".tmp-", udev_device_get_id_filename(dev), 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", target, slink_tmp);
                goto exit;
        }
        err = rename(slink_tmp, slink);
        if (err != 0) {
                log_error("rename '%s' '%s' failed: %m", slink_tmp, slink);
                unlink(slink_tmp);
        }
exit:
        return err;
}
Beispiel #4
0
static int write_one_file(Item *i, const char *path) {
        int r, e, fd, flags;
        struct stat st;
        mode_t u;

        flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND :
                i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0;

        u = umask(0);
        label_context_set(path, S_IFREG);
        fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode);
        e = errno;
        label_context_clear();
        umask(u);
        errno = e;

        if (fd < 0) {
                if (i->type == WRITE_FILE && errno == ENOENT)
                        return 0;

                log_error("Failed to create file %s: %m", path);
                return -errno;
        }

        if (i->argument) {
                ssize_t n;
                size_t l;
                _cleanup_free_ char *unescaped;

                unescaped = cunescape(i->argument);
                if (unescaped == NULL) {
                        close_nointr_nofail(fd);
                        return log_oom();
                }

                l = strlen(unescaped);
                n = write(fd, unescaped, l);

                if (n < 0 || (size_t) n < l) {
                        log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
                        close_nointr_nofail(fd);
                        return n < 0 ? n : -EIO;
                }
        }

        close_nointr_nofail(fd);

        if (stat(path, &st) < 0) {
                log_error("stat(%s) failed: %m", path);
                return -errno;
        }

        if (!S_ISREG(st.st_mode)) {
                log_error("%s is not a file.", path);
                return -EEXIST;
        }

        r = item_set_perms(i, path);
        if (r < 0)
                return r;

        return 0;
}