]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/import/import-common.c
fd-util: add new helper move_fd() and make use of it
[thirdparty/systemd.git] / src / import / import-common.c
CommitLineData
b6e676ce
LP
1/***
2 This file is part of systemd.
3
4 Copyright 2015 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
618234a5 20#include <sched.h>
b6e676ce
LP
21#include <sys/prctl.h>
22#include <sys/stat.h>
23#include <unistd.h>
24
b6e676ce 25#include "btrfs-util.h"
430f0182 26#include "capability-util.h"
3ffd4af2
LP
27#include "fd-util.h"
28#include "import-common.h"
24882e06 29#include "signal-util.h"
618234a5 30#include "util.h"
b6e676ce
LP
31
32int import_make_read_only_fd(int fd) {
33 int r;
34
35 assert(fd >= 0);
36
37 /* First, let's make this a read-only subvolume if it refers
38 * to a subvolume */
39 r = btrfs_subvol_set_read_only_fd(fd, true);
4c701096 40 if (IN_SET(r, -ENOTTY, -ENOTDIR, -EINVAL)) {
b6e676ce
LP
41 struct stat st;
42
43 /* This doesn't refer to a subvolume, or the file
44 * system isn't even btrfs. In that, case fall back to
45 * chmod()ing */
46
47 r = fstat(fd, &st);
48 if (r < 0)
49 return log_error_errno(errno, "Failed to stat temporary image: %m");
50
51 /* Drop "w" flag */
52 if (fchmod(fd, st.st_mode & 07555) < 0)
53 return log_error_errno(errno, "Failed to chmod() final image: %m");
54
55 return 0;
56
57 } else if (r < 0)
58 return log_error_errno(r, "Failed to make subvolume read-only: %m");
59
60 return 0;
61}
62
63int import_make_read_only(const char *path) {
64 _cleanup_close_ int fd = 1;
65
66 fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
67 if (fd < 0)
68 return log_error_errno(errno, "Failed to open %s: %m", path);
69
70 return import_make_read_only_fd(fd);
71}
72
587fec42 73int import_fork_tar_x(const char *path, pid_t *ret) {
b6e676ce
LP
74 _cleanup_close_pair_ int pipefd[2] = { -1, -1 };
75 pid_t pid;
76 int r;
77
78 assert(path);
79 assert(ret);
80
81 if (pipe2(pipefd, O_CLOEXEC) < 0)
82 return log_error_errno(errno, "Failed to create pipe for tar: %m");
83
84 pid = fork();
85 if (pid < 0)
86 return log_error_errno(errno, "Failed to fork off tar: %m");
87
88 if (pid == 0) {
89 int null_fd;
90 uint64_t retain =
91 (1ULL << CAP_CHOWN) |
92 (1ULL << CAP_FOWNER) |
93 (1ULL << CAP_FSETID) |
94 (1ULL << CAP_MKNOD) |
95 (1ULL << CAP_SETFCAP) |
96 (1ULL << CAP_DAC_OVERRIDE);
97
98 /* Child */
99
ce30c8dc
LP
100 (void) reset_all_signal_handlers();
101 (void) reset_signal_mask();
b6e676ce
LP
102 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
103
104 pipefd[1] = safe_close(pipefd[1]);
105
046a82c1
LP
106 r = move_fd(pipefd[0], STDIN_FILENO, false);
107 if (r < 0) {
108 log_error_errno(r, "Failed to move fd: %m");
b6e676ce
LP
109 _exit(EXIT_FAILURE);
110 }
111
b6e676ce
LP
112 null_fd = open("/dev/null", O_WRONLY|O_NOCTTY);
113 if (null_fd < 0) {
114 log_error_errno(errno, "Failed to open /dev/null: %m");
115 _exit(EXIT_FAILURE);
116 }
117
046a82c1
LP
118 r = move_fd(null_fd, STDOUT_FILENO, false);
119 if (r < 0) {
120 log_error_errno(r, "Failed to move fd: %m");
b6e676ce
LP
121 _exit(EXIT_FAILURE);
122 }
123
913f38e4 124 stdio_unset_cloexec();
b6e676ce
LP
125
126 if (unshare(CLONE_NEWNET) < 0)
127 log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
128
a103496c 129 r = capability_bounding_set_drop(retain, true);
b6e676ce
LP
130 if (r < 0)
131 log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
132
2944758c 133 execlp("tar", "tar", "--numeric-owner", "-C", path, "-px", "--xattrs", "--xattrs-include=*", NULL);
b6e676ce
LP
134 log_error_errno(errno, "Failed to execute tar: %m");
135 _exit(EXIT_FAILURE);
136 }
137
138 pipefd[0] = safe_close(pipefd[0]);
139 r = pipefd[1];
140 pipefd[1] = -1;
141
142 *ret = pid;
143
144 return r;
145}
587fec42
LP
146
147int import_fork_tar_c(const char *path, pid_t *ret) {
148 _cleanup_close_pair_ int pipefd[2] = { -1, -1 };
149 pid_t pid;
150 int r;
151
152 assert(path);
153 assert(ret);
154
155 if (pipe2(pipefd, O_CLOEXEC) < 0)
156 return log_error_errno(errno, "Failed to create pipe for tar: %m");
157
158 pid = fork();
159 if (pid < 0)
160 return log_error_errno(errno, "Failed to fork off tar: %m");
161
162 if (pid == 0) {
163 int null_fd;
164 uint64_t retain = (1ULL << CAP_DAC_OVERRIDE);
165
166 /* Child */
167
ce30c8dc
LP
168 (void) reset_all_signal_handlers();
169 (void) reset_signal_mask();
587fec42
LP
170 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
171
172 pipefd[0] = safe_close(pipefd[0]);
173
046a82c1
LP
174 r = move_fd(pipefd[1], STDOUT_FILENO, false);
175 if (r < 0) {
176 log_error_errno(r, "Failed to move fd: %m");
587fec42
LP
177 _exit(EXIT_FAILURE);
178 }
179
587fec42
LP
180 null_fd = open("/dev/null", O_RDONLY|O_NOCTTY);
181 if (null_fd < 0) {
182 log_error_errno(errno, "Failed to open /dev/null: %m");
183 _exit(EXIT_FAILURE);
184 }
185
046a82c1
LP
186 r = move_fd(null_fd, STDIN_FILENO, false);
187 if (r < 0) {
188 log_error_errno(errno, "Failed to move fd: %m");
587fec42
LP
189 _exit(EXIT_FAILURE);
190 }
191
913f38e4 192 stdio_unset_cloexec();
587fec42
LP
193
194 if (unshare(CLONE_NEWNET) < 0)
195 log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
196
a103496c 197 r = capability_bounding_set_drop(retain, true);
587fec42
LP
198 if (r < 0)
199 log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
200
2944758c 201 execlp("tar", "tar", "-C", path, "-c", "--xattrs", "--xattrs-include=*", ".", NULL);
587fec42
LP
202 log_error_errno(errno, "Failed to execute tar: %m");
203 _exit(EXIT_FAILURE);
204 }
205
206 pipefd[1] = safe_close(pipefd[1]);
207 r = pipefd[0];
208 pipefd[0] = -1;
209
210 *ret = pid;
211
212 return r;
213}