Beispiel #1
0
static int tar_import_fork_tar(TarImport *i) {
        int r;

        assert(i);

        assert(!i->final_path);
        assert(!i->temp_path);
        assert(i->tar_fd < 0);

        i->final_path = strjoin(i->image_root, "/", i->local, NULL);
        if (!i->final_path)
                return log_oom();

        r = tempfn_random(i->final_path, &i->temp_path);
        if (r < 0)
                return log_oom();

        (void) mkdir_parents_label(i->temp_path, 0700);

        r = btrfs_subvol_make(i->temp_path);
        if (r == -ENOTTY) {
                if (mkdir(i->temp_path, 0755) < 0)
                        return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path);
        } else if (r < 0)
                return log_error_errno(errno, "Failed to create subvolume %s: %m", i->temp_path);

        i->tar_fd = import_fork_tar_x(i->temp_path, &i->tar_pid);
        if (i->tar_fd < 0)
                return i->tar_fd;

        return 0;
}
Beispiel #2
0
static int raw_import_open_disk(RawImport *i) {
        int r;

        assert(i);

        assert(!i->final_path);
        assert(!i->temp_path);
        assert(i->output_fd < 0);

        i->final_path = strjoin(i->image_root, "/", i->local, ".raw");
        if (!i->final_path)
                return log_oom();

        r = tempfn_random(i->final_path, NULL, &i->temp_path);
        if (r < 0)
                return log_oom();

        (void) mkdir_parents_label(i->temp_path, 0700);

        i->output_fd = open(i->temp_path, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664);
        if (i->output_fd < 0)
                return log_error_errno(errno, "Failed to open destination %s: %m", i->temp_path);

        r = chattr_fd(i->output_fd, FS_NOCOW_FL, FS_NOCOW_FL);
        if (r < 0)
                log_warning_errno(r, "Failed to set file attributes on %s: %m", i->temp_path);

        return 0;
}
Beispiel #3
0
static int raw_pull_job_on_open_disk_settings(PullJob *j) {
        RawPull *i;
        int r;

        assert(j);
        assert(j->userdata);

        i = j->userdata;
        assert(i->settings_job == j);
        assert(!i->settings_path);
        assert(!i->settings_temp_path);

        r = pull_make_path(j->url, j->etag, i->image_root, ".settings-", NULL, &i->settings_path);
        if (r < 0)
                return log_oom();

        r = tempfn_random(i->settings_path, NULL, &i->settings_temp_path);
        if (r < 0)
                return log_oom();

        mkdir_parents_label(i->settings_temp_path, 0700);

        j->disk_fd = open(i->settings_temp_path, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664);
        if (j->disk_fd < 0)
                return log_error_errno(errno, "Failed to create %s: %m", i->settings_temp_path);

        return 0;
}
Beispiel #4
0
static int reflink_snapshot(int fd, const char *path) {
        char *p, *d;
        int new_fd, r;

        p = strdupa(path);
        d = dirname(p);

        new_fd = open(d, O_TMPFILE|O_CLOEXEC|O_NOCTTY|O_RDWR, 0600);
        if (new_fd < 0) {
                _cleanup_free_ char *t = NULL;

                r = tempfn_random(path, NULL, &t);
                if (r < 0)
                        return r;

                new_fd = open(t, O_CLOEXEC|O_CREAT|O_NOCTTY|O_RDWR, 0600);
                if (new_fd < 0)
                        return -errno;

                (void) unlink(t);
        }

        r = btrfs_reflink(fd, new_fd);
        if (r < 0) {
                safe_close(new_fd);
                return r;
        }

        return new_fd;
}
Beispiel #5
0
static int raw_pull_job_on_open_disk_raw(PullJob *j) {
        RawPull *i;
        int r;

        assert(j);
        assert(j->userdata);

        i = j->userdata;
        assert(i->raw_job == j);
        assert(!i->final_path);
        assert(!i->temp_path);

        r = pull_make_path(j->url, j->etag, i->image_root, ".raw-", ".raw", &i->final_path);
        if (r < 0)
                return log_oom();

        r = tempfn_random(i->final_path, NULL, &i->temp_path);
        if (r < 0)
                return log_oom();

        (void) mkdir_parents_label(i->temp_path, 0700);

        j->disk_fd = open(i->temp_path, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664);
        if (j->disk_fd < 0)
                return log_error_errno(errno, "Failed to create %s: %m", i->temp_path);

        r = chattr_fd(j->disk_fd, FS_NOCOW_FL, FS_NOCOW_FL);
        if (r < 0)
                log_warning_errno(errno, "Failed to set file attributes on %s: %m", i->temp_path);

        return 0;
}
Beispiel #6
0
int main(int argc, char** argv) {
        _cleanup_free_ char *cmd = NULL, *cmd2 = NULL, *ans = NULL, *ans2 = NULL, *d = NULL, *tmp = NULL, *line = NULL;
        _cleanup_close_ int fd = -1, fd2 = -1;
        const char *p = argv[1] ?: "/tmp";
        char *pattern;

        log_set_max_level(LOG_DEBUG);
        log_parse_environment();

        pattern = strjoina(p, "/systemd-test-XXXXXX");

        fd = open_tmpfile_unlinkable(p, O_RDWR|O_CLOEXEC);
        assert_se(fd >= 0);

        assert_se(asprintf(&cmd, "ls -l /proc/"PID_FMT"/fd/%d", getpid_cached(), fd) > 0);
        (void) system(cmd);
        assert_se(readlink_malloc(cmd + 6, &ans) >= 0);
        log_debug("link1: %s", ans);
        assert_se(endswith(ans, " (deleted)"));

        fd2 = mkostemp_safe(pattern);
        assert_se(fd >= 0);
        assert_se(unlink(pattern) == 0);

        assert_se(asprintf(&cmd2, "ls -l /proc/"PID_FMT"/fd/%d", getpid_cached(), fd2) > 0);
        (void) system(cmd2);
        assert_se(readlink_malloc(cmd2 + 6, &ans2) >= 0);
        log_debug("link2: %s", ans2);
        assert_se(endswith(ans2, " (deleted)"));

        pattern = strjoina(p, "/tmpfiles-test");
        assert_se(tempfn_random(pattern, NULL, &d) >= 0);

        fd = open_tmpfile_linkable(d, O_RDWR|O_CLOEXEC, &tmp);
        assert_se(fd >= 0);
        assert_se(write(fd, "foobar\n", 7) == 7);

        assert_se(touch(d) >= 0);
        assert_se(link_tmpfile(fd, tmp, d) == -EEXIST);
        assert_se(unlink(d) >= 0);
        assert_se(link_tmpfile(fd, tmp, d) >= 0);

        assert_se(read_one_line_file(d, &line) >= 0);
        assert_se(streq(line, "foobar"));
        assert_se(unlink(d) >= 0);

        return 0;
}
Beispiel #7
0
static int raw_pull_maybe_convert_qcow2(RawPull *i) {
        _cleanup_close_ int converted_fd = -1;
        _cleanup_free_ char *t = NULL;
        int r;

        assert(i);
        assert(i->raw_job);

        r = qcow2_detect(i->raw_job->disk_fd);
        if (r < 0)
                return log_error_errno(r, "Failed to detect whether this is a QCOW2 image: %m");
        if (r == 0)
                return 0;

        /* This is a QCOW2 image, let's convert it */
        r = tempfn_random(i->final_path, NULL, &t);
        if (r < 0)
                return log_oom();

        converted_fd = open(t, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664);
        if (converted_fd < 0)
                return log_error_errno(errno, "Failed to create %s: %m", t);

        r = chattr_fd(converted_fd, FS_NOCOW_FL, FS_NOCOW_FL);
        if (r < 0)
                log_warning_errno(errno, "Failed to set file attributes on %s: %m", t);

        log_info("Unpacking QCOW2 file.");

        r = qcow2_convert(i->raw_job->disk_fd, converted_fd);
        if (r < 0) {
                unlink(t);
                return log_error_errno(r, "Failed to convert qcow2 image: %m");
        }

        (void) unlink(i->temp_path);
        free(i->temp_path);
        i->temp_path = t;
        t = NULL;

        safe_close(i->raw_job->disk_fd);
        i->raw_job->disk_fd = converted_fd;
        converted_fd = -1;

        return 1;
}
Beispiel #8
0
static int tar_pull_job_on_open_disk_tar(PullJob *j) {
        TarPull *i;
        int r;

        assert(j);
        assert(j->userdata);

        i = j->userdata;
        assert(i->tar_job == j);
        assert(!i->final_path);
        assert(!i->temp_path);
        assert(i->tar_pid <= 0);

        r = pull_make_path(j->url, j->etag, i->image_root, ".tar-", NULL, &i->final_path);
        if (r < 0)
                return log_oom();

        r = tempfn_random(i->final_path, NULL, &i->temp_path);
        if (r < 0)
                return log_oom();

        mkdir_parents_label(i->temp_path, 0700);

        r = btrfs_subvol_make(i->temp_path);
        if (r == -ENOTTY) {
                if (mkdir(i->temp_path, 0755) < 0)
                        return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path);
        } else if (r < 0)
                return log_error_errno(errno, "Failed to create subvolume %s: %m", i->temp_path);
        else
                (void) import_assign_pool_quota_and_warn(i->temp_path);

        j->disk_fd = import_fork_tar_x(i->temp_path, &i->tar_pid);
        if (j->disk_fd < 0)
                return j->disk_fd;

        return 0;
}
Beispiel #9
0
static int dkr_pull_job_on_open_disk(PullJob *j) {
        const char *base;
        DkrPull *i;
        int r;

        assert(j);
        assert(j->userdata);

        i = j->userdata;
        assert(i->layer_job == j);
        assert(i->final_path);
        assert(!i->temp_path);
        assert(i->tar_pid <= 0);

        r = tempfn_random(i->final_path, &i->temp_path);
        if (r < 0)
                return log_oom();

        mkdir_parents_label(i->temp_path, 0700);

        base = dkr_pull_current_base_layer(i);
        if (base) {
                const char *base_path;

                base_path = strjoina(i->image_root, "/.dkr-", base);
                r = btrfs_subvol_snapshot(base_path, i->temp_path, BTRFS_SNAPSHOT_FALLBACK_COPY);
        } else
                r = btrfs_subvol_make(i->temp_path);
        if (r < 0)
                return log_error_errno(r, "Failed to make btrfs subvolume %s: %m", i->temp_path);

        j->disk_fd = import_fork_tar_x(i->temp_path, &i->tar_pid);
        if (j->disk_fd < 0)
                return j->disk_fd;

        return 0;
}
Beispiel #10
0
static int raw_pull_make_local_copy(RawPull *i) {
        _cleanup_free_ char *tp = NULL;
        _cleanup_close_ int dfd = -1;
        const char *p;
        int r;

        assert(i);
        assert(i->raw_job);

        if (!i->local)
                return 0;

        if (i->raw_job->etag_exists) {
                /* We have downloaded this one previously, reopen it */

                assert(i->raw_job->disk_fd < 0);

                i->raw_job->disk_fd = open(i->final_path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
                if (i->raw_job->disk_fd < 0)
                        return log_error_errno(errno, "Failed to open vendor image: %m");
        } else {
                /* We freshly downloaded the image, use it */

                assert(i->raw_job->disk_fd >= 0);

                if (lseek(i->raw_job->disk_fd, SEEK_SET, 0) == (off_t) -1)
                        return log_error_errno(errno, "Failed to seek to beginning of vendor image: %m");
        }

        p = strjoina(i->image_root, "/", i->local, ".raw");

        if (i->force_local)
                (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);

        r = tempfn_random(p, NULL, &tp);
        if (r < 0)
                return log_oom();

        dfd = open(tp, O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664);
        if (dfd < 0)
                return log_error_errno(errno, "Failed to create writable copy of image: %m");

        /* Turn off COW writing. This should greatly improve
         * performance on COW file systems like btrfs, since it
         * reduces fragmentation caused by not allowing in-place
         * writes. */
        r = chattr_fd(dfd, FS_NOCOW_FL, FS_NOCOW_FL);
        if (r < 0)
                log_warning_errno(r, "Failed to set file attributes on %s: %m", tp);

        r = copy_bytes(i->raw_job->disk_fd, dfd, (uint64_t) -1, COPY_REFLINK);
        if (r < 0) {
                unlink(tp);
                return log_error_errno(r, "Failed to make writable copy of image: %m");
        }

        (void) copy_times(i->raw_job->disk_fd, dfd);
        (void) copy_xattr(i->raw_job->disk_fd, dfd);

        dfd = safe_close(dfd);

        r = rename(tp, p);
        if (r < 0)  {
                r = log_error_errno(errno, "Failed to move writable image into place: %m");
                unlink(tp);
                return r;
        }

        log_info("Created new local image '%s'.", i->local);

        if (i->roothash) {
                r = raw_pull_copy_auxiliary_file(i, ".roothash", &i->roothash_path);
                if (r < 0)
                        return r;
        }

        if (i->settings) {
                r = raw_pull_copy_auxiliary_file(i, ".nspawn", &i->settings_path);
                if (r < 0)
                        return r;
        }

        return 0;
}
Beispiel #11
0
                if (fd_to < 0) {
                        if (errno != -ENOENT)
                                return log_error_errno(errno, "Failed to open \"%s\" for reading: %m", to);
                } else {
                        r = version_check(fd_from, from, fd_to, to);
                        if (r < 0)
                                return r;

                        if (lseek(fd_from, 0, SEEK_SET) == (off_t) -1)
                                return log_error_errno(errno, "Failed to seek in \%s\": %m", from);

                        fd_to = safe_close(fd_to);
                }
        }

        r = tempfn_random(to, NULL, &t);
        if (r < 0)
                return log_oom();

        RUN_WITH_UMASK(0000) {
                fd_to = open(t, O_WRONLY|O_CREAT|O_CLOEXEC|O_EXCL|O_NOFOLLOW, 0644);
                if (fd_to < 0)
                        return log_error_errno(errno, "Failed to open \"%s\" for writing: %m", t);
        }

        r = copy_bytes(fd_from, fd_to, (uint64_t) -1, COPY_REFLINK);
        if (r < 0) {
                (void) unlink(t);
                return log_error_errno(r, "Failed to copy data from \"%s\" to \"%s\": %m", from, t);
        }
