import-tar.c revision b6e676ce41508e2aeea22202fc8f234126177f52
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye This file is part of systemd.
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye Copyright 2015 Lennart Poettering
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye systemd is free software; you can redistribute it and/or modify it
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye under the terms of the GNU Lesser General Public License as published by
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye the Free Software Foundation; either version 2.1 of the License, or
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye (at your option) any later version.
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye systemd is distributed in the hope that it will be useful, but
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye WITHOUT ANY WARRANTY; without even the implied warranty of
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye Lesser General Public License for more details.
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye You should have received a copy of the GNU Lesser General Public License
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye along with systemd; If not, see <http://www.gnu.org/licenses/>.
0a0811923cbbd2976425db6f4c78eed811c2825bKnut Anders Hatlen (void) btrfs_subvol_remove(i->temp_path);
fe80b749cd764b1f0f72b2f913b1fe10581911c3Knut Anders Hatlen (void) rm_rf_dangerous(i->temp_path, false, true, false);
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik _cleanup_(tar_import_unrefp) TarImport *i = NULL;
49f592091468eac515dde6139fbc8efa26056b0aJorgen Austvik RATELIMIT_INIT(i->progress_rate_limit, 500 * USEC_PER_MSEC, 1);
49f592091468eac515dde6139fbc8efa26056b0aJorgen Austvik i->image_root = strdup(image_root ?: "/var/lib/machines");
945f4c3c36a15447913781dfb1894b34f2941c57Jorgen Austvik i->grow_machine_directory = path_startswith(i->image_root, "/var/lib/machines");
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Koscostatic void tar_import_report_progress(TarImport *i) {
45909b3ef8c6e568a87482cb890fec7b5dbb7733Lubos Kosco /* We have no size information, unless the source is a regular file */
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco if (i->written_compressed >= (uint64_t) i->st.st_size)
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco percent = (unsigned) ((i->written_compressed * UINT64_C(100)) / (uint64_t) i->st.st_size);
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent);
3d35131df8607ae05b064219b9448afc5c4b550aKnut Anders Hatlen r = wait_for_terminate_and_warn("tar", i->tar_pid, true);
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen (void) btrfs_subvol_remove(i->final_path);
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen (void) rm_rf_dangerous(i->final_path, false, true, false);
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen if (renameat2(AT_FDCWD, i->temp_path, AT_FDCWD, i->final_path, RENAME_NOREPLACE) < 0)
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen return log_error_errno(errno, "Failed to move image into place: %m");
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlenstatic int tar_import_fork_tar(TarImport *i) {
7b046969a1b2565787df8ae3a8126359e8cd6fafTrond Norbye i->final_path = strjoin(i->image_root, "/", i->local, NULL);
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco r = tempfn_random(i->final_path, &i->temp_path);
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye (void) mkdir_parents_label(i->temp_path, 0700);
9cf297d9a579835e9336d587eaee187ca0954767Knut Anders Hatlen return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path);
2dbc1835e0ae88ad102e2b9a85e5c7b5298b14b6Knut Anders Hatlen } else if (r < 0)
2dbc1835e0ae88ad102e2b9a85e5c7b5298b14b6Knut Anders Hatlen return log_error_errno(errno, "Failed to create subvolume %s: %m", i->temp_path);
2dbc1835e0ae88ad102e2b9a85e5c7b5298b14b6Knut Anders Hatlen i->tar_fd = import_fork_tar(i->temp_path, &i->tar_pid);
2dbc1835e0ae88ad102e2b9a85e5c7b5298b14b6Knut Anders Hatlenstatic int tar_import_write(const void *p, size_t sz, void *userdata) {
9cf297d9a579835e9336d587eaee187ca0954767Knut Anders Hatlen if (i->grow_machine_directory && i->written_since_last_grow >= GROW_INTERVAL_BYTES) {
2dbc1835e0ae88ad102e2b9a85e5c7b5298b14b6Knut Anders Hatlen assert(i->buffer_size < sizeof(i->buffer));
2dbc1835e0ae88ad102e2b9a85e5c7b5298b14b6Knut Anders Hatlen l = read(i->input_fd, i->buffer + i->buffer_size, sizeof(i->buffer) - i->buffer_size);
9661674ed58ba62a40e43d1a4b38d5e77c3c6545Knut Anders Hatlen r = log_error_errno(errno, "Failed to read input file: %m");
9cf297d9a579835e9336d587eaee187ca0954767Knut Anders Hatlen if (i->compress.type == IMPORT_COMPRESS_UNKNOWN) {
523201f786f6b12b7cf54091c6e5be167878cbeeTrond Norbye if (i->compress.type == IMPORT_COMPRESS_UNKNOWN) {
523201f786f6b12b7cf54091c6e5be167878cbeeTrond Norbye r = import_uncompress_detect(&i->compress, i->buffer, i->buffer_size);
523201f786f6b12b7cf54091c6e5be167878cbeeTrond Norbye if (r < 0) {
523201f786f6b12b7cf54091c6e5be167878cbeeTrond Norbye log_error("Failed to detect file compression: %m");
0a0811923cbbd2976425db6f4c78eed811c2825bKnut Anders Hatlen if (r == 0) /* Need more data */
0a0811923cbbd2976425db6f4c78eed811c2825bKnut Anders Hatlen r = import_uncompress(&i->compress, i->buffer, i->buffer_size, tar_import_write, i);
a07b2874263e3c5f0cd2e83441719415d53059c2Knut Anders Hatlen log_error_errno(r, "Failed to decode and write: %m");
5e6c91d7e77062129cd0b6ac8aaa546dff216419Lubos Koscostatic int tar_import_on_input(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
a7f25b0d188e4ea80ddcabf3ac52ade1bdb4ebecLubos Koscostatic int tar_import_on_defer(sd_event_source *s, void *userdata) {
edcb01bf549171673fd0bb4239f2edfc7a810397Knut Anders Hatlenint tar_import_start(TarImport *i, int fd, const char *local, bool force_local, bool read_only) {
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik r = sd_event_add_io(i->event, &i->input_event_source, fd, EPOLLIN, tar_import_on_input, i);
52cf1d63b1f1b231ff1e86eca2058d88560579b5Lubos Kosco /* This fd does not support epoll, for example because it is a regular file. Busy read in that case */
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik r = sd_event_add_defer(i->event, &i->input_event_source, tar_import_on_defer, i);