Beispiel #1
0
static int setup_machine_raw(uint64_t size, sd_bus_error *error) {
        _cleanup_free_ char *tmp = NULL;
        _cleanup_close_ int fd = -1;
        struct statvfs ss;
        pid_t pid = 0;
        int r;

        /* We want to be able to make use of btrfs-specific file
         * system features, in particular subvolumes, reflinks and
         * quota. Hence, if we detect that /var/lib/machines.raw is
         * not located on btrfs, let's create a loopback file, place a
         * btrfs file system into it, and mount it to
         * /var/lib/machines. */

        fd = open("/var/lib/machines.raw", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
        if (fd >= 0)
                return TAKE_FD(fd);

        if (errno != ENOENT)
                return sd_bus_error_set_errnof(error, errno, "Failed to open /var/lib/machines.raw: %m");

        r = tempfn_xxxxxx("/var/lib/machines.raw", NULL, &tmp);
        if (r < 0)
                return r;

        (void) mkdir_p_label("/var/lib", 0755);
        fd = open(tmp, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0600);
        if (fd < 0)
                return sd_bus_error_set_errnof(error, errno, "Failed to create /var/lib/machines.raw: %m");

        if (fstatvfs(fd, &ss) < 0) {
                r = sd_bus_error_set_errnof(error, errno, "Failed to determine free space on /var/lib/machines.raw: %m");
                goto fail;
        }

        if (ss.f_bsize * ss.f_bavail < VAR_LIB_MACHINES_FREE_MIN) {
                r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Not enough free disk space to set up /var/lib/machines.");
                goto fail;
        }

        if (ftruncate(fd, size) < 0) {
                r = sd_bus_error_set_errnof(error, errno, "Failed to enlarge /var/lib/machines.raw: %m");
                goto fail;
        }

        r = safe_fork("(mkfs)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
        if (r < 0) {
                sd_bus_error_set_errnof(error, r, "Failed to fork mkfs.btrfs: %m");
                goto fail;
        }
        if (r == 0) {

                /* Child */

                fd = safe_close(fd);

                execlp("mkfs.btrfs", "-Lvar-lib-machines", tmp, NULL);
                if (errno == ENOENT)
                        _exit(99);

                _exit(EXIT_FAILURE);
        }

        r = wait_for_terminate_and_check("mkfs", pid, 0);
        pid = 0;

        if (r < 0) {
                sd_bus_error_set_errnof(error, r, "Failed to wait for mkfs.btrfs: %m");
                goto fail;
        }
        if (r == 99) {
                r = sd_bus_error_set_errnof(error, ENOENT, "Cannot set up /var/lib/machines, mkfs.btrfs is missing");
                goto fail;
        }
        if (r != EXIT_SUCCESS) {
                r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "mkfs.btrfs failed with error code %i", r);
                goto fail;
        }

        r = rename_noreplace(AT_FDCWD, tmp, AT_FDCWD, "/var/lib/machines.raw");
        if (r < 0) {
                sd_bus_error_set_errnof(error, r, "Failed to move /var/lib/machines.raw into place: %m");
                goto fail;
        }

        return TAKE_FD(fd);

fail:
        unlink_noerrno(tmp);

        if (pid > 1)
                kill_and_sigcont(pid, SIGKILL);

        return r;
}
Beispiel #2
0
static void tar_pull_job_on_finished(PullJob *j) {
        TarPull *i;
        int r;

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

        i = j->userdata;

        if (j == i->settings_job) {
                if (j->error != 0)
                        log_info_errno(j->error, "Settings file could not be retrieved, proceeding without.");
        } else if (j->error != 0 && j != i->signature_job) {
                if (j == i->checksum_job)
                        log_error_errno(j->error, "Failed to retrieve SHA256 checksum, cannot verify. (Try --verify=no?)");
                else
                        log_error_errno(j->error, "Failed to retrieve image file. (Wrong URL?)");

                r = j->error;
                goto finish;
        }

        /* This is invoked if either the download completed
         * successfully, or the download was skipped because we
         * already have the etag. */

        if (!tar_pull_is_done(i))
                return;

        if (i->signature_job && i->checksum_job->style == VERIFICATION_PER_DIRECTORY && i->signature_job->error != 0) {
                log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)");

                r = i->signature_job->error;
                goto finish;
        }

        i->tar_job->disk_fd = safe_close(i->tar_job->disk_fd);
        if (i->settings_job)
                i->settings_job->disk_fd = safe_close(i->settings_job->disk_fd);

        r = tar_pull_determine_path(i, NULL, &i->final_path);
        if (r < 0)
                goto finish;

        if (i->tar_pid > 0) {
                r = wait_for_terminate_and_check("tar", i->tar_pid, WAIT_LOG);
                i->tar_pid = 0;
                if (r < 0)
                        goto finish;
                if (r != EXIT_SUCCESS) {
                        r = -EIO;
                        goto finish;
                }
        }

        if (!i->tar_job->etag_exists) {
                /* This is a new download, verify it, and move it into place */

                tar_pull_report_progress(i, TAR_VERIFYING);

                r = pull_verify(i->tar_job, NULL, i->settings_job, i->checksum_job, i->signature_job);
                if (r < 0)
                        goto finish;

                tar_pull_report_progress(i, TAR_FINALIZING);

                r = import_make_read_only(i->temp_path);
                if (r < 0)
                        goto finish;

                r = rename_noreplace(AT_FDCWD, i->temp_path, AT_FDCWD, i->final_path);
                if (r < 0) {
                        log_error_errno(r, "Failed to rename to final image name to %s: %m", i->final_path);
                        goto finish;
                }

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

                if (i->settings_job &&
                    i->settings_job->error == 0) {

                        /* Also move the settings file into place, if it exists. Note that we do so only if we also
                         * moved the tar file in place, to keep things strictly in sync. */
                        assert(i->settings_temp_path);

                        /* Regenerate final name for this auxiliary file, we might know the etag of the file now, and
                         * we should incorporate it in the file name if we can */
                        i->settings_path = mfree(i->settings_path);

                        r = tar_pull_determine_path(i, ".nspawn", &i->settings_path);
                        if (r < 0)
                                goto finish;

                        r = import_make_read_only(i->settings_temp_path);
                        if (r < 0)
                                goto finish;

                        r = rename_noreplace(AT_FDCWD, i->settings_temp_path, AT_FDCWD, i->settings_path);
                        if (r < 0) {
                                log_error_errno(r, "Failed to rename settings file to %s: %m", i->settings_path);
                                goto finish;
                        }

                        i->settings_temp_path = mfree(i->settings_temp_path);
                }
        }

        tar_pull_report_progress(i, TAR_COPYING);

        r = tar_pull_make_local_copy(i);
        if (r < 0)
                goto finish;

        r = 0;

finish:
        if (i->on_finished)
                i->on_finished(i, r, i->userdata);
        else
                sd_event_exit(i->event, r);
}
Beispiel #3
0
static int do_execute(
                char **directories,
                usec_t timeout,
                gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX],
                void* const callback_args[_STDOUT_CONSUME_MAX],
                int output_fd,
                char *argv[],
                char *envp[],
                ExecDirFlags flags) {

        _cleanup_hashmap_free_free_ Hashmap *pids = NULL;
        _cleanup_strv_free_ char **paths = NULL;
        char **path, **e;
        int r;
        bool parallel_execution;

        /* We fork this all off from a child process so that we can somewhat cleanly make
         * use of SIGALRM to set a time limit.
         *
         * We attempt to perform parallel execution if configured by the user, however
         * if `callbacks` is nonnull, execution must be serial.
         */
        parallel_execution = FLAGS_SET(flags, EXEC_DIR_PARALLEL) && !callbacks;

        r = conf_files_list_strv(&paths, NULL, NULL, CONF_FILES_EXECUTABLE|CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, (const char* const*) directories);
        if (r < 0)
                return log_error_errno(r, "Failed to enumerate executables: %m");

        if (parallel_execution) {
                pids = hashmap_new(NULL);
                if (!pids)
                        return log_oom();
        }

        /* Abort execution of this process after the timout. We simply rely on SIGALRM as
         * default action terminating the process, and turn on alarm(). */

        if (timeout != USEC_INFINITY)
                alarm(DIV_ROUND_UP(timeout, USEC_PER_SEC));

        STRV_FOREACH(e, envp)
                if (putenv(*e) != 0)
                        return log_error_errno(errno, "Failed to set environment variable: %m");

        STRV_FOREACH(path, paths) {
                _cleanup_free_ char *t = NULL;
                _cleanup_close_ int fd = -1;
                pid_t pid;

                t = strdup(*path);
                if (!t)
                        return log_oom();

                if (callbacks) {
                        fd = open_serialization_fd(basename(*path));
                        if (fd < 0)
                                return log_error_errno(fd, "Failed to open serialization file: %m");
                }

                r = do_spawn(t, argv, fd, &pid);
                if (r <= 0)
                        continue;

                if (parallel_execution) {
                        r = hashmap_put(pids, PID_TO_PTR(pid), t);
                        if (r < 0)
                                return log_oom();
                        t = NULL;
                } else {
                        r = wait_for_terminate_and_check(t, pid, WAIT_LOG);
                        if (FLAGS_SET(flags, EXEC_DIR_IGNORE_ERRORS)) {
                                if (r < 0)
                                        continue;
                        } else if (r > 0)
                                return r;

                        if (callbacks) {
                                if (lseek(fd, 0, SEEK_SET) < 0)
                                        return log_error_errno(errno, "Failed to seek on serialization fd: %m");

                                r = callbacks[STDOUT_GENERATE](fd, callback_args[STDOUT_GENERATE]);
                                fd = -1;
                                if (r < 0)
                                        return log_error_errno(r, "Failed to process output from %s: %m", *path);
                        }
                }
        }