Beispiel #12
0
static int save_external_coredump(
                const char *info[_INFO_LEN],
                uid_t uid,
                char **ret_filename,
                int *ret_fd,
                uint64_t *ret_size) {

        _cleanup_free_ char *fn = NULL, *tmp = NULL;
        _cleanup_close_ int fd = -1;
        struct stat st;
        int r;

        assert(info);
        assert(ret_filename);
        assert(ret_fd);
        assert(ret_size);

        r = make_filename(info, &fn);
        if (r < 0)
                return log_error_errno(r, "Failed to determine coredump file name: %m");

        r = tempfn_random(fn, NULL, &tmp);
        if (r < 0)
                return log_error_errno(r, "Failed to determine temporary file name: %m");

        mkdir_p_label("/var/lib/systemd/coredump", 0755);

        fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
        if (fd < 0)
                return log_error_errno(errno, "Failed to create coredump file %s: %m", tmp);

        r = copy_bytes(STDIN_FILENO, fd, arg_process_size_max, false);
        if (r == -EFBIG) {
                log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", info[INFO_PID], info[INFO_COMM]);
                goto fail;
        } else if (IN_SET(r, -EDQUOT, -ENOSPC)) {
                log_error("Not enough disk space for coredump of %s (%s), refusing.", info[INFO_PID], info[INFO_COMM]);
                goto fail;
        } else if (r < 0) {
                log_error_errno(r, "Failed to dump coredump to file: %m");
                goto fail;
        }

        if (fstat(fd, &st) < 0) {
                log_error_errno(errno, "Failed to fstat coredump %s: %m", tmp);
                goto fail;
        }

        if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
                log_error_errno(errno, "Failed to seek on %s: %m", tmp);
                goto fail;
        }

