chiark / gitweb /
importd: when listing transfers, show progress percentage
[elogind.git] / src / import / import-tar.c
index e09ecaba115d612051791cf54ec1aad43c17ee9b..999aa8ab5e8c5dd9924402e7fe36b64e9cc97a47 100644 (file)
@@ -22,6 +22,7 @@
 #include <sys/prctl.h>
 #include <curl/curl.h>
 
+#include "sd-daemon.h"
 #include "utf8.h"
 #include "strv.h"
 #include "copy.h"
 #include "util.h"
 #include "macro.h"
 #include "mkdir.h"
+#include "import-util.h"
 #include "curl-util.h"
 #include "import-job.h"
-#include "import-util.h"
+#include "import-common.h"
 #include "import-tar.h"
 
+typedef enum TarProgress {
+        TAR_DOWNLOADING,
+        TAR_VERIFYING,
+        TAR_FINALIZING,
+        TAR_COPYING,
+} TarProgress;
+
 struct TarImport {
         sd_event *event;
         CurlGlue *glue;
@@ -133,6 +142,53 @@ int tar_import_new(
         return 0;
 }
 
+static void tar_import_report_progress(TarImport *i, TarProgress p) {
+        unsigned percent;
+
+        assert(i);
+
+        switch (p) {
+
+        case TAR_DOWNLOADING: {
+                unsigned remain = 85;
+
+                percent = 0;
+
+                if (i->checksum_job) {
+                        percent += i->checksum_job->progress_percent * 5 / 100;
+                        remain -= 5;
+                }
+
+                if (i->signature_job) {
+                        percent += i->signature_job->progress_percent * 5 / 100;
+                        remain -= 5;
+                }
+
+                if (i->tar_job)
+                        percent += i->tar_job->progress_percent * remain / 100;
+                break;
+        }
+
+        case TAR_VERIFYING:
+                percent = 85;
+                break;
+
+        case TAR_FINALIZING:
+                percent = 90;
+                break;
+
+        case TAR_COPYING:
+                percent = 95;
+                break;
+
+        default:
+                assert_not_reached("Unknown progress state");
+        }
+
+        sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent);
+        log_debug("Combined progress %u%%", percent);
+}
+
 static int tar_import_make_local_copy(TarImport *i) {
         int r;
 
@@ -208,10 +264,14 @@ static void tar_import_job_on_finished(ImportJob *j) {
         if (!i->tar_job->etag_exists) {
                 /* This is a new download, verify it, and move it into place */
 
+                tar_import_report_progress(i, TAR_VERIFYING);
+
                 r = import_verify(i->tar_job, i->checksum_job, i->signature_job);
                 if (r < 0)
                         goto finish;
 
+                tar_import_report_progress(i, TAR_FINALIZING);
+
                 r = import_make_read_only(i->temp_path);
                 if (r < 0)
                         goto finish;
@@ -225,6 +285,8 @@ static void tar_import_job_on_finished(ImportJob *j) {
                 i->temp_path = NULL;
         }
 
+        tar_import_report_progress(i, TAR_COPYING);
+
         r = tar_import_make_local_copy(i);
         if (r < 0)
                 goto finish;
@@ -269,56 +331,22 @@ static int tar_import_job_on_open_disk(ImportJob *j) {
         } else if (r < 0)
                 return log_error_errno(errno, "Failed to create subvolume %s: %m", i->temp_path);
 
-        if (pipe2(pipefd, O_CLOEXEC) < 0)
-                return log_error_errno(errno, "Failed to create pipe for tar: %m");
-
-        i->tar_pid = fork();
-        if (i->tar_pid < 0)
-                return log_error_errno(errno, "Failed to fork off tar: %m");
-        if (i->tar_pid == 0) {
-                int null_fd;
-
-                /* Child */
-
-                reset_all_signal_handlers();
-                reset_signal_mask();
-                assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
-                pipefd[1] = safe_close(pipefd[1]);
-
-                if (dup2(pipefd[0], STDIN_FILENO) != STDIN_FILENO) {
-                        log_error_errno(errno, "Failed to dup2() fd: %m");
-                        _exit(EXIT_FAILURE);
-                }
-
-                if (pipefd[0] != STDIN_FILENO)
-                        safe_close(pipefd[0]);
-
-                null_fd = open("/dev/null", O_WRONLY|O_NOCTTY);
-                if (null_fd < 0) {
-                        log_error_errno(errno, "Failed to open /dev/null: %m");
-                        _exit(EXIT_FAILURE);
-                }
-
-                if (dup2(null_fd, STDOUT_FILENO) != STDOUT_FILENO) {
-                        log_error_errno(errno, "Failed to dup2() fd: %m");
-                        _exit(EXIT_FAILURE);
-                }
+        j->disk_fd = import_fork_tar(i->temp_path, &i->tar_pid);
+        if (j->disk_fd < 0)
+                return j->disk_fd;
 
-                if (null_fd != STDOUT_FILENO)
-                        safe_close(null_fd);
+        return 0;
+}
 
-                execlp("tar", "tar", "--numeric-owner", "-C", i->temp_path, "-px", NULL);
-                log_error_errno(errno, "Failed to execute tar: %m");
-                _exit(EXIT_FAILURE);
-        }
+static void tar_import_job_on_progress(ImportJob *j) {
+        TarImport *i;
 
-        pipefd[0] = safe_close(pipefd[0]);
+        assert(j);
+        assert(j->userdata);
 
-        j->disk_fd = pipefd[1];
-        pipefd[1] = -1;
+        i = j->userdata;
 
-        return 0;
+        tar_import_report_progress(i, TAR_DOWNLOADING);
 }
 
 int tar_import_pull(TarImport *i, const char *url, const char *local, bool force_local, ImportVerify verify) {
@@ -347,6 +375,7 @@ int tar_import_pull(TarImport *i, const char *url, const char *local, bool force
 
         i->tar_job->on_finished = tar_import_job_on_finished;
         i->tar_job->on_open_disk = tar_import_job_on_open_disk;
+        i->tar_job->on_progress = tar_import_job_on_progress;
         i->tar_job->calc_checksum = verify != IMPORT_VERIFY_NO;
 
         r = import_find_old_etags(url, i->image_root, DT_DIR, ".tar-", NULL, &i->tar_job->old_etags);
@@ -362,17 +391,20 @@ int tar_import_pull(TarImport *i, const char *url, const char *local, bool force
                 return r;
 
         if (i->checksum_job) {
+                i->checksum_job->on_progress = tar_import_job_on_progress;
+
                 r = import_job_begin(i->checksum_job);
                 if (r < 0)
                         return r;
         }
 
         if (i->signature_job) {
+                i->signature_job->on_progress = tar_import_job_on_progress;
+
                 r = import_job_begin(i->signature_job);
                 if (r < 0)
                         return r;
         }
 
         return 0;
-
 }