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; }
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); }
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); } } }