#if defined(HAVE_XZ) || defined(HAVE_LZ4)
        /* If we will remove the coredump anyway, do not compress. */
        if (maybe_remove_external_coredump(NULL, st.st_size) == 0
            && arg_compress) {

                _cleanup_free_ char *fn_compressed = NULL, *tmp_compressed = NULL;
                _cleanup_close_ int fd_compressed = -1;

                fn_compressed = strappend(fn, COMPRESSED_EXT);
                if (!fn_compressed) {
                        log_oom();
                        goto uncompressed;
                }

                r = tempfn_random(fn_compressed, NULL, &tmp_compressed);
                if (r < 0) {
                        log_error_errno(r, "Failed to determine temporary file name for %s: %m", fn_compressed);
                        goto uncompressed;
                }

                fd_compressed = open(tmp_compressed, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
                if (fd_compressed < 0) {
                        log_error_errno(errno, "Failed to create file %s: %m", tmp_compressed);
                        goto uncompressed;
                }

                r = compress_stream(fd, fd_compressed, -1);
                if (r < 0) {
                        log_error_errno(r, "Failed to compress %s: %m", tmp_compressed);
                        goto fail_compressed;
                }

                r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, info, uid);
                if (r < 0)
                        goto fail_compressed;

                /* OK, this worked, we can get rid of the uncompressed version now */
                unlink_noerrno(tmp);

                *ret_filename = fn_compressed;     /* compressed */
                *ret_fd = fd;                      /* uncompressed */
                *ret_size = (uint64_t) st.st_size; /* uncompressed */

                fn_compressed = NULL;
                fd = -1;

                return 0;

        fail_compressed:
                unlink_noerrno(tmp_compressed);
        }

uncompressed:
#endif
        r = fix_permissions(fd, tmp, fn, info, uid);
        if (r < 0)
                goto fail;

        *ret_filename = fn;
        *ret_fd = fd;
        *ret_size = (uint64_t) st.st_size;

        fn = NULL;
        fd = -1;

        return 0;

fail:
        unlink_noerrno(tmp);
        return r;
}
Beispiel #13
0
int tar_export_start(TarExport *e, const char *path, int fd, ImportCompressType compress) {
    _cleanup_close_ int sfd = -1;
    int r;

    assert(e);
    assert(path);
    assert(fd >= 0);
    assert(compress < _IMPORT_COMPRESS_TYPE_MAX);
    assert(compress != IMPORT_COMPRESS_UNKNOWN);

    if (e->output_fd >= 0)
        return -EBUSY;

    sfd = open(path, O_DIRECTORY|O_RDONLY|O_NOCTTY|O_CLOEXEC);
    if (sfd < 0)
        return -errno;

    if (fstat(sfd, &e->st) < 0)
        return -errno;

    r = fd_nonblock(fd, true);
    if (r < 0)
        return r;

    r = free_and_strdup(&e->path, path);
    if (r < 0)
        return r;

    e->quota_referenced = (uint64_t) -1;

    if (e->st.st_ino == 256) { /* might be a btrfs subvolume? */
        BtrfsQuotaInfo q;

        r = btrfs_subvol_get_subtree_quota_fd(sfd, 0, &q);
        if (r >= 0)
            e->quota_referenced = q.referenced;

        e->temp_path = mfree(e->temp_path);

        r = tempfn_random(path, NULL, &e->temp_path);
        if (r < 0)
            return r;

        /* Let's try to make a snapshot, if we can, so that the export is atomic */
        r = btrfs_subvol_snapshot_fd(sfd, e->temp_path, BTRFS_SNAPSHOT_READ_ONLY|BTRFS_SNAPSHOT_RECURSIVE);
        if (r < 0) {
            log_debug_errno(r, "Couldn't create snapshot %s of %s, not exporting atomically: %m", e->temp_path, path);
            e->temp_path = mfree(e->temp_path);
        }
    }

    r = import_compress_init(&e->compress, compress);
    if (r < 0)
        return r;

    r = sd_event_add_io(e->event, &e->output_event_source, fd, EPOLLOUT, tar_export_on_output, e);
    if (r == -EPERM) {
        r = sd_event_add_defer(e->event, &e->output_event_source, tar_export_on_defer, e);
        if (r < 0)
            return r;

        r = sd_event_source_set_enabled(e->output_event_source, SD_EVENT_ON);
    }
    if (r < 0)
        return r;

    e->tar_fd = import_fork_tar_c(e->temp_path ?: e->path, &e->tar_pid);
    if (e->tar_fd < 0) {
        e->output_event_source = sd_event_source_unref(e->output_event_source);
        return e->tar_fd;
    }

    e->output_fd = fd;
    return r;
}