chiark / gitweb /
importd: add API for exporting container/VM images
[elogind.git] / src / import / import-common.c
index 6c3f347e759fd4deb2f2f6dc26f4a6187f6a0425..aede2f9b3686622bcb8659dc7abaf590a4cdbfaa 100644 (file)
@@ -69,7 +69,7 @@ int import_make_read_only(const char *path) {
         return import_make_read_only_fd(fd);
 }
 
-int import_fork_tar(const char *path, pid_t *ret) {
+int import_fork_tar_x(const char *path, pid_t *ret) {
         _cleanup_close_pair_ int pipefd[2] = { -1, -1 };
         pid_t pid;
         int r;
@@ -148,3 +148,77 @@ int import_fork_tar(const char *path, pid_t *ret) {
 
         return r;
 }
+
+int import_fork_tar_c(const char *path, pid_t *ret) {
+        _cleanup_close_pair_ int pipefd[2] = { -1, -1 };
+        pid_t pid;
+        int r;
+
+        assert(path);
+        assert(ret);
+
+        if (pipe2(pipefd, O_CLOEXEC) < 0)
+                return log_error_errno(errno, "Failed to create pipe for tar: %m");
+
+        pid = fork();
+        if (pid < 0)
+                return log_error_errno(errno, "Failed to fork off tar: %m");
+
+        if (pid == 0) {
+                int null_fd;
+                uint64_t retain = (1ULL << CAP_DAC_OVERRIDE);
+
+                /* Child */
+
+                reset_all_signal_handlers();
+                reset_signal_mask();
+                assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
+
+                pipefd[0] = safe_close(pipefd[0]);
+
+                if (dup2(pipefd[1], STDOUT_FILENO) != STDOUT_FILENO) {
+                        log_error_errno(errno, "Failed to dup2() fd: %m");
+                        _exit(EXIT_FAILURE);
+                }
+
+                if (pipefd[1] != STDOUT_FILENO)
+                        pipefd[1] = safe_close(pipefd[1]);
+
+                null_fd = open("/dev/null", O_RDONLY|O_NOCTTY);
+                if (null_fd < 0) {
+                        log_error_errno(errno, "Failed to open /dev/null: %m");
+                        _exit(EXIT_FAILURE);
+                }
+
+                if (dup2(null_fd, STDIN_FILENO) != STDIN_FILENO) {
+                        log_error_errno(errno, "Failed to dup2() fd: %m");
+                        _exit(EXIT_FAILURE);
+                }
+
+                if (null_fd != STDIN_FILENO)
+                        null_fd = safe_close(null_fd);
+
+                fd_cloexec(STDIN_FILENO, false);
+                fd_cloexec(STDOUT_FILENO, false);
+                fd_cloexec(STDERR_FILENO, false);
+
+                if (unshare(CLONE_NEWNET) < 0)
+                        log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
+
+                r = capability_bounding_set_drop(~retain, true);
+                if (r < 0)
+                        log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
+
+                execlp("tar", "tar", "--sparse", "-C", path, "-c", ".", NULL);
+                log_error_errno(errno, "Failed to execute tar: %m");
+                _exit(EXIT_FAILURE);
+        }
+
+        pipefd[1] = safe_close(pipefd[1]);
+        r = pipefd[0];
+        pipefd[0] = -1;
+
+        *ret = pid;
+
+        return r;
+}