import-tar.c revision 587fec427c80b6c34dcf1d7570f891fcb652a7c5
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering This file is part of systemd.
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering Copyright 2015 Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering systemd is free software; you can redistribute it and/or modify it
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering under the terms of the GNU Lesser General Public License as published by
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering (at your option) any later version.
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering systemd is distributed in the hope that it will be useful, but
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering Lesser General Public License for more details.
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering You should have received a copy of the GNU Lesser General Public License
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
b6e676ce41508e2aeea22202fc8f234126177f52Lennart PoetteringTarImport* tar_import_unref(TarImport *i) {
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering sd_event_source_unref(i->input_event_source);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering (void) kill_and_sigcont(i->tar_pid, SIGKILL);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering (void) wait_for_terminate(i->tar_pid, NULL);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering (void) btrfs_subvol_remove(i->temp_path);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering (void) rm_rf_dangerous(i->temp_path, false, true, false);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering _cleanup_(tar_import_unrefp) TarImport *i = NULL;
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering RATELIMIT_INIT(i->progress_rate_limit, 100 * USEC_PER_MSEC, 1);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering i->image_root = strdup(image_root ?: "/var/lib/machines");
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering i->grow_machine_directory = path_startswith(i->image_root, "/var/lib/machines");
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringstatic void tar_import_report_progress(TarImport *i) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering /* We have no size information, unless the source is a regular file */
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (i->written_compressed >= (uint64_t) i->st.st_size)
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering percent = (unsigned) ((i->written_compressed * UINT64_C(100)) / (uint64_t) i->st.st_size);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (!ratelimit_test(&i->progress_rate_limit))
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringstatic int tar_import_finish(TarImport *i) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering r = wait_for_terminate_and_warn("tar", i->tar_pid, true);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering (void) btrfs_subvol_remove(i->final_path);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering (void) rm_rf_dangerous(i->final_path, false, true, false);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (renameat2(AT_FDCWD, i->temp_path, AT_FDCWD, i->final_path, RENAME_NOREPLACE) < 0)
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return log_error_errno(errno, "Failed to move image into place: %m");
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringstatic int tar_import_fork_tar(TarImport *i) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering i->final_path = strjoin(i->image_root, "/", i->local, NULL);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering r = tempfn_random(i->final_path, &i->temp_path);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering (void) mkdir_parents_label(i->temp_path, 0700);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering } else if (r < 0)
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return log_error_errno(errno, "Failed to create subvolume %s: %m", i->temp_path);
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering i->tar_fd = import_fork_tar_x(i->temp_path, &i->tar_pid);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringstatic int tar_import_write(const void *p, size_t sz, void *userdata) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (i->grow_machine_directory && i->written_since_last_grow >= GROW_INTERVAL_BYTES) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringstatic int tar_import_process(TarImport *i) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering assert(i->buffer_size < sizeof(i->buffer));
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering l = read(i->input_fd, i->buffer + i->buffer_size, sizeof(i->buffer) - i->buffer_size);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering r = log_error_errno(errno, "Failed to read input file: %m");
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (i->compress.type == IMPORT_COMPRESS_UNKNOWN) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (i->compress.type == IMPORT_COMPRESS_UNKNOWN) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering r = import_uncompress_detect(&i->compress, i->buffer, i->buffer_size);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering log_error("Failed to detect file compression: %m");
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (r == 0) /* Need more data */
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering r = import_uncompress(&i->compress, i->buffer, i->buffer_size, tar_import_write, i);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering log_error_errno(r, "Failed to decode and write: %m");
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringstatic int tar_import_on_input(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringstatic int tar_import_on_defer(sd_event_source *s, void *userdata) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringint tar_import_start(TarImport *i, int fd, const char *local, bool force_local, bool read_only) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering r = sd_event_add_io(i->event, &i->input_event_source, fd, EPOLLIN, tar_import_on_input, i);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering /* This fd does not support epoll, for example because it is a regular file. Busy read in that case */
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering r = sd_event_add_defer(i->event, &i->input_event_source, tar_import_on_defer, i);