]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/import/import-common.c
util: split out signal-util.[ch] from util.[ch]
[thirdparty/systemd.git] / src / import / import-common.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2015 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/prctl.h>
23 #include <sys/stat.h>
24 #include <unistd.h>
25
26 #include "util.h"
27 #include "btrfs-util.h"
28 #include "capability.h"
29 #include "signal-util.h"
30 #include "import-common.h"
31
32 int 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);
40 if (r == -ENOTTY || r == -ENOTDIR || r == -EINVAL) {
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
63 int 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
73 int import_fork_tar_x(const char *path, pid_t *ret) {
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
100 reset_all_signal_handlers();
101 reset_signal_mask();
102 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
103
104 pipefd[1] = safe_close(pipefd[1]);
105
106 if (dup2(pipefd[0], STDIN_FILENO) != STDIN_FILENO) {
107 log_error_errno(errno, "Failed to dup2() fd: %m");
108 _exit(EXIT_FAILURE);
109 }
110
111 if (pipefd[0] != STDIN_FILENO)
112 pipefd[0] = safe_close(pipefd[0]);
113
114 null_fd = open("/dev/null", O_WRONLY|O_NOCTTY);
115 if (null_fd < 0) {
116 log_error_errno(errno, "Failed to open /dev/null: %m");
117 _exit(EXIT_FAILURE);
118 }
119
120 if (dup2(null_fd, STDOUT_FILENO) != STDOUT_FILENO) {
121 log_error_errno(errno, "Failed to dup2() fd: %m");
122 _exit(EXIT_FAILURE);
123 }
124
125 if (null_fd != STDOUT_FILENO)
126 null_fd = safe_close(null_fd);
127
128 fd_cloexec(STDIN_FILENO, false);
129 fd_cloexec(STDOUT_FILENO, false);
130 fd_cloexec(STDERR_FILENO, false);
131
132 if (unshare(CLONE_NEWNET) < 0)
133 log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
134
135 r = capability_bounding_set_drop(~retain, true);
136 if (r < 0)
137 log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
138
139 execlp("tar", "tar", "--numeric-owner", "-C", path, "-px", NULL);
140 log_error_errno(errno, "Failed to execute tar: %m");
141 _exit(EXIT_FAILURE);
142 }
143
144 pipefd[0] = safe_close(pipefd[0]);
145 r = pipefd[1];
146 pipefd[1] = -1;
147
148 *ret = pid;
149
150 return r;
151 }
152
153 int import_fork_tar_c(const char *path, pid_t *ret) {
154 _cleanup_close_pair_ int pipefd[2] = { -1, -1 };
155 pid_t pid;
156 int r;
157
158 assert(path);
159 assert(ret);
160
161 if (pipe2(pipefd, O_CLOEXEC) < 0)
162 return log_error_errno(errno, "Failed to create pipe for tar: %m");
163
164 pid = fork();
165 if (pid < 0)
166 return log_error_errno(errno, "Failed to fork off tar: %m");
167
168 if (pid == 0) {
169 int null_fd;
170 uint64_t retain = (1ULL << CAP_DAC_OVERRIDE);
171
172 /* Child */
173
174 reset_all_signal_handlers();
175 reset_signal_mask();
176 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
177
178 pipefd[0] = safe_close(pipefd[0]);
179
180 if (dup2(pipefd[1], STDOUT_FILENO) != STDOUT_FILENO) {
181 log_error_errno(errno, "Failed to dup2() fd: %m");
182 _exit(EXIT_FAILURE);
183 }
184
185 if (pipefd[1] != STDOUT_FILENO)
186 pipefd[1] = safe_close(pipefd[1]);
187
188 null_fd = open("/dev/null", O_RDONLY|O_NOCTTY);
189 if (null_fd < 0) {
190 log_error_errno(errno, "Failed to open /dev/null: %m");
191 _exit(EXIT_FAILURE);
192 }
193
194 if (dup2(null_fd, STDIN_FILENO) != STDIN_FILENO) {
195 log_error_errno(errno, "Failed to dup2() fd: %m");
196 _exit(EXIT_FAILURE);
197 }
198
199 if (null_fd != STDIN_FILENO)
200 null_fd = safe_close(null_fd);
201
202 fd_cloexec(STDIN_FILENO, false);
203 fd_cloexec(STDOUT_FILENO, false);
204 fd_cloexec(STDERR_FILENO, false);
205
206 if (unshare(CLONE_NEWNET) < 0)
207 log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
208
209 r = capability_bounding_set_drop(~retain, true);
210 if (r < 0)
211 log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
212
213 execlp("tar", "tar", "--sparse", "-C", path, "-c", ".", NULL);
214 log_error_errno(errno, "Failed to execute tar: %m");
215 _exit(EXIT_FAILURE);
216 }
217
218 pipefd[1] = safe_close(pipefd[1]);
219 r = pipefd[0];
220 pipefd[0] = -1;
221
222 *ret = pid;
223
224 return r;
225 }