/src/lxc/src/lxc/lxccontainer.c
Line | Count | Source |
1 | | /* SPDX-License-Identifier: LGPL-2.1+ */ |
2 | | |
3 | | #include "config.h" |
4 | | |
5 | | #include <arpa/inet.h> |
6 | | #include <dirent.h> |
7 | | #include <errno.h> |
8 | | #include <fcntl.h> |
9 | | #include <grp.h> |
10 | | #include <libgen.h> |
11 | | #include <mntent.h> |
12 | | #include <pthread.h> |
13 | | #include <sched.h> |
14 | | #include <stdarg.h> |
15 | | #include <stdint.h> |
16 | | #include <stdio.h> |
17 | | #include <stdlib.h> |
18 | | #include <sys/file.h> |
19 | | #include <sys/mman.h> |
20 | | #include <sys/mount.h> |
21 | | #include <sys/stat.h> |
22 | | #include <sys/syscall.h> |
23 | | #include <sys/sysmacros.h> |
24 | | #include <sys/types.h> |
25 | | #include <sys/wait.h> |
26 | | #include <unistd.h> |
27 | | |
28 | | #include "lxc.h" |
29 | | |
30 | | #include "netns_ifaddrs.h" |
31 | | #include "af_unix.h" |
32 | | #include "api_extensions.h" |
33 | | #include "attach.h" |
34 | | #include "cgroup.h" |
35 | | #include "macro.h" |
36 | | #include "commands.h" |
37 | | #include "commands_utils.h" |
38 | | #include "conf.h" |
39 | | #include "confile.h" |
40 | | #include "confile_utils.h" |
41 | | #include "criu.h" |
42 | | #include "error.h" |
43 | | #include "idmap_utils.h" |
44 | | #include "initutils.h" |
45 | | #include "log.h" |
46 | | #include "lxc.h" |
47 | | #include "lxclock.h" |
48 | | #include "memory_utils.h" |
49 | | #include "monitor.h" |
50 | | #include "namespace.h" |
51 | | #include "network.h" |
52 | | #include "open_utils.h" |
53 | | #include "parse.h" |
54 | | #include "process_utils.h" |
55 | | #include "start.h" |
56 | | #include "state.h" |
57 | | #include "storage.h" |
58 | | #include "storage/btrfs.h" |
59 | | #include "storage/overlay.h" |
60 | | #include "storage_utils.h" |
61 | | #include "sync.h" |
62 | | #include "syscall_wrappers.h" |
63 | | #include "terminal.h" |
64 | | #include "utils.h" |
65 | | #include "version.h" |
66 | | |
67 | | #if HAVE_OPENSSL |
68 | | #include <openssl/evp.h> |
69 | | #endif |
70 | | |
71 | | /* major()/minor() */ |
72 | | #ifdef MAJOR_IN_MKDEV |
73 | | #include <sys/mkdev.h> |
74 | | #endif |
75 | | |
76 | | #if !HAVE_STRLCPY |
77 | | #include "include/strlcpy.h" |
78 | | #endif |
79 | | |
80 | 0 | lxc_log_define(lxccontainer, lxc); Unexecuted instantiation: lxccontainer.c:LXC_ERROR Unexecuted instantiation: lxccontainer.c:LXC_DEBUG Unexecuted instantiation: lxccontainer.c:LXC_TRACE Unexecuted instantiation: lxccontainer.c:LXC_NOTICE Unexecuted instantiation: lxccontainer.c:LXC_INFO Unexecuted instantiation: lxccontainer.c:LXC_WARN |
81 | 0 |
|
82 | 0 | static bool do_lxcapi_destroy(struct lxc_container *c); |
83 | 0 | static const char *lxcapi_get_config_path(struct lxc_container *c); |
84 | 0 | #define do_lxcapi_get_config_path(c) lxcapi_get_config_path(c) |
85 | | static bool do_lxcapi_set_config_item(struct lxc_container *c, const char *key, const char *v); |
86 | | static bool container_destroy(struct lxc_container *c, |
87 | | struct lxc_storage *storage); |
88 | | static bool get_snappath_dir(struct lxc_container *c, char *snappath); |
89 | | static bool lxcapi_snapshot_destroy_all(struct lxc_container *c); |
90 | | static bool do_lxcapi_save_config(struct lxc_container *c, const char *alt_file); |
91 | | |
92 | | static bool config_file_exists(const char *lxcpath, const char *cname) |
93 | 0 | { |
94 | 0 | __do_free char *fname = NULL; |
95 | 0 | int ret; |
96 | 0 | size_t len; |
97 | | |
98 | | /* $lxcpath + '/' + $cname + '/config' + \0 */ |
99 | 0 | len = strlen(lxcpath) + 1 + strlen(cname) + 1 + strlen(LXC_CONFIG_FNAME) + 1; |
100 | 0 | fname = must_realloc(NULL, len); |
101 | 0 | ret = strnprintf(fname, len, "%s/%s/%s", lxcpath, cname, LXC_CONFIG_FNAME); |
102 | 0 | if (ret < 0) |
103 | 0 | return false; |
104 | | |
105 | 0 | return file_exists(fname); |
106 | 0 | } |
107 | | |
108 | | /* |
109 | | * A few functions to help detect when a container creation failed. If a |
110 | | * container creation was killed partway through, then trying to actually start |
111 | | * that container could harm the host. We detect this by creating a 'partial' |
112 | | * file under the container directory, and keeping an advisory lock. When |
113 | | * container creation completes, we remove that file. When we load or try to |
114 | | * start a container, if we find that file, without a flock, we remove the |
115 | | * container. |
116 | | */ |
117 | | enum { |
118 | | LXC_CREATE_FAILED = -1, |
119 | | LXC_CREATE_SUCCESS = 0, |
120 | | LXC_CREATE_ONGOING = 1, |
121 | | LXC_CREATE_INCOMPLETE = 2, |
122 | | }; |
123 | | |
124 | | static int ongoing_create(struct lxc_container *c) |
125 | 7.99k | { |
126 | 7.99k | __do_close int fd = -EBADF; |
127 | 7.99k | __do_free char *path = NULL; |
128 | 7.99k | struct flock lk = {0}; |
129 | 7.99k | int ret; |
130 | 7.99k | size_t len; |
131 | | |
132 | 7.99k | len = strlen(c->config_path) + 1 + strlen(c->name) + 1 + strlen(LXC_PARTIAL_FNAME) + 1; |
133 | 7.99k | path = must_realloc(NULL, len); |
134 | 7.99k | ret = strnprintf(path, len, "%s/%s/%s", c->config_path, c->name, LXC_PARTIAL_FNAME); |
135 | 7.99k | if (ret < 0) |
136 | 0 | return LXC_CREATE_FAILED; |
137 | | |
138 | 7.99k | fd = open(path, O_RDWR | O_CLOEXEC); |
139 | 7.99k | if (fd < 0) { |
140 | 7.99k | if (errno != ENOENT) |
141 | 0 | return LXC_CREATE_FAILED; |
142 | | |
143 | 7.99k | return LXC_CREATE_SUCCESS; |
144 | 7.99k | } |
145 | | |
146 | 0 | lk.l_type = F_WRLCK; |
147 | 0 | lk.l_whence = SEEK_SET; |
148 | | /* |
149 | | * F_OFD_GETLK requires that l_pid be set to 0 otherwise the kernel |
150 | | * will EINVAL us. |
151 | | */ |
152 | 0 | lk.l_pid = 0; |
153 | |
|
154 | 0 | ret = fcntl(fd, F_OFD_GETLK, &lk); |
155 | 0 | if (ret < 0 && errno == EINVAL) { |
156 | 0 | ret = flock(fd, LOCK_EX | LOCK_NB); |
157 | 0 | if (ret < 0 && errno == EWOULDBLOCK) |
158 | 0 | ret = 0; |
159 | 0 | } |
160 | | |
161 | | /* F_OFD_GETLK will not send us back a pid so don't check it. */ |
162 | 0 | if (ret == 0) |
163 | | /* Create is still ongoing. */ |
164 | 0 | return LXC_CREATE_ONGOING; |
165 | | |
166 | | /* Create completed but partial is still there. */ |
167 | 0 | return LXC_CREATE_INCOMPLETE; |
168 | 0 | } |
169 | | |
170 | | static int create_partial(int fd_rootfs, struct lxc_container *c) |
171 | 0 | { |
172 | 0 | __do_close int fd_partial = -EBADF; |
173 | 0 | int ret; |
174 | 0 | struct flock lk = {0}; |
175 | |
|
176 | 0 | fd_partial = openat(fd_rootfs, LXC_PARTIAL_FNAME, O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0000); |
177 | 0 | if (fd_partial < 0) |
178 | 0 | return syserror("errno(%d) - Failed to create \"%d/" LXC_PARTIAL_FNAME "\" to mark container as partially created", errno, fd_rootfs); |
179 | | |
180 | 0 | lk.l_type = F_WRLCK; |
181 | 0 | lk.l_whence = SEEK_SET; |
182 | |
|
183 | 0 | ret = fcntl(fd_partial, F_OFD_SETLKW, &lk); |
184 | 0 | if (ret < 0) { |
185 | 0 | if (errno == EINVAL) { |
186 | 0 | ret = flock(fd_partial, LOCK_EX); |
187 | 0 | if (ret == 0) |
188 | 0 | return move_fd(fd_partial); |
189 | 0 | } |
190 | | |
191 | 0 | return syserror("Failed to lock partial file \"%d/" LXC_PARTIAL_FNAME"\"", fd_rootfs); |
192 | 0 | } |
193 | | |
194 | 0 | TRACE("Created \"%d/" LXC_PARTIAL_FNAME "\" to mark container as partially created", fd_rootfs); |
195 | 0 | return move_fd(fd_partial); |
196 | 0 | } |
197 | | |
198 | | static void remove_partial(struct lxc_container *c, int fd) |
199 | 0 | { |
200 | 0 | __do_free char *path = NULL; |
201 | 0 | int ret; |
202 | 0 | size_t len; |
203 | |
|
204 | 0 | close(fd); |
205 | | |
206 | | /* $lxcpath + '/' + $name + '/partial' + \0 */ |
207 | 0 | len = strlen(c->config_path) + 1 + strlen(c->name) + 1 + strlen(LXC_PARTIAL_FNAME) + 1; |
208 | 0 | path = must_realloc(NULL, len); |
209 | 0 | ret = strnprintf(path, len, "%s/%s/%s", c->config_path, c->name, LXC_PARTIAL_FNAME); |
210 | 0 | if (ret < 0) |
211 | 0 | return; |
212 | | |
213 | 0 | ret = unlink(path); |
214 | 0 | if (ret < 0) |
215 | 0 | SYSERROR("Failed to remove partial file %s", path); |
216 | 0 | } |
217 | | |
218 | | /* LOCKING |
219 | | * 1. container_mem_lock(c) protects the struct lxc_container from multiple threads. |
220 | | * 2. container_disk_lock(c) protects the on-disk container data - in particular the |
221 | | * container configuration file. |
222 | | * The container_disk_lock also takes the container_mem_lock. |
223 | | * 3. thread_mutex protects process data (ex: fd table) from multiple threads. |
224 | | * NOTHING mutexes two independent programs with their own struct |
225 | | * lxc_container for the same c->name, between API calls. For instance, |
226 | | * c->config_read(); c->start(); Between those calls, data on disk |
227 | | * could change (which shouldn't bother the caller unless for instance |
228 | | * the rootfs get moved). c->config_read(); update; c->config_write(); |
229 | | * Two such updaters could race. The callers should therefore check their |
230 | | * results. Trying to prevent that would necessarily expose us to deadlocks |
231 | | * due to hung callers. So I prefer to keep the locks only within our own |
232 | | * functions, not across functions. |
233 | | * |
234 | | * If you're going to clone while holding a lxccontainer, increment |
235 | | * c->numthreads (under privlock) before forking. When deleting, |
236 | | * decrement numthreads under privlock, then if it hits 0 you can delete. |
237 | | * Do not ever use a lxccontainer whose numthreads you did not bump. |
238 | | */ |
239 | | static void lxc_container_free(struct lxc_container *c) |
240 | 7.99k | { |
241 | 7.99k | if (!c) |
242 | 0 | return; |
243 | | |
244 | 7.99k | free(c->configfile); |
245 | 7.99k | c->configfile = NULL; |
246 | | |
247 | 7.99k | free(c->error_string); |
248 | 7.99k | c->error_string = NULL; |
249 | | |
250 | 7.99k | if (c->slock) { |
251 | 7.99k | lxc_putlock(c->slock); |
252 | 7.99k | c->slock = NULL; |
253 | 7.99k | } |
254 | | |
255 | 7.99k | if (c->privlock) { |
256 | 7.99k | lxc_putlock(c->privlock); |
257 | 7.99k | c->privlock = NULL; |
258 | 7.99k | } |
259 | | |
260 | 7.99k | free(c->name); |
261 | 7.99k | c->name = NULL; |
262 | | |
263 | 7.99k | if (c->lxc_conf) { |
264 | 7.92k | lxc_conf_free(c->lxc_conf); |
265 | 7.92k | c->lxc_conf = NULL; |
266 | 7.92k | } |
267 | | |
268 | 7.99k | free(c->config_path); |
269 | 7.99k | c->config_path = NULL; |
270 | | |
271 | 7.99k | free(c); |
272 | 7.99k | } |
273 | | |
274 | | /* Consider the following case: |
275 | | * |
276 | | * |====================================================================| |
277 | | * | freer | racing get()er | |
278 | | * |====================================================================| |
279 | | * | lxc_container_put() | lxc_container_get() | |
280 | | * | \ lxclock(c->privlock) | c->numthreads < 1? (no) | |
281 | | * | \ c->numthreads = 0 | \ lxclock(c->privlock) -> waits | |
282 | | * | \ lxcunlock() | \ | |
283 | | * | \ lxc_container_free() | \ lxclock() returns | |
284 | | * | | \ c->numthreads < 1 -> return 0 | |
285 | | * | \ \ (free stuff) | | |
286 | | * | \ \ sem_destroy(privlock) | | |
287 | | * |_______________________________|____________________________________| |
288 | | * |
289 | | * When the get()er checks numthreads the first time, one of the following |
290 | | * is true: |
291 | | * 1. freer has set numthreads = 0. get() returns 0 |
292 | | * 2. freer is between lxclock and setting numthreads to 0. get()er will |
293 | | * sem_wait on privlock, get lxclock after freer() drops it, then see |
294 | | * numthreads is 0 and exit without touching lxclock again.. |
295 | | * 3. freer has not yet locked privlock. If get()er runs first, then put()er |
296 | | * will see --numthreads = 1 and not call lxc_container_free(). |
297 | | */ |
298 | | |
299 | | int lxc_container_get(struct lxc_container *c) |
300 | 0 | { |
301 | 0 | if (!c) |
302 | 0 | return 0; |
303 | | |
304 | | /* If someone else has already started freeing the container, don't try |
305 | | * to take the lock, which may be invalid. |
306 | | */ |
307 | 0 | if (c->numthreads < 1) |
308 | 0 | return 0; |
309 | | |
310 | 0 | if (container_mem_lock(c)) |
311 | 0 | return 0; |
312 | | |
313 | | /* Bail without trying to unlock, bc the privlock is now probably in |
314 | | * freed memory. |
315 | | */ |
316 | 0 | if (c->numthreads < 1) |
317 | 0 | return 0; |
318 | | |
319 | 0 | c->numthreads++; |
320 | 0 | container_mem_unlock(c); |
321 | |
|
322 | 0 | return 1; |
323 | 0 | } |
324 | | |
325 | | int lxc_container_put(struct lxc_container *c) |
326 | 7.99k | { |
327 | 7.99k | if (!c) |
328 | 0 | return -1; |
329 | | |
330 | 7.99k | if (container_mem_lock(c)) |
331 | 0 | return -1; |
332 | | |
333 | 7.99k | c->numthreads--; |
334 | | |
335 | 7.99k | if (c->numthreads < 1) { |
336 | 7.99k | container_mem_unlock(c); |
337 | 7.99k | lxc_container_free(c); |
338 | 7.99k | return 1; |
339 | 7.99k | } |
340 | | |
341 | 0 | container_mem_unlock(c); |
342 | 0 | return 0; |
343 | 7.99k | } |
344 | | |
345 | | static bool do_lxcapi_is_defined(struct lxc_container *c) |
346 | 0 | { |
347 | 0 | int statret; |
348 | 0 | struct stat statbuf; |
349 | 0 | bool ret = false; |
350 | |
|
351 | 0 | if (!c) |
352 | 0 | return false; |
353 | | |
354 | 0 | if (container_mem_lock(c)) |
355 | 0 | return false; |
356 | | |
357 | 0 | if (!c->configfile) |
358 | 0 | goto on_error; |
359 | | |
360 | 0 | statret = stat(c->configfile, &statbuf); |
361 | 0 | if (statret != 0) |
362 | 0 | goto on_error; |
363 | | |
364 | 0 | ret = true; |
365 | |
|
366 | 0 | on_error: |
367 | 0 | container_mem_unlock(c); |
368 | 0 | return ret; |
369 | 0 | } |
370 | | |
371 | | #define WRAP_API(rettype, fnname) \ |
372 | 0 | static rettype fnname(struct lxc_container *c) \ |
373 | 0 | { \ |
374 | 0 | rettype ret; \ |
375 | 0 | bool reset_config = false; \ |
376 | 0 | \ |
377 | 0 | if (!current_config && c && c->lxc_conf) { \ |
378 | 0 | current_config = c->lxc_conf; \ |
379 | 0 | reset_config = true; \ |
380 | 0 | } \ |
381 | 0 | \ |
382 | 0 | ret = do_##fnname(c); \ |
383 | 0 | if (reset_config) \ |
384 | 0 | current_config = NULL; \ |
385 | 0 | \ |
386 | 0 | return ret; \ |
387 | 0 | } |
388 | | |
389 | | #define WRAP_API_1(rettype, fnname, t1) \ |
390 | 0 | static rettype fnname(struct lxc_container *c, t1 a1) \ |
391 | 0 | { \ |
392 | 0 | rettype ret; \ |
393 | 0 | bool reset_config = false; \ |
394 | 0 | \ |
395 | 0 | if (!current_config && c && c->lxc_conf) { \ |
396 | 0 | current_config = c->lxc_conf; \ |
397 | 0 | reset_config = true; \ |
398 | 0 | } \ |
399 | 0 | \ |
400 | 0 | ret = do_##fnname(c, a1); \ |
401 | 0 | if (reset_config) \ |
402 | 0 | current_config = NULL; \ |
403 | 0 | \ |
404 | 0 | return ret; \ |
405 | 0 | } |
406 | | |
407 | | #define WRAP_API_2(rettype, fnname, t1, t2) \ |
408 | 7.92k | static rettype fnname(struct lxc_container *c, t1 a1, t2 a2) \ |
409 | 7.92k | { \ |
410 | 7.92k | rettype ret; \ |
411 | 7.92k | bool reset_config = false; \ |
412 | 7.92k | \ |
413 | 7.92k | if (!current_config && c && c->lxc_conf) { \ |
414 | 0 | current_config = c->lxc_conf; \ |
415 | 0 | reset_config = true; \ |
416 | 0 | } \ |
417 | 7.92k | \ |
418 | 7.92k | ret = do_##fnname(c, a1, a2); \ |
419 | 7.92k | if (reset_config) \ |
420 | 7.92k | current_config = NULL; \ |
421 | 7.92k | \ |
422 | 7.92k | return ret; \ |
423 | 7.92k | } |
424 | | |
425 | | #define WRAP_API_3(rettype, fnname, t1, t2, t3) \ |
426 | 6.67k | static rettype fnname(struct lxc_container *c, t1 a1, t2 a2, t3 a3) \ |
427 | 6.67k | { \ |
428 | 6.67k | rettype ret; \ |
429 | 6.67k | bool reset_config = false; \ |
430 | 6.67k | \ |
431 | 6.67k | if (!current_config && c && c->lxc_conf) { \ |
432 | 6.67k | current_config = c->lxc_conf; \ |
433 | 6.67k | reset_config = true; \ |
434 | 6.67k | } \ |
435 | 6.67k | \ |
436 | 6.67k | ret = do_##fnname(c, a1, a2, a3); \ |
437 | 6.67k | if (reset_config) \ |
438 | 6.67k | current_config = NULL; \ |
439 | 6.67k | \ |
440 | 6.67k | return ret; \ |
441 | 6.67k | } |
442 | | |
443 | | #define WRAP_API_5(rettype, fnname, t1, t2, t3, t4, t5) \ |
444 | | static rettype fnname(struct lxc_container *c, t1 a1, t2 a2, t3 a3, \ |
445 | 0 | t4 a4, t5 a5) \ |
446 | 0 | { \ |
447 | 0 | rettype ret; \ |
448 | 0 | bool reset_config = false; \ |
449 | 0 | \ |
450 | 0 | if (!current_config && c && c->lxc_conf) { \ |
451 | 0 | current_config = c->lxc_conf; \ |
452 | 0 | reset_config = true; \ |
453 | 0 | } \ |
454 | 0 | \ |
455 | 0 | ret = do_##fnname(c, a1, a2, a3, a4, a5); \ |
456 | 0 | if (reset_config) \ |
457 | 0 | current_config = NULL; \ |
458 | 0 | \ |
459 | 0 | return ret; \ |
460 | 0 | } |
461 | | |
462 | | #define WRAP_API_6(rettype, fnname, t1, t2, t3, t4, t5, t6) \ |
463 | | static rettype fnname(struct lxc_container *c, t1 a1, t2 a2, t3 a3, \ |
464 | 0 | t4 a4, t5 a5, t6 a6) \ |
465 | 0 | { \ |
466 | 0 | rettype ret; \ |
467 | 0 | bool reset_config = false; \ |
468 | 0 | \ |
469 | 0 | if (!current_config && c && c->lxc_conf) { \ |
470 | 0 | current_config = c->lxc_conf; \ |
471 | 0 | reset_config = true; \ |
472 | 0 | } \ |
473 | 0 | \ |
474 | 0 | ret = do_##fnname(c, a1, a2, a3, a4, a5, a6); \ |
475 | 0 | if (reset_config) \ |
476 | 0 | current_config = NULL; \ |
477 | 0 | \ |
478 | 0 | return ret; \ |
479 | 0 | } |
480 | | |
481 | 0 | WRAP_API(bool, lxcapi_is_defined) |
482 | | |
483 | | static const char *do_lxcapi_state(struct lxc_container *c) |
484 | 0 | { |
485 | 0 | lxc_state_t s; |
486 | |
|
487 | 0 | if (!c) |
488 | 0 | return NULL; |
489 | | |
490 | 0 | s = lxc_getstate(c->name, c->config_path, c->rcv_timeout); |
491 | 0 | return lxc_state2str(s); |
492 | 0 | } |
493 | | |
494 | 0 | WRAP_API(const char *, lxcapi_state) |
495 | | |
496 | | static bool is_stopped(struct lxc_container *c) |
497 | 0 | { |
498 | 0 | lxc_state_t s; |
499 | |
|
500 | 0 | s = lxc_getstate(c->name, c->config_path, c->rcv_timeout); |
501 | 0 | return (s == STOPPED); |
502 | 0 | } |
503 | | |
504 | | static bool do_lxcapi_is_running(struct lxc_container *c) |
505 | 0 | { |
506 | 0 | if (!c) |
507 | 0 | return false; |
508 | | |
509 | 0 | return !is_stopped(c); |
510 | 0 | } |
511 | | |
512 | 0 | WRAP_API(bool, lxcapi_is_running) |
513 | | |
514 | | static bool do_lxcapi_freeze(struct lxc_container *c) |
515 | 0 | { |
516 | 0 | int ret = 0; |
517 | 0 | lxc_state_t s; |
518 | |
|
519 | 0 | if (!c || !c->lxc_conf) |
520 | 0 | return false; |
521 | | |
522 | 0 | s = lxc_getstate(c->name, c->config_path, 0); |
523 | 0 | if (s != FROZEN) { |
524 | 0 | ret = cgroup_freeze(c->name, c->config_path, -1); |
525 | 0 | if (ret == -ENOCGROUP2) |
526 | 0 | ret = lxc_freeze(c->lxc_conf, c->name, c->config_path); |
527 | 0 | } |
528 | |
|
529 | 0 | return ret == 0; |
530 | 0 | } |
531 | | |
532 | 0 | WRAP_API(bool, lxcapi_freeze) |
533 | | |
534 | | static bool do_lxcapi_unfreeze(struct lxc_container *c) |
535 | 0 | { |
536 | 0 | int ret = 0; |
537 | 0 | lxc_state_t s; |
538 | |
|
539 | 0 | if (!c || !c->lxc_conf) |
540 | 0 | return false; |
541 | | |
542 | 0 | s = lxc_getstate(c->name, c->config_path, 0); |
543 | |
|
544 | 0 | if (s < 0) { |
545 | 0 | return false; |
546 | 0 | } |
547 | | |
548 | | // Prevent lxc from unexpectedly exiting when executing freeze, |
549 | | // causing the container to be in the FREEZING state, |
550 | | // making normal life cycle management impossible. |
551 | 0 | if (s == FROZEN || s == FREEZING) { |
552 | 0 | ret = cgroup_unfreeze(c->name, c->config_path, -1); |
553 | 0 | if (ret == -ENOCGROUP2) |
554 | 0 | ret = lxc_unfreeze(c->lxc_conf, c->name, c->config_path); |
555 | 0 | } |
556 | | |
557 | |
|
558 | 0 | return ret == 0; |
559 | 0 | } |
560 | | |
561 | 0 | WRAP_API(bool, lxcapi_unfreeze) |
562 | | |
563 | | static int do_lxcapi_console_getfd(struct lxc_container *c, int *ttynum, int *ptxfd) |
564 | 0 | { |
565 | 0 | if (!c) |
566 | 0 | return -1; |
567 | | |
568 | 0 | return lxc_terminal_getfd(c, ttynum, ptxfd); |
569 | 0 | } |
570 | | |
571 | 0 | WRAP_API_2(int, lxcapi_console_getfd, int *, int *) |
572 | | |
573 | | static int lxcapi_console(struct lxc_container *c, int ttynum, int stdinfd, |
574 | | int stdoutfd, int stderrfd, int escape) |
575 | 0 | { |
576 | 0 | int ret; |
577 | |
|
578 | 0 | if (!c) |
579 | 0 | return -1; |
580 | | |
581 | 0 | current_config = c->lxc_conf; |
582 | 0 | ret = lxc_console(c, ttynum, stdinfd, stdoutfd, stderrfd, escape); |
583 | 0 | current_config = NULL; |
584 | |
|
585 | 0 | return ret; |
586 | 0 | } |
587 | | |
588 | | static int do_lxcapi_console_log(struct lxc_container *c, struct lxc_console_log *log) |
589 | 0 | { |
590 | 0 | int ret; |
591 | |
|
592 | 0 | if (!c) |
593 | 0 | return -EINVAL; |
594 | | |
595 | 0 | ret = lxc_cmd_console_log(c->name, do_lxcapi_get_config_path(c), log); |
596 | 0 | if (ret < 0) { |
597 | 0 | if (ret == -ENODATA) |
598 | 0 | NOTICE("The console log is empty"); |
599 | 0 | else if (ret == -EFAULT) |
600 | 0 | NOTICE("The container does not keep a console log"); |
601 | 0 | else if (ret == -ENOENT) |
602 | 0 | NOTICE("The container does not keep a console log file"); |
603 | 0 | else if (ret == -EIO) |
604 | 0 | NOTICE("Failed to write console log to log file"); |
605 | 0 | else |
606 | 0 | ERROR("Failed to retrieve console log"); |
607 | 0 | } |
608 | |
|
609 | 0 | return ret; |
610 | 0 | } |
611 | | |
612 | 0 | WRAP_API_1(int, lxcapi_console_log, struct lxc_console_log *) |
613 | | |
614 | | static pid_t do_lxcapi_init_pid(struct lxc_container *c) |
615 | 0 | { |
616 | 0 | if (!c) |
617 | 0 | return -1; |
618 | | |
619 | 0 | return lxc_cmd_get_init_pid(c->name, c->config_path); |
620 | 0 | } |
621 | | |
622 | 0 | WRAP_API(pid_t, lxcapi_init_pid) |
623 | | |
624 | | static int do_lxcapi_init_pidfd(struct lxc_container *c) |
625 | 0 | { |
626 | 0 | if (!c) |
627 | 0 | return ret_errno(EBADF); |
628 | | |
629 | 0 | return lxc_cmd_get_init_pidfd(c->name, c->config_path); |
630 | 0 | } |
631 | | |
632 | 0 | WRAP_API(int, lxcapi_init_pidfd) |
633 | | |
634 | | static int do_lxcapi_devpts_fd(struct lxc_container *c) |
635 | 0 | { |
636 | 0 | if (!c) |
637 | 0 | return ret_errno(EBADF); |
638 | | |
639 | 0 | return lxc_cmd_get_devpts_fd(c->name, c->config_path); |
640 | 0 | } |
641 | | |
642 | 0 | WRAP_API(int, lxcapi_devpts_fd) |
643 | | |
644 | | static bool load_config_locked(struct lxc_container *c, const char *fname) |
645 | 0 | { |
646 | 0 | if (!c->lxc_conf) |
647 | 0 | c->lxc_conf = lxc_conf_init(); |
648 | |
|
649 | 0 | if (!c->lxc_conf) |
650 | 0 | return false; |
651 | | |
652 | 0 | if (lxc_config_read(fname, c->lxc_conf, false) != 0) |
653 | 0 | return false; |
654 | | |
655 | 0 | c->lxc_conf->name = c->name; |
656 | 0 | return true; |
657 | 0 | } |
658 | | |
659 | | static bool do_lxcapi_load_config(struct lxc_container *c, const char *alt_file) |
660 | 0 | { |
661 | 0 | int lret; |
662 | 0 | const char *fname; |
663 | 0 | bool need_disklock = false, ret = false; |
664 | |
|
665 | 0 | if (!c) |
666 | 0 | return false; |
667 | | |
668 | 0 | fname = c->configfile; |
669 | |
|
670 | 0 | if (alt_file) |
671 | 0 | fname = alt_file; |
672 | |
|
673 | 0 | if (!fname) |
674 | 0 | return false; |
675 | | |
676 | | /* If we're reading something other than the container's config, we only |
677 | | * need to lock the in-memory container. If loading the container's |
678 | | * config file, take the disk lock. |
679 | | */ |
680 | 0 | if (strequal(fname, c->configfile)) |
681 | 0 | need_disklock = true; |
682 | |
|
683 | 0 | if (need_disklock) |
684 | 0 | lret = container_disk_lock(c); |
685 | 0 | else |
686 | 0 | lret = container_mem_lock(c); |
687 | 0 | if (lret) |
688 | 0 | return false; |
689 | | |
690 | 0 | ret = load_config_locked(c, fname); |
691 | |
|
692 | 0 | if (need_disklock) |
693 | 0 | container_disk_unlock(c); |
694 | 0 | else |
695 | 0 | container_mem_unlock(c); |
696 | |
|
697 | 0 | return ret; |
698 | 0 | } |
699 | | |
700 | 0 | WRAP_API_1(bool, lxcapi_load_config, const char *) |
701 | | |
702 | | static bool do_lxcapi_want_daemonize(struct lxc_container *c, bool state) |
703 | 0 | { |
704 | 0 | if (!c || !c->lxc_conf) |
705 | 0 | return false; |
706 | | |
707 | 0 | if (container_mem_lock(c)) |
708 | 0 | return false; |
709 | | |
710 | 0 | c->daemonize = state; |
711 | |
|
712 | 0 | container_mem_unlock(c); |
713 | |
|
714 | 0 | return true; |
715 | 0 | } |
716 | | |
717 | 0 | WRAP_API_1(bool, lxcapi_want_daemonize, bool) |
718 | | |
719 | | static bool do_lxcapi_want_close_all_fds(struct lxc_container *c, bool state) |
720 | 0 | { |
721 | 0 | if (!c || !c->lxc_conf) |
722 | 0 | return false; |
723 | | |
724 | 0 | if (container_mem_lock(c)) |
725 | 0 | return false; |
726 | | |
727 | 0 | c->lxc_conf->close_all_fds = state; |
728 | |
|
729 | 0 | container_mem_unlock(c); |
730 | |
|
731 | 0 | return true; |
732 | 0 | } |
733 | | |
734 | 0 | WRAP_API_1(bool, lxcapi_want_close_all_fds, bool) |
735 | | |
736 | | static bool do_lxcapi_wait(struct lxc_container *c, const char *state, |
737 | | int timeout) |
738 | 0 | { |
739 | 0 | int ret; |
740 | |
|
741 | 0 | if (!c) |
742 | 0 | return false; |
743 | | |
744 | 0 | ret = lxc_wait(c->name, state, timeout, c->config_path); |
745 | 0 | return ret == 0; |
746 | 0 | } |
747 | | |
748 | 0 | WRAP_API_2(bool, lxcapi_wait, const char *, int) |
749 | | |
750 | | static bool am_single_threaded(void) |
751 | 0 | { |
752 | 0 | __do_closedir DIR *dir = NULL; |
753 | 0 | struct dirent *direntp; |
754 | 0 | int count = 0; |
755 | |
|
756 | 0 | dir = opendir("/proc/self/task"); |
757 | 0 | if (!dir) |
758 | 0 | return false; |
759 | | |
760 | 0 | while ((direntp = readdir(dir))) { |
761 | 0 | if (strequal(direntp->d_name, ".")) |
762 | 0 | continue; |
763 | | |
764 | 0 | if (strequal(direntp->d_name, "..")) |
765 | 0 | continue; |
766 | | |
767 | 0 | count++; |
768 | 0 | if (count > 1) |
769 | 0 | break; |
770 | 0 | } |
771 | |
|
772 | 0 | return count == 1; |
773 | 0 | } |
774 | | |
775 | | static void free_init_cmd(char **argv) |
776 | 0 | { |
777 | 0 | int i = 0; |
778 | |
|
779 | 0 | if (!argv) |
780 | 0 | return; |
781 | | |
782 | 0 | while (argv[i]) |
783 | 0 | free(argv[i++]); |
784 | |
|
785 | 0 | free(argv); |
786 | 0 | } |
787 | | |
788 | | static int lxc_rcv_status(int state_socket) |
789 | 0 | { |
790 | 0 | int ret; |
791 | 0 | int state = -1; |
792 | |
|
793 | 0 | again: |
794 | | /* Receive container state. */ |
795 | 0 | ret = lxc_abstract_unix_rcv_credential(state_socket, &state, sizeof(int)); |
796 | 0 | if (ret <= 0) { |
797 | 0 | if (errno != EINTR) |
798 | 0 | return -1; |
799 | | |
800 | 0 | TRACE("Caught EINTR; retrying"); |
801 | 0 | goto again; |
802 | 0 | } |
803 | | |
804 | 0 | return state; |
805 | 0 | } |
806 | | |
807 | | static bool wait_on_daemonized_start(struct lxc_handler *handler, int pid) |
808 | 0 | { |
809 | 0 | int ret, state; |
810 | | |
811 | | /* The first child is going to fork() again and then exits. So we reap |
812 | | * the first child here. |
813 | | */ |
814 | 0 | ret = wait_for_pid(pid); |
815 | 0 | if (ret < 0) |
816 | 0 | DEBUG("Failed waiting on first child %d", pid); |
817 | 0 | else |
818 | 0 | DEBUG("First child %d exited", pid); |
819 | | |
820 | | /* Close write end of the socket pair. */ |
821 | 0 | close_prot_errno_disarm(handler->state_socket_pair[1]); |
822 | |
|
823 | 0 | state = lxc_rcv_status(handler->state_socket_pair[0]); |
824 | | |
825 | | /* Close read end of the socket pair. */ |
826 | 0 | close_prot_errno_disarm(handler->state_socket_pair[0]); |
827 | |
|
828 | 0 | if (state < 0) { |
829 | 0 | SYSERROR("Failed to receive the container state"); |
830 | 0 | return false; |
831 | 0 | } |
832 | | |
833 | | /* If we receive anything else then running we know that the container |
834 | | * failed to start. |
835 | | */ |
836 | 0 | if (state != RUNNING) { |
837 | 0 | ERROR("Received container state \"%s\" instead of \"RUNNING\"", |
838 | 0 | lxc_state2str(state)); |
839 | 0 | return false; |
840 | 0 | } |
841 | | |
842 | 0 | TRACE("Container is in \"RUNNING\" state"); |
843 | 0 | return true; |
844 | 0 | } |
845 | | |
846 | | static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const argv[]) |
847 | 0 | { |
848 | 0 | int ret; |
849 | 0 | struct lxc_handler *handler; |
850 | 0 | struct lxc_conf *conf; |
851 | 0 | char *default_args[] = { |
852 | 0 | "/sbin/init", |
853 | 0 | NULL, |
854 | 0 | }; |
855 | 0 | char **init_cmd = NULL; |
856 | | |
857 | | /* container does exist */ |
858 | 0 | if (!c) |
859 | 0 | return false; |
860 | | |
861 | | /* If anything fails before we set error_num, we want an error in there. |
862 | | */ |
863 | 0 | c->error_num = 1; |
864 | | |
865 | | /* Container has not been setup. */ |
866 | 0 | if (!c->lxc_conf) |
867 | 0 | return false; |
868 | | |
869 | 0 | ret = ongoing_create(c); |
870 | 0 | switch (ret) { |
871 | 0 | case LXC_CREATE_FAILED: |
872 | 0 | ERROR("Failed checking for incomplete container creation"); |
873 | 0 | return false; |
874 | 0 | case LXC_CREATE_ONGOING: |
875 | 0 | ERROR("Ongoing container creation detected"); |
876 | 0 | return false; |
877 | 0 | case LXC_CREATE_INCOMPLETE: |
878 | 0 | ERROR("Failed to create container"); |
879 | 0 | do_lxcapi_destroy(c); |
880 | 0 | return false; |
881 | 0 | } |
882 | | |
883 | 0 | if (container_mem_lock(c)) |
884 | 0 | return false; |
885 | | |
886 | 0 | conf = c->lxc_conf; |
887 | | |
888 | | /* initialize handler */ |
889 | 0 | handler = lxc_init_handler(NULL, c->name, conf, c->config_path, c->daemonize); |
890 | |
|
891 | 0 | container_mem_unlock(c); |
892 | 0 | if (!handler) |
893 | 0 | return false; |
894 | | |
895 | 0 | if (!argv) { |
896 | 0 | char *cfgcmd = conf->init_cmd; |
897 | 0 | if (useinit && conf->execute_cmd) |
898 | 0 | cfgcmd = conf->execute_cmd; |
899 | |
|
900 | 0 | if (cfgcmd != NULL) |
901 | 0 | argv = init_cmd = lxc_string_split_quoted(cfgcmd); |
902 | 0 | } |
903 | | |
904 | | /* ... otherwise use default_args. */ |
905 | 0 | if (!argv) { |
906 | 0 | if (useinit) { |
907 | 0 | ERROR("No valid init detected"); |
908 | 0 | lxc_put_handler(handler); |
909 | 0 | return false; |
910 | 0 | } |
911 | 0 | argv = default_args; |
912 | 0 | } |
913 | | |
914 | | /* I'm not sure what locks we want here.Any? Is liblxc's locking enough |
915 | | * here to protect the on disk container? We don't want to exclude |
916 | | * things like lxc_info while the container is running. |
917 | | */ |
918 | 0 | if (c->daemonize) { |
919 | 0 | bool started; |
920 | 0 | char title[2048]; |
921 | 0 | pid_t pid_first, pid_second; |
922 | |
|
923 | 0 | pid_first = fork(); |
924 | 0 | if (pid_first < 0) { |
925 | 0 | free_init_cmd(init_cmd); |
926 | 0 | lxc_put_handler(handler); |
927 | 0 | return false; |
928 | 0 | } |
929 | | |
930 | | /* first parent */ |
931 | 0 | if (pid_first != 0) { |
932 | | /* Set to NULL because we don't want father unlink |
933 | | * the PID file, child will do the free and unlink. |
934 | | */ |
935 | 0 | c->pidfile = NULL; |
936 | | |
937 | | /* Wait for container to tell us whether it started |
938 | | * successfully. |
939 | | */ |
940 | 0 | started = wait_on_daemonized_start(handler, pid_first); |
941 | |
|
942 | 0 | free_init_cmd(init_cmd); |
943 | 0 | lxc_put_handler(handler); |
944 | 0 | return started; |
945 | 0 | } |
946 | | |
947 | | /* first child */ |
948 | | |
949 | | /* We don't really care if this doesn't print all the |
950 | | * characters. All that it means is that the proctitle will be |
951 | | * ugly. Similarly, we also don't care if setproctitle() fails. |
952 | | */ |
953 | 0 | ret = strnprintf(title, sizeof(title), "[lxc monitor] %s %s", c->config_path, c->name); |
954 | 0 | if (ret > 0) { |
955 | 0 | ret = setproctitle(title); |
956 | 0 | if (ret < 0) |
957 | 0 | INFO("Failed to set process title to %s", title); |
958 | 0 | else |
959 | 0 | INFO("Set process title to %s", title); |
960 | 0 | } |
961 | | |
962 | | /* We fork() a second time to be reparented to init. Like |
963 | | * POSIX's daemon() function we change to "/" and redirect |
964 | | * std{in,out,err} to /dev/null. |
965 | | */ |
966 | 0 | pid_second = fork(); |
967 | 0 | if (pid_second < 0) { |
968 | 0 | SYSERROR("Failed to fork first child process"); |
969 | 0 | _exit(EXIT_FAILURE); |
970 | 0 | } |
971 | | |
972 | | /* second parent */ |
973 | 0 | if (pid_second != 0) { |
974 | 0 | free_init_cmd(init_cmd); |
975 | 0 | lxc_put_handler(handler); |
976 | 0 | _exit(EXIT_SUCCESS); |
977 | 0 | } |
978 | | |
979 | | /* second child */ |
980 | | |
981 | | /* change to / directory */ |
982 | 0 | ret = chdir("/"); |
983 | 0 | if (ret < 0) { |
984 | 0 | SYSERROR("Failed to change to \"/\" directory"); |
985 | 0 | _exit(EXIT_FAILURE); |
986 | 0 | } |
987 | | |
988 | 0 | ret = inherit_fds(handler, true); |
989 | 0 | if (ret < 0) |
990 | 0 | _exit(EXIT_FAILURE); |
991 | | |
992 | | /* redirect std{in,out,err} to /dev/null */ |
993 | 0 | ret = null_stdfds(); |
994 | 0 | if (ret < 0) { |
995 | 0 | ERROR("Failed to redirect std{in,out,err} to /dev/null"); |
996 | 0 | _exit(EXIT_FAILURE); |
997 | 0 | } |
998 | | |
999 | | /* become session leader */ |
1000 | 0 | ret = setsid(); |
1001 | 0 | if (ret < 0) |
1002 | 0 | TRACE("Process %d is already process group leader", lxc_raw_getpid()); |
1003 | 0 | } else if (!am_single_threaded()) { |
1004 | 0 | ERROR("Cannot start non-daemonized container when threaded"); |
1005 | 0 | free_init_cmd(init_cmd); |
1006 | 0 | lxc_put_handler(handler); |
1007 | 0 | return false; |
1008 | 0 | } |
1009 | | |
1010 | | /* We need to write PID file after daemonize, so we always write the |
1011 | | * right PID. |
1012 | | */ |
1013 | 0 | if (c->pidfile) { |
1014 | 0 | int w; |
1015 | 0 | char pidstr[INTTYPE_TO_STRLEN(pid_t)]; |
1016 | |
|
1017 | 0 | w = strnprintf(pidstr, sizeof(pidstr), "%d", lxc_raw_getpid()); |
1018 | 0 | if (w < 0) { |
1019 | 0 | free_init_cmd(init_cmd); |
1020 | 0 | lxc_put_handler(handler); |
1021 | |
|
1022 | 0 | SYSERROR("Failed to write monitor pid to \"%s\"", c->pidfile); |
1023 | |
|
1024 | 0 | if (c->daemonize) |
1025 | 0 | _exit(EXIT_FAILURE); |
1026 | | |
1027 | 0 | return false; |
1028 | 0 | } |
1029 | | |
1030 | 0 | ret = lxc_write_to_file(c->pidfile, pidstr, w, false, 0600); |
1031 | 0 | if (ret < 0) { |
1032 | 0 | free_init_cmd(init_cmd); |
1033 | 0 | lxc_put_handler(handler); |
1034 | |
|
1035 | 0 | SYSERROR("Failed to write monitor pid to \"%s\"", c->pidfile); |
1036 | |
|
1037 | 0 | if (c->daemonize) |
1038 | 0 | _exit(EXIT_FAILURE); |
1039 | | |
1040 | 0 | return false; |
1041 | 0 | } |
1042 | 0 | } |
1043 | | |
1044 | 0 | conf->reboot = REBOOT_NONE; |
1045 | | |
1046 | | /* Unshare the mount namespace if requested */ |
1047 | 0 | if (conf->monitor_unshare) { |
1048 | 0 | ret = unshare(CLONE_NEWNS); |
1049 | 0 | if (ret < 0) { |
1050 | 0 | SYSERROR("Failed to unshare mount namespace"); |
1051 | 0 | lxc_put_handler(handler); |
1052 | 0 | ret = 1; |
1053 | 0 | goto on_error; |
1054 | 0 | } |
1055 | | |
1056 | 0 | ret = mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL); |
1057 | 0 | if (ret < 0) { |
1058 | 0 | SYSERROR("Failed to recursively turn root mount tree into dependent mount. Continuing..."); |
1059 | 0 | lxc_put_handler(handler); |
1060 | 0 | ret = 1; |
1061 | 0 | goto on_error; |
1062 | 0 | } |
1063 | 0 | } |
1064 | | |
1065 | 0 | reboot: |
1066 | 0 | if (conf->reboot == REBOOT_INIT) { |
1067 | | /* initialize handler */ |
1068 | 0 | handler = lxc_init_handler(handler, c->name, conf, c->config_path, c->daemonize); |
1069 | 0 | if (!handler) { |
1070 | 0 | ret = 1; |
1071 | 0 | goto on_error; |
1072 | 0 | } |
1073 | 0 | } |
1074 | | |
1075 | 0 | ret = inherit_fds(handler, c->daemonize); |
1076 | 0 | if (ret < 0) { |
1077 | 0 | lxc_put_handler(handler); |
1078 | 0 | ret = 1; |
1079 | 0 | goto on_error; |
1080 | 0 | } |
1081 | | |
1082 | 0 | if (useinit) |
1083 | 0 | ret = lxc_execute(c->name, argv, 1, handler, c->config_path, |
1084 | 0 | c->daemonize, &c->error_num); |
1085 | 0 | else |
1086 | 0 | ret = lxc_start(argv, handler, c->config_path, c->daemonize, |
1087 | 0 | &c->error_num); |
1088 | |
|
1089 | 0 | if (conf->reboot == REBOOT_REQ) { |
1090 | 0 | INFO("Container requested reboot"); |
1091 | 0 | conf->reboot = REBOOT_INIT; |
1092 | 0 | goto reboot; |
1093 | 0 | } |
1094 | | |
1095 | 0 | on_error: |
1096 | 0 | if (c->pidfile) { |
1097 | 0 | unlink(c->pidfile); |
1098 | 0 | free(c->pidfile); |
1099 | 0 | c->pidfile = NULL; |
1100 | 0 | } |
1101 | 0 | free_init_cmd(init_cmd); |
1102 | |
|
1103 | 0 | if (c->daemonize && ret != 0) |
1104 | 0 | _exit(EXIT_FAILURE); |
1105 | 0 | else if (c->daemonize) |
1106 | 0 | _exit(EXIT_SUCCESS); |
1107 | | |
1108 | 0 | if (ret != 0) |
1109 | 0 | return false; |
1110 | | |
1111 | 0 | return true; |
1112 | 0 | } |
1113 | | |
1114 | | static bool lxcapi_start(struct lxc_container *c, int useinit, |
1115 | | char *const argv[]) |
1116 | 0 | { |
1117 | 0 | bool ret; |
1118 | |
|
1119 | 0 | current_config = c ? c->lxc_conf : NULL; |
1120 | 0 | ret = do_lxcapi_start(c, useinit, argv); |
1121 | 0 | current_config = NULL; |
1122 | |
|
1123 | 0 | return ret; |
1124 | 0 | } |
1125 | | |
1126 | | /* Note, there MUST be an ending NULL. */ |
1127 | | static bool lxcapi_startl(struct lxc_container *c, int useinit, ...) |
1128 | 0 | { |
1129 | 0 | va_list ap; |
1130 | 0 | char **inargs = NULL; |
1131 | 0 | bool bret = false; |
1132 | | |
1133 | | /* container exists */ |
1134 | 0 | if (!c) |
1135 | 0 | return false; |
1136 | | |
1137 | 0 | current_config = c->lxc_conf; |
1138 | |
|
1139 | 0 | va_start(ap, useinit); |
1140 | 0 | inargs = lxc_va_arg_list_to_argv(ap, 0, 1); |
1141 | 0 | va_end(ap); |
1142 | 0 | if (!inargs) |
1143 | 0 | goto on_error; |
1144 | | |
1145 | | /* pass NULL if no arguments were supplied */ |
1146 | 0 | bret = do_lxcapi_start(c, useinit, *inargs ? inargs : NULL); |
1147 | |
|
1148 | 0 | on_error: |
1149 | 0 | if (inargs) { |
1150 | 0 | char **arg; |
1151 | |
|
1152 | 0 | for (arg = inargs; *arg; arg++) |
1153 | 0 | free(*arg); |
1154 | 0 | free(inargs); |
1155 | 0 | } |
1156 | |
|
1157 | 0 | current_config = NULL; |
1158 | |
|
1159 | 0 | return bret; |
1160 | 0 | } |
1161 | | |
1162 | | static bool do_lxcapi_stop(struct lxc_container *c) |
1163 | 0 | { |
1164 | 0 | int ret; |
1165 | |
|
1166 | 0 | if (!c) |
1167 | 0 | return false; |
1168 | | |
1169 | 0 | ret = lxc_cmd_stop(c->name, c->config_path); |
1170 | |
|
1171 | 0 | return ret == 0; |
1172 | 0 | } |
1173 | | |
1174 | 0 | WRAP_API(bool, lxcapi_stop) |
1175 | | |
1176 | | static int do_create_container_dir(const char *path, struct lxc_conf *conf) |
1177 | 0 | { |
1178 | 0 | __do_close int fd_rootfs = -EBADF; |
1179 | 0 | int ret = -1; |
1180 | |
|
1181 | 0 | mode_t mask = umask(0002); |
1182 | 0 | ret = mkdir(path, 0770); |
1183 | 0 | umask(mask); |
1184 | 0 | if (ret < 0 && errno != EEXIST) |
1185 | 0 | return -errno; |
1186 | | |
1187 | 0 | fd_rootfs = open_at(-EBADF, path, O_DIRECTORY | O_CLOEXEC, PROTECT_LOOKUP_ABSOLUTE_XDEV_SYMLINKS, 0); |
1188 | 0 | if (fd_rootfs < 0) |
1189 | 0 | return syserror("Failed to open container directory \"%d(%s)\"", fd_rootfs, path); |
1190 | | |
1191 | 0 | if (list_empty(&conf->id_map)) |
1192 | 0 | return move_fd(fd_rootfs); |
1193 | | |
1194 | 0 | ret = userns_exec_mapped_root(NULL, fd_rootfs, conf); |
1195 | 0 | if (ret < 0) |
1196 | 0 | return syserror_ret(-1, "Failed to chown rootfs \"%s\"", path); |
1197 | | |
1198 | 0 | return move_fd(fd_rootfs); |
1199 | 0 | } |
1200 | | |
1201 | | /* Create the standard expected container dir. */ |
1202 | | static int create_container_dir(struct lxc_container *c) |
1203 | 0 | { |
1204 | 0 | __do_free char *s = NULL; |
1205 | 0 | int ret; |
1206 | 0 | size_t len; |
1207 | |
|
1208 | 0 | len = strlen(c->config_path) + strlen(c->name) + 2; |
1209 | 0 | s = malloc(len); |
1210 | 0 | if (!s) |
1211 | 0 | return ret_errno(ENOMEM); |
1212 | | |
1213 | 0 | ret = strnprintf(s, len, "%s/%s", c->config_path, c->name); |
1214 | 0 | if (ret < 0) |
1215 | 0 | return -errno; |
1216 | | |
1217 | 0 | return do_create_container_dir(s, c->lxc_conf); |
1218 | 0 | } |
1219 | | |
1220 | | /* do_storage_create: thin wrapper around storage_create(). Like |
1221 | | * storage_create(), it returns a mounted bdev on success, NULL on error. |
1222 | | */ |
1223 | | static struct lxc_storage *do_storage_create(struct lxc_container *c, |
1224 | | const char *type, |
1225 | | struct bdev_specs *specs) |
1226 | 0 | { |
1227 | 0 | __do_free char *dest = NULL; |
1228 | 0 | int ret; |
1229 | 0 | size_t len; |
1230 | 0 | struct lxc_storage *bdev; |
1231 | | |
1232 | | /* rootfs.path or lxcpath/lxcname/rootfs */ |
1233 | 0 | if (c->lxc_conf->rootfs.path && |
1234 | 0 | (access(c->lxc_conf->rootfs.path, F_OK) == 0)) { |
1235 | 0 | const char *rpath = c->lxc_conf->rootfs.path; |
1236 | 0 | len = strlen(rpath) + 1; |
1237 | 0 | dest = must_realloc(NULL, len); |
1238 | 0 | ret = strnprintf(dest, len, "%s", rpath); |
1239 | 0 | } else { |
1240 | 0 | const char *lxcpath = do_lxcapi_get_config_path(c); |
1241 | 0 | len = strlen(c->name) + 1 + strlen(lxcpath) + 1 + strlen(LXC_ROOTFS_DNAME) + 1; |
1242 | 0 | dest = must_realloc(NULL, len); |
1243 | 0 | ret = strnprintf(dest, len, "%s/%s/%s", lxcpath, c->name, LXC_ROOTFS_DNAME); |
1244 | 0 | } |
1245 | 0 | if (ret < 0) |
1246 | 0 | return NULL; |
1247 | | |
1248 | 0 | bdev = storage_create(dest, type, c->name, specs, c->lxc_conf); |
1249 | 0 | if (!bdev) { |
1250 | 0 | ERROR("Failed to create \"%s\" storage", type); |
1251 | 0 | return NULL; |
1252 | 0 | } |
1253 | | |
1254 | 0 | if (!c->set_config_item(c, "lxc.rootfs.path", bdev->src)) { |
1255 | 0 | ERROR("Failed to set \"lxc.rootfs.path = %s\"", bdev->src); |
1256 | 0 | storage_put(bdev); |
1257 | 0 | return NULL; |
1258 | 0 | } |
1259 | | |
1260 | | /* If we are not root, chown the rootfs dir to root in the target user |
1261 | | * namespace. |
1262 | | */ |
1263 | 0 | if (am_guest_unpriv() || !list_empty(&c->lxc_conf->id_map)) { |
1264 | 0 | ret = chown_mapped_root(bdev->dest, c->lxc_conf); |
1265 | 0 | if (ret < 0) { |
1266 | 0 | ERROR("Error chowning \"%s\" to container root", bdev->dest); |
1267 | 0 | suggest_default_idmap(); |
1268 | 0 | storage_put(bdev); |
1269 | 0 | return NULL; |
1270 | 0 | } |
1271 | 0 | } |
1272 | | |
1273 | 0 | return bdev; |
1274 | 0 | } |
1275 | | |
1276 | | /* Strip path and return name of file for argv[0] passed to execvp */ |
1277 | | static char *lxctemplatefilename(char *tpath) |
1278 | 0 | { |
1279 | 0 | char *p; |
1280 | |
|
1281 | 0 | p = tpath + strlen(tpath) - 1; |
1282 | 0 | while ( (p-1) >= tpath && *(p-1) != '/') |
1283 | 0 | p--; |
1284 | |
|
1285 | 0 | return p; |
1286 | 0 | } |
1287 | | |
1288 | | static bool create_run_template(struct lxc_container *c, char *tpath, |
1289 | | bool need_null_stdfds, char *const argv[]) |
1290 | 0 | { |
1291 | 0 | int ret; |
1292 | 0 | pid_t pid; |
1293 | |
|
1294 | 0 | if (!tpath) |
1295 | 0 | return true; |
1296 | | |
1297 | 0 | pid = fork(); |
1298 | 0 | if (pid < 0) { |
1299 | 0 | SYSERROR("Failed to fork task for container creation template"); |
1300 | 0 | return false; |
1301 | 0 | } |
1302 | | |
1303 | 0 | if (pid == 0) { /* child */ |
1304 | 0 | int i, len; |
1305 | 0 | char *namearg, *patharg, *rootfsarg; |
1306 | 0 | char **newargv; |
1307 | 0 | int nargs = 0; |
1308 | 0 | struct lxc_storage *bdev = NULL; |
1309 | 0 | struct lxc_conf *conf = c->lxc_conf; |
1310 | 0 | uid_t euid; |
1311 | |
|
1312 | 0 | if (need_null_stdfds) { |
1313 | 0 | ret = null_stdfds(); |
1314 | 0 | if (ret < 0) |
1315 | 0 | _exit(EXIT_FAILURE); |
1316 | 0 | } |
1317 | | |
1318 | 0 | ret = lxc_storage_prepare(conf); |
1319 | 0 | if (ret) { |
1320 | 0 | ERROR("Failed to initialize storage"); |
1321 | 0 | _exit(EXIT_FAILURE); |
1322 | 0 | } |
1323 | 0 | bdev = conf->rootfs.storage; |
1324 | |
|
1325 | 0 | euid = geteuid(); |
1326 | 0 | if (euid == 0) { |
1327 | 0 | ret = unshare(CLONE_NEWNS); |
1328 | 0 | if (ret < 0) { |
1329 | 0 | ERROR("Failed to unshare CLONE_NEWNS"); |
1330 | 0 | _exit(EXIT_FAILURE); |
1331 | 0 | } |
1332 | | |
1333 | 0 | if (detect_shared_rootfs() && mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL)) |
1334 | 0 | SYSERROR("Failed to recursively turn root mount tree into dependent mount. Continuing..."); |
1335 | 0 | } |
1336 | | |
1337 | 0 | if (!strequal(bdev->type, "dir") && !strequal(bdev->type, "btrfs")) { |
1338 | 0 | if (euid != 0) { |
1339 | 0 | ERROR("Unprivileged users can only create " |
1340 | 0 | "btrfs and directory-backed containers"); |
1341 | 0 | _exit(EXIT_FAILURE); |
1342 | 0 | } |
1343 | | |
1344 | 0 | if (strequal(bdev->type, "overlay") || |
1345 | 0 | strequal(bdev->type, "overlayfs")) { |
1346 | | /* If we create an overlay container we need to |
1347 | | * rsync the contents into |
1348 | | * <container-path>/<container-name>/rootfs. |
1349 | | * However, the overlay mount function will |
1350 | | * mount |
1351 | | * <container-path>/<container-name>/delta0 |
1352 | | * over |
1353 | | * <container-path>/<container-name>/rootfs |
1354 | | * which means we would rsync the rootfs into |
1355 | | * the delta directory. That doesn't make sense |
1356 | | * since the delta directory only exists to |
1357 | | * record the differences to |
1358 | | * <container-path>/<container-name>/rootfs. So |
1359 | | * let's simply bind-mount here and then rsync |
1360 | | * directly into |
1361 | | * <container-path>/<container-name>/rootfs. |
1362 | | */ |
1363 | 0 | char *src; |
1364 | |
|
1365 | 0 | src = ovl_get_rootfs(bdev->src, &(size_t){0}); |
1366 | 0 | if (!src) { |
1367 | 0 | ERROR("Failed to get rootfs"); |
1368 | 0 | _exit(EXIT_FAILURE); |
1369 | 0 | } |
1370 | | |
1371 | 0 | ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC, NULL); |
1372 | 0 | if (ret < 0) { |
1373 | 0 | ERROR("Failed to mount rootfs"); |
1374 | 0 | _exit(EXIT_FAILURE); |
1375 | 0 | } |
1376 | 0 | } else { |
1377 | 0 | ret = bdev->ops->mount(bdev); |
1378 | 0 | if (ret < 0) { |
1379 | 0 | ERROR("Failed to mount rootfs"); |
1380 | 0 | _exit(EXIT_FAILURE); |
1381 | 0 | } |
1382 | 0 | } |
1383 | 0 | } else { /* TODO come up with a better way here! */ |
1384 | 0 | const char *src; |
1385 | 0 | free(bdev->dest); |
1386 | 0 | src = lxc_storage_get_path(bdev->src, bdev->type); |
1387 | 0 | bdev->dest = strdup(src); |
1388 | 0 | } |
1389 | | |
1390 | | /* Create our new array, pre-pend the template name and base |
1391 | | * args. |
1392 | | */ |
1393 | 0 | if (argv) |
1394 | 0 | for (nargs = 0; argv[nargs]; nargs++) |
1395 | 0 | ; |
1396 | | |
1397 | | /* template, path, rootfs and name args */ |
1398 | 0 | nargs += 4; |
1399 | |
|
1400 | 0 | newargv = malloc(nargs * sizeof(*newargv)); |
1401 | 0 | if (!newargv) |
1402 | 0 | _exit(EXIT_FAILURE); |
1403 | 0 | newargv[0] = lxctemplatefilename(tpath); |
1404 | | |
1405 | | /* --path */ |
1406 | 0 | len = strlen(c->config_path) + strlen(c->name) + strlen("--path=") + 2; |
1407 | 0 | patharg = malloc(len); |
1408 | 0 | if (!patharg) |
1409 | 0 | _exit(EXIT_FAILURE); |
1410 | | |
1411 | 0 | ret = strnprintf(patharg, len, "--path=%s/%s", c->config_path, c->name); |
1412 | 0 | if (ret < 0) |
1413 | 0 | _exit(EXIT_FAILURE); |
1414 | 0 | newargv[1] = patharg; |
1415 | | |
1416 | | /* --name */ |
1417 | 0 | len = strlen("--name=") + strlen(c->name) + 1; |
1418 | 0 | namearg = malloc(len); |
1419 | 0 | if (!namearg) |
1420 | 0 | _exit(EXIT_FAILURE); |
1421 | | |
1422 | 0 | ret = strnprintf(namearg, len, "--name=%s", c->name); |
1423 | 0 | if (ret < 0) |
1424 | 0 | _exit(EXIT_FAILURE); |
1425 | 0 | newargv[2] = namearg; |
1426 | | |
1427 | | /* --rootfs */ |
1428 | 0 | len = strlen("--rootfs=") + 1 + strlen(bdev->dest); |
1429 | 0 | rootfsarg = malloc(len); |
1430 | 0 | if (!rootfsarg) |
1431 | 0 | _exit(EXIT_FAILURE); |
1432 | | |
1433 | 0 | ret = strnprintf(rootfsarg, len, "--rootfs=%s", bdev->dest); |
1434 | 0 | if (ret < 0) |
1435 | 0 | _exit(EXIT_FAILURE); |
1436 | 0 | newargv[3] = rootfsarg; |
1437 | | |
1438 | | /* add passed-in args */ |
1439 | 0 | if (argv) |
1440 | 0 | for (i = 4; i < nargs; i++) |
1441 | 0 | newargv[i] = argv[i - 4]; |
1442 | | |
1443 | | /* add trailing NULL */ |
1444 | 0 | nargs++; |
1445 | 0 | newargv = realloc(newargv, nargs * sizeof(*newargv)); |
1446 | 0 | if (!newargv) |
1447 | 0 | _exit(EXIT_FAILURE); |
1448 | 0 | newargv[nargs - 1] = NULL; |
1449 | | |
1450 | | /* If we're running the template in a mapped userns, then we |
1451 | | * prepend the template command with: lxc-usernsexec <-m map1> |
1452 | | * ... <-m mapn> -- and we append "--mapped-uid x", where x is |
1453 | | * the mapped uid for our geteuid() |
1454 | | */ |
1455 | 0 | if (!list_empty(&conf->id_map)) { |
1456 | 0 | int extraargs, hostuid_mapped, hostgid_mapped; |
1457 | 0 | char **n2; |
1458 | 0 | char *txtuid = NULL, *txtgid = NULL; |
1459 | 0 | struct id_map *map; |
1460 | 0 | int n2args = 1; |
1461 | |
|
1462 | 0 | n2 = malloc(n2args * sizeof(*n2)); |
1463 | 0 | if (!n2) |
1464 | 0 | _exit(EXIT_FAILURE); |
1465 | | |
1466 | 0 | newargv[0] = tpath; |
1467 | 0 | tpath = "lxc-usernsexec"; |
1468 | 0 | n2[0] = "lxc-usernsexec"; |
1469 | |
|
1470 | 0 | list_for_each_entry(map, &conf->id_map, head) { |
1471 | 0 | n2args += 2; |
1472 | 0 | n2 = realloc(n2, n2args * sizeof(char *)); |
1473 | 0 | if (!n2) |
1474 | 0 | _exit(EXIT_FAILURE); |
1475 | | |
1476 | 0 | n2[n2args - 2] = "-m"; |
1477 | 0 | n2[n2args - 1] = malloc(200); |
1478 | 0 | if (!n2[n2args - 1]) |
1479 | 0 | _exit(EXIT_FAILURE); |
1480 | | |
1481 | 0 | ret = strnprintf(n2[n2args - 1], 200, "%c:%lu:%lu:%lu", |
1482 | 0 | map->idtype == ID_TYPE_UID ? 'u' : 'g', |
1483 | 0 | map->nsid, map->hostid, map->range); |
1484 | 0 | if (ret < 0) |
1485 | 0 | _exit(EXIT_FAILURE); |
1486 | 0 | } |
1487 | | |
1488 | 0 | hostuid_mapped = mapped_hostid(geteuid(), conf, ID_TYPE_UID); |
1489 | 0 | extraargs = hostuid_mapped >= 0 ? 1 : 3; |
1490 | |
|
1491 | 0 | n2 = realloc(n2, (nargs + n2args + extraargs) * sizeof(char *)); |
1492 | 0 | if (!n2) |
1493 | 0 | _exit(EXIT_FAILURE); |
1494 | | |
1495 | 0 | if (hostuid_mapped < 0) { |
1496 | 0 | hostuid_mapped = find_unmapped_nsid(conf, ID_TYPE_UID); |
1497 | 0 | n2[n2args++] = "-m"; |
1498 | 0 | if (hostuid_mapped < 0) { |
1499 | 0 | ERROR("Failed to find free uid to map"); |
1500 | 0 | _exit(EXIT_FAILURE); |
1501 | 0 | } |
1502 | | |
1503 | 0 | n2[n2args++] = malloc(200); |
1504 | 0 | if (!n2[n2args - 1]) { |
1505 | 0 | SYSERROR("out of memory"); |
1506 | 0 | _exit(EXIT_FAILURE); |
1507 | 0 | } |
1508 | | |
1509 | 0 | ret = strnprintf(n2[n2args - 1], 200, "u:%d:%d:1", |
1510 | 0 | hostuid_mapped, geteuid()); |
1511 | 0 | if (ret < 0) |
1512 | 0 | _exit(EXIT_FAILURE); |
1513 | 0 | } |
1514 | | |
1515 | 0 | hostgid_mapped = mapped_hostid(getegid(), conf, ID_TYPE_GID); |
1516 | 0 | extraargs = hostgid_mapped >= 0 ? 1 : 3; |
1517 | |
|
1518 | 0 | n2 = realloc(n2, (nargs + n2args + extraargs) * sizeof(char *)); |
1519 | 0 | if (!n2) |
1520 | 0 | _exit(EXIT_FAILURE); |
1521 | | |
1522 | 0 | if (hostgid_mapped < 0) { |
1523 | 0 | hostgid_mapped = find_unmapped_nsid(conf, ID_TYPE_GID); |
1524 | 0 | n2[n2args++] = "-m"; |
1525 | 0 | if (hostgid_mapped < 0) { |
1526 | 0 | ERROR("Failed to find free gid to map"); |
1527 | 0 | _exit(EXIT_FAILURE); |
1528 | 0 | } |
1529 | | |
1530 | 0 | n2[n2args++] = malloc(200); |
1531 | 0 | if (!n2[n2args - 1]) { |
1532 | 0 | SYSERROR("out of memory"); |
1533 | 0 | _exit(EXIT_FAILURE); |
1534 | 0 | } |
1535 | | |
1536 | 0 | ret = strnprintf(n2[n2args - 1], 200, "g:%d:%d:1", |
1537 | 0 | hostgid_mapped, getegid()); |
1538 | 0 | if (ret < 0) |
1539 | 0 | _exit(EXIT_FAILURE); |
1540 | 0 | } |
1541 | | |
1542 | 0 | n2[n2args++] = "--"; |
1543 | |
|
1544 | 0 | for (i = 0; i < nargs; i++) |
1545 | 0 | n2[i + n2args] = newargv[i]; |
1546 | 0 | n2args += nargs; |
1547 | | |
1548 | | /* Finally add "--mapped-uid $uid" to tell template what |
1549 | | * to chown cached images to. |
1550 | | */ |
1551 | 0 | n2args += 4; |
1552 | 0 | n2 = realloc(n2, n2args * sizeof(char *)); |
1553 | 0 | if (!n2) |
1554 | 0 | _exit(EXIT_FAILURE); |
1555 | | |
1556 | | /* note n2[n2args-1] is NULL */ |
1557 | 0 | n2[n2args - 5] = "--mapped-uid"; |
1558 | |
|
1559 | 0 | txtuid = malloc(20); |
1560 | 0 | if (!txtuid) { |
1561 | 0 | free(newargv); |
1562 | 0 | free(n2); |
1563 | 0 | _exit(EXIT_FAILURE); |
1564 | 0 | } |
1565 | 0 | ret = strnprintf(txtuid, 20, "%d", hostuid_mapped); |
1566 | 0 | if (ret < 0) { |
1567 | 0 | free(newargv); |
1568 | 0 | free(n2); |
1569 | 0 | _exit(EXIT_FAILURE); |
1570 | 0 | } |
1571 | | |
1572 | 0 | n2[n2args - 4] = txtuid; |
1573 | 0 | n2[n2args - 3] = "--mapped-gid"; |
1574 | |
|
1575 | 0 | txtgid = malloc(20); |
1576 | 0 | if (!txtgid) { |
1577 | 0 | free(newargv); |
1578 | 0 | free(n2); |
1579 | 0 | _exit(EXIT_FAILURE); |
1580 | 0 | } |
1581 | 0 | ret = strnprintf(txtgid, 20, "%d", hostgid_mapped); |
1582 | 0 | if (ret < 0) { |
1583 | 0 | free(newargv); |
1584 | 0 | free(n2); |
1585 | 0 | _exit(EXIT_FAILURE); |
1586 | 0 | } |
1587 | | |
1588 | 0 | n2[n2args - 2] = txtgid; |
1589 | 0 | n2[n2args - 1] = NULL; |
1590 | 0 | free(newargv); |
1591 | 0 | newargv = n2; |
1592 | 0 | } |
1593 | | |
1594 | 0 | execvp(tpath, newargv); |
1595 | 0 | SYSERROR("Failed to execute template %s", tpath); |
1596 | 0 | _exit(EXIT_FAILURE); |
1597 | 0 | } |
1598 | | |
1599 | 0 | ret = wait_for_pid(pid); |
1600 | 0 | if (ret != 0) { |
1601 | 0 | ERROR("Failed to create container from template"); |
1602 | 0 | return false; |
1603 | 0 | } |
1604 | | |
1605 | 0 | return true; |
1606 | 0 | } |
1607 | | |
1608 | | static bool prepend_lxc_header(char *path, const char *t, char *const argv[]) |
1609 | 0 | { |
1610 | 0 | ssize_t len, flen; |
1611 | 0 | char *contents; |
1612 | 0 | FILE *f; |
1613 | 0 | int ret = -1; |
1614 | 0 | ssize_t nbytes; |
1615 | | #if HAVE_OPENSSL |
1616 | | unsigned int md_len = 0; |
1617 | | unsigned char md_value[EVP_MAX_MD_SIZE]; |
1618 | | char *tpath; |
1619 | | #endif |
1620 | |
|
1621 | 0 | f = fopen(path, "re"); |
1622 | 0 | if (f == NULL) |
1623 | 0 | return false; |
1624 | | |
1625 | 0 | ret = fseek(f, 0, SEEK_END); |
1626 | 0 | if (ret < 0) |
1627 | 0 | goto out_error; |
1628 | | |
1629 | 0 | ret = -1; |
1630 | 0 | flen = ftell(f); |
1631 | 0 | if (flen < 0) |
1632 | 0 | goto out_error; |
1633 | | |
1634 | 0 | ret = fseek(f, 0, SEEK_SET); |
1635 | 0 | if (ret < 0) |
1636 | 0 | goto out_error; |
1637 | | |
1638 | 0 | ret = fseek(f, 0, SEEK_SET); |
1639 | 0 | if (ret < 0) |
1640 | 0 | goto out_error; |
1641 | | |
1642 | 0 | ret = -1; |
1643 | 0 | contents = malloc(flen + 1); |
1644 | 0 | if (!contents) |
1645 | 0 | goto out_error; |
1646 | | |
1647 | 0 | len = fread(contents, 1, flen, f); |
1648 | 0 | if (len != flen) |
1649 | 0 | goto out_free_contents; |
1650 | | |
1651 | 0 | contents[flen] = '\0'; |
1652 | |
|
1653 | 0 | ret = fclose(f); |
1654 | 0 | f = NULL; |
1655 | 0 | if (ret < 0) |
1656 | 0 | goto out_free_contents; |
1657 | | |
1658 | | #if HAVE_OPENSSL |
1659 | | tpath = get_template_path(t); |
1660 | | if (!tpath) { |
1661 | | ERROR("Invalid template \"%s\" specified", t); |
1662 | | goto out_free_contents; |
1663 | | } |
1664 | | |
1665 | | ret = sha1sum_file(tpath, md_value, &md_len); |
1666 | | if (ret < 0) { |
1667 | | ERROR("Failed to get sha1sum of %s", tpath); |
1668 | | free(tpath); |
1669 | | goto out_free_contents; |
1670 | | } |
1671 | | free(tpath); |
1672 | | #endif |
1673 | | |
1674 | 0 | f = fopen(path, "we"); |
1675 | 0 | if (f == NULL) { |
1676 | 0 | SYSERROR("Reopening config for writing"); |
1677 | 0 | free(contents); |
1678 | 0 | return false; |
1679 | 0 | } |
1680 | | |
1681 | 0 | fprintf(f, "# Template used to create this container: %s\n", t); |
1682 | 0 | if (argv) { |
1683 | 0 | fprintf(f, "# Parameters passed to the template:"); |
1684 | 0 | while (*argv) { |
1685 | 0 | fprintf(f, " %s", *argv); |
1686 | 0 | argv++; |
1687 | 0 | } |
1688 | 0 | fprintf(f, "\n"); |
1689 | 0 | } |
1690 | |
|
1691 | | #if HAVE_OPENSSL |
1692 | | fprintf(f, "# Template script checksum (SHA-1): "); |
1693 | | for (size_t i = 0; i < md_len; i++) |
1694 | | fprintf(f, "%02x", md_value[i]); |
1695 | | fprintf(f, "\n"); |
1696 | | #endif |
1697 | 0 | fprintf(f, "# For additional config options, please look at lxc.container.conf(5)\n"); |
1698 | 0 | fprintf(f, "\n# Uncomment the following line to support nesting containers:\n"); |
1699 | 0 | fprintf(f, "#lxc.include = " LXCTEMPLATECONFIG "/nesting.conf\n"); |
1700 | 0 | fprintf(f, "# (Be aware this has security implications)\n\n"); |
1701 | 0 | nbytes = fwrite(contents, 1, flen, f); |
1702 | 0 | if (nbytes < 0 || nbytes != flen) { |
1703 | 0 | SYSERROR("Writing original contents"); |
1704 | 0 | free(contents); |
1705 | 0 | fclose(f); |
1706 | 0 | return false; |
1707 | 0 | } |
1708 | | |
1709 | 0 | ret = 0; |
1710 | |
|
1711 | 0 | out_free_contents: |
1712 | 0 | free(contents); |
1713 | |
|
1714 | 0 | out_error: |
1715 | 0 | if (f) { |
1716 | 0 | int newret; |
1717 | 0 | newret = fclose(f); |
1718 | 0 | if (ret == 0) |
1719 | 0 | ret = newret; |
1720 | 0 | } |
1721 | |
|
1722 | 0 | if (ret < 0) { |
1723 | 0 | SYSERROR("Error prepending header"); |
1724 | 0 | return false; |
1725 | 0 | } |
1726 | | |
1727 | 0 | return true; |
1728 | 0 | } |
1729 | | |
1730 | | static void lxcapi_clear_config(struct lxc_container *c) |
1731 | 0 | { |
1732 | 0 | if (!c || !c->lxc_conf) |
1733 | 0 | return; |
1734 | | |
1735 | 0 | lxc_conf_free(c->lxc_conf); |
1736 | 0 | c->lxc_conf = NULL; |
1737 | 0 | } |
1738 | | |
1739 | 0 | #define do_lxcapi_clear_config(c) lxcapi_clear_config(c) |
1740 | | |
1741 | | /* |
1742 | | * lxcapi_create: |
1743 | | * create a container with the given parameters. |
1744 | | * @c: container to be created. It has the lxcpath, name, and a starting |
1745 | | * configuration already set |
1746 | | * @t: the template to execute to instantiate the root filesystem and |
1747 | | * adjust the configuration. |
1748 | | * @bdevtype: backing store type to use. If NULL, dir will be used. |
1749 | | * @specs: additional parameters for the backing store, i.e. LVM vg to |
1750 | | * use. |
1751 | | * |
1752 | | * @argv: the arguments to pass to the template, terminated by NULL. If no |
1753 | | * arguments, you can just pass NULL. |
1754 | | */ |
1755 | | static bool __lxcapi_create(struct lxc_container *c, const char *t, |
1756 | | const char *bdevtype, struct bdev_specs *specs, |
1757 | | int flags, char *const argv[]) |
1758 | 0 | { |
1759 | 0 | __do_close int fd_rootfs = -EBADF; |
1760 | 0 | __do_free char *path_template = NULL; |
1761 | 0 | int partial_fd; |
1762 | 0 | mode_t mask; |
1763 | 0 | pid_t pid; |
1764 | 0 | bool bret = false, rootfs_managed = true; |
1765 | |
|
1766 | 0 | if (!c) |
1767 | 0 | return false; |
1768 | | |
1769 | 0 | if (t) { |
1770 | 0 | path_template = get_template_path(t); |
1771 | 0 | if (!path_template) |
1772 | 0 | return log_error(false, "Template \"%s\" not found", t); |
1773 | 0 | } |
1774 | | |
1775 | | /* If a template is passed in, and the rootfs already is defined in the |
1776 | | * container config and exists, then the caller is trying to create an |
1777 | | * existing container. Return an error, but do NOT delete the container. |
1778 | | */ |
1779 | 0 | if (do_lxcapi_is_defined(c) && c->lxc_conf && c->lxc_conf->rootfs.path && |
1780 | 0 | access(c->lxc_conf->rootfs.path, F_OK) == 0 && path_template) |
1781 | 0 | return log_error(false, "Container \"%s\" already exists in \"%s\"", |
1782 | 0 | c->name, c->config_path); |
1783 | | |
1784 | 0 | if (!c->lxc_conf && |
1785 | 0 | !do_lxcapi_load_config(c, lxc_global_config_value("lxc.default_config"))) |
1786 | 0 | return log_error(false, "Failed to load default configuration file %s", |
1787 | 0 | lxc_global_config_value("lxc.default_config")); |
1788 | | |
1789 | 0 | fd_rootfs = create_container_dir(c); |
1790 | 0 | if (fd_rootfs < 0) |
1791 | 0 | return log_error(false, "Failed to create container %s", c->name); |
1792 | | |
1793 | 0 | if (c->lxc_conf->rootfs.path) |
1794 | 0 | rootfs_managed = false; |
1795 | | |
1796 | | /* If both template and rootfs.path are set, template is setup as |
1797 | | * rootfs.path. The container is already created if we have a config and |
1798 | | * rootfs.path is accessible |
1799 | | */ |
1800 | 0 | if (!c->lxc_conf->rootfs.path && !path_template) { |
1801 | | /* No template passed in and rootfs does not exist. */ |
1802 | 0 | if (!c->save_config(c, NULL)) { |
1803 | 0 | ERROR("Failed to save initial config for \"%s\"", c->name); |
1804 | 0 | goto out; |
1805 | 0 | } |
1806 | | |
1807 | 0 | bret = true; |
1808 | 0 | goto out; |
1809 | 0 | } |
1810 | | |
1811 | | /* Rootfs passed into configuration, but does not exist. */ |
1812 | 0 | if (c->lxc_conf->rootfs.path && access(c->lxc_conf->rootfs.path, F_OK) != 0) { |
1813 | 0 | ERROR("The rootfs \"%s\" does not exist", c->lxc_conf->rootfs.path); |
1814 | 0 | goto out; |
1815 | 0 | } |
1816 | | |
1817 | 0 | if (do_lxcapi_is_defined(c) && c->lxc_conf->rootfs.path && !path_template) { |
1818 | | /* Rootfs already existed, user just wanted to save the loaded |
1819 | | * configuration. |
1820 | | */ |
1821 | 0 | if (!c->save_config(c, NULL)) |
1822 | 0 | ERROR("Failed to save initial config for \"%s\"", c->name); |
1823 | |
|
1824 | 0 | bret = true; |
1825 | 0 | goto out; |
1826 | 0 | } |
1827 | | |
1828 | | /* Mark that this container as being created */ |
1829 | 0 | partial_fd = create_partial(fd_rootfs, c); |
1830 | 0 | if (partial_fd < 0) { |
1831 | 0 | SYSERROR("Failed to mark container as being partially created"); |
1832 | 0 | goto out; |
1833 | 0 | } |
1834 | | |
1835 | | /* No need to get disk lock bc we have the partial lock. */ |
1836 | | |
1837 | 0 | mask = umask(0022); |
1838 | | |
1839 | | /* Create the storage. |
1840 | | * Note we can't do this in the same task as we use to execute the |
1841 | | * template because of the way zfs works. |
1842 | | * After you 'zfs create', zfs mounts the fs only in the initial |
1843 | | * namespace. |
1844 | | */ |
1845 | 0 | pid = fork(); |
1846 | 0 | if (pid < 0) { |
1847 | 0 | SYSERROR("Failed to fork task for container creation template"); |
1848 | 0 | goto out_unlock; |
1849 | 0 | } |
1850 | | |
1851 | 0 | if (pid == 0) { /* child */ |
1852 | 0 | struct lxc_storage *bdev = NULL; |
1853 | |
|
1854 | 0 | bdev = do_storage_create(c, bdevtype, specs); |
1855 | 0 | if (!bdev) { |
1856 | 0 | ERROR("Failed to create %s storage for %s", |
1857 | 0 | bdevtype ? bdevtype : "(none)", c->name); |
1858 | 0 | _exit(EXIT_FAILURE); |
1859 | 0 | } |
1860 | | |
1861 | | /* Save config file again to store the new rootfs location. */ |
1862 | 0 | if (!do_lxcapi_save_config(c, NULL)) { |
1863 | 0 | ERROR("Failed to save initial config for %s", c->name); |
1864 | | /* Parent task won't see the storage driver in the |
1865 | | * config so we delete it. |
1866 | | */ |
1867 | 0 | bdev->ops->umount(bdev); |
1868 | 0 | bdev->ops->destroy(bdev); |
1869 | 0 | _exit(EXIT_FAILURE); |
1870 | 0 | } |
1871 | | |
1872 | 0 | _exit(EXIT_SUCCESS); |
1873 | 0 | } |
1874 | | |
1875 | 0 | if (!wait_exited(pid)) |
1876 | 0 | goto out_unlock; |
1877 | | |
1878 | | /* Reload config to get the rootfs. */ |
1879 | 0 | lxc_conf_free(c->lxc_conf); |
1880 | 0 | c->lxc_conf = NULL; |
1881 | |
|
1882 | 0 | if (!load_config_locked(c, c->configfile)) |
1883 | 0 | goto out_unlock; |
1884 | | |
1885 | 0 | if (!create_run_template(c, path_template, !!(flags & LXC_CREATE_QUIET), argv)) |
1886 | 0 | goto out_unlock; |
1887 | | |
1888 | | /* Now clear out the lxc_conf we have, reload from the created |
1889 | | * container. |
1890 | | */ |
1891 | 0 | do_lxcapi_clear_config(c); |
1892 | |
|
1893 | 0 | if (t) { |
1894 | 0 | if (!prepend_lxc_header(c->configfile, path_template, argv)) { |
1895 | 0 | ERROR("Failed to prepend header to config file"); |
1896 | 0 | goto out_unlock; |
1897 | 0 | } |
1898 | 0 | } |
1899 | | |
1900 | 0 | bret = load_config_locked(c, c->configfile); |
1901 | |
|
1902 | 0 | out_unlock: |
1903 | 0 | umask(mask); |
1904 | 0 | remove_partial(c, partial_fd); |
1905 | |
|
1906 | 0 | out: |
1907 | 0 | if (!bret) { |
1908 | 0 | bool reset_managed = c->lxc_conf->rootfs.managed; |
1909 | | |
1910 | | /* |
1911 | | * Ensure that we don't destroy storage we didn't create |
1912 | | * ourselves. |
1913 | | */ |
1914 | 0 | if (!rootfs_managed) |
1915 | 0 | c->lxc_conf->rootfs.managed = false; |
1916 | 0 | container_destroy(c, NULL); |
1917 | 0 | c->lxc_conf->rootfs.managed = reset_managed; |
1918 | 0 | } |
1919 | |
|
1920 | 0 | return bret; |
1921 | 0 | } |
1922 | | |
1923 | | static bool do_lxcapi_create(struct lxc_container *c, const char *t, |
1924 | | const char *bdevtype, struct bdev_specs *specs, |
1925 | | int flags, char *const argv[]) |
1926 | 0 | { |
1927 | 0 | return __lxcapi_create(c, t, bdevtype, specs, flags, argv); |
1928 | 0 | } |
1929 | | |
1930 | 0 | WRAP_API_5(bool, lxcapi_create, const char *, const char *, |
1931 | | struct bdev_specs *, int, char *const *) |
1932 | | |
1933 | | static bool do_lxcapi_reboot(struct lxc_container *c) |
1934 | 0 | { |
1935 | 0 | __do_close int pidfd = -EBADF; |
1936 | 0 | pid_t pid = -1; |
1937 | 0 | int ret; |
1938 | 0 | int rebootsignal = SIGINT; |
1939 | |
|
1940 | 0 | if (!c) |
1941 | 0 | return false; |
1942 | | |
1943 | 0 | if (!do_lxcapi_is_running(c)) |
1944 | 0 | return false; |
1945 | | |
1946 | 0 | pidfd = do_lxcapi_init_pidfd(c); |
1947 | 0 | if (pidfd < 0) { |
1948 | 0 | pid = do_lxcapi_init_pid(c); |
1949 | 0 | if (pid <= 0) |
1950 | 0 | return false; |
1951 | 0 | } |
1952 | | |
1953 | 0 | if (c->lxc_conf && c->lxc_conf->rebootsignal) |
1954 | 0 | rebootsignal = c->lxc_conf->rebootsignal; |
1955 | |
|
1956 | 0 | if (pidfd >= 0) |
1957 | 0 | ret = lxc_raw_pidfd_send_signal(pidfd, rebootsignal, NULL, 0); |
1958 | 0 | else |
1959 | 0 | ret = kill(pid, rebootsignal); |
1960 | 0 | if (ret < 0) |
1961 | 0 | return log_warn(false, "Failed to send signal %d to pid %d", |
1962 | 0 | rebootsignal, pid); |
1963 | | |
1964 | 0 | return true; |
1965 | 0 | } |
1966 | | |
1967 | 0 | WRAP_API(bool, lxcapi_reboot) |
1968 | | |
1969 | | static bool do_lxcapi_reboot2(struct lxc_container *c, int timeout) |
1970 | 0 | { |
1971 | 0 | __do_close int pidfd = -EBADF, state_client_fd = -EBADF; |
1972 | 0 | int rebootsignal = SIGINT; |
1973 | 0 | pid_t pid = -1; |
1974 | 0 | lxc_state_t states[MAX_STATE] = {0}; |
1975 | 0 | int killret, ret; |
1976 | |
|
1977 | 0 | if (!c) |
1978 | 0 | return false; |
1979 | | |
1980 | 0 | if (!do_lxcapi_is_running(c)) |
1981 | 0 | return true; |
1982 | | |
1983 | 0 | pidfd = do_lxcapi_init_pidfd(c); |
1984 | 0 | if (pidfd < 0) { |
1985 | 0 | pid = do_lxcapi_init_pid(c); |
1986 | 0 | if (pid <= 0) |
1987 | 0 | return true; |
1988 | 0 | } |
1989 | | |
1990 | 0 | if (c->lxc_conf && c->lxc_conf->rebootsignal) |
1991 | 0 | rebootsignal = c->lxc_conf->rebootsignal; |
1992 | | |
1993 | | /* Add a new state client before sending the shutdown signal so that we |
1994 | | * don't miss a state. |
1995 | | */ |
1996 | 0 | if (timeout != 0) { |
1997 | 0 | states[RUNNING] = 2; |
1998 | 0 | ret = lxc_cmd_add_state_client(c->name, c->config_path, states, |
1999 | 0 | &state_client_fd); |
2000 | 0 | if (ret < 0) |
2001 | 0 | return false; |
2002 | | |
2003 | 0 | if (state_client_fd < 0) |
2004 | 0 | return false; |
2005 | | |
2006 | 0 | if (ret == RUNNING) |
2007 | 0 | return true; |
2008 | | |
2009 | 0 | if (ret < MAX_STATE) |
2010 | 0 | return false; |
2011 | 0 | } |
2012 | | |
2013 | | /* Send reboot signal to container. */ |
2014 | 0 | if (pidfd >= 0) |
2015 | 0 | killret = lxc_raw_pidfd_send_signal(pidfd, rebootsignal, NULL, 0); |
2016 | 0 | else |
2017 | 0 | killret = kill(pid, rebootsignal); |
2018 | 0 | if (killret < 0) |
2019 | 0 | return log_warn(false, "Failed to send signal %d to pidfd(%d)/pid(%d)", rebootsignal, pidfd, pid); |
2020 | 0 | TRACE("Sent signal %d to pidfd(%d)/pid(%d)", rebootsignal, pidfd, pid); |
2021 | |
|
2022 | 0 | if (timeout == 0) |
2023 | 0 | return true; |
2024 | | |
2025 | 0 | ret = lxc_cmd_sock_rcv_state(state_client_fd, timeout); |
2026 | 0 | if (ret < 0) |
2027 | 0 | return false; |
2028 | | |
2029 | 0 | TRACE("Received state \"%s\"", lxc_state2str(ret)); |
2030 | 0 | if (ret != RUNNING) |
2031 | 0 | return false; |
2032 | | |
2033 | 0 | return true; |
2034 | 0 | } |
2035 | | |
2036 | 0 | WRAP_API_1(bool, lxcapi_reboot2, int) |
2037 | | |
2038 | | static bool do_lxcapi_shutdown(struct lxc_container *c, int timeout) |
2039 | 0 | { |
2040 | 0 | __do_close int pidfd = -EBADF, state_client_fd = -EBADF; |
2041 | 0 | int haltsignal = SIGPWR; |
2042 | 0 | pid_t pid = -1; |
2043 | 0 | lxc_state_t states[MAX_STATE] = {0}; |
2044 | 0 | int killret, ret; |
2045 | |
|
2046 | 0 | if (!c) |
2047 | 0 | return false; |
2048 | | |
2049 | 0 | if (!do_lxcapi_is_running(c)) |
2050 | 0 | return true; |
2051 | | |
2052 | 0 | pidfd = do_lxcapi_init_pidfd(c); |
2053 | 0 | pid = do_lxcapi_init_pid(c); |
2054 | 0 | if (pid <= 0) |
2055 | 0 | return true; |
2056 | | |
2057 | | /* Detect whether we should send SIGRTMIN + 3 (e.g. systemd). */ |
2058 | 0 | if (c->lxc_conf && c->lxc_conf->haltsignal) |
2059 | 0 | haltsignal = c->lxc_conf->haltsignal; |
2060 | 0 | else if (task_blocks_signal(pid, (SIGRTMIN + 3))) |
2061 | 0 | haltsignal = (SIGRTMIN + 3); |
2062 | | |
2063 | | |
2064 | | /* |
2065 | | * Add a new state client before sending the shutdown signal so |
2066 | | * that we don't miss a state. |
2067 | | */ |
2068 | 0 | if (timeout != 0) { |
2069 | 0 | states[STOPPED] = 1; |
2070 | 0 | ret = lxc_cmd_add_state_client(c->name, c->config_path, states, |
2071 | 0 | &state_client_fd); |
2072 | 0 | if (ret < 0) |
2073 | 0 | return false; |
2074 | | |
2075 | 0 | if (state_client_fd < 0) |
2076 | 0 | return false; |
2077 | | |
2078 | 0 | if (ret == STOPPED) |
2079 | 0 | return true; |
2080 | | |
2081 | 0 | if (ret < MAX_STATE) |
2082 | 0 | return false; |
2083 | 0 | } |
2084 | | |
2085 | 0 | if (pidfd >= 0) { |
2086 | 0 | struct pollfd pidfd_poll = { |
2087 | 0 | .events = POLLIN, |
2088 | 0 | .fd = pidfd, |
2089 | 0 | }; |
2090 | |
|
2091 | 0 | killret = lxc_raw_pidfd_send_signal(pidfd, haltsignal, |
2092 | 0 | NULL, 0); |
2093 | 0 | if (killret < 0) |
2094 | 0 | return log_warn(false, "Failed to send signal %d to pidfd %d", |
2095 | 0 | haltsignal, pidfd); |
2096 | | |
2097 | 0 | TRACE("Sent signal %d to pidfd %d", haltsignal, pidfd); |
2098 | | |
2099 | | /* |
2100 | | * No need for going through all of the state server |
2101 | | * complications anymore. We can just poll on pidfds. :) |
2102 | | */ |
2103 | |
|
2104 | 0 | if (timeout != 0) { |
2105 | 0 | ret = poll(&pidfd_poll, 1, timeout * 1000); |
2106 | 0 | if (ret < 0 || !(pidfd_poll.revents & POLLIN)) |
2107 | 0 | return false; |
2108 | | |
2109 | 0 | TRACE("Pidfd polling detected container exit"); |
2110 | 0 | } |
2111 | 0 | } else { |
2112 | 0 | killret = kill(pid, haltsignal); |
2113 | 0 | if (killret < 0) |
2114 | 0 | return log_warn(false, "Failed to send signal %d to pid %d", |
2115 | 0 | haltsignal, pid); |
2116 | | |
2117 | 0 | TRACE("Sent signal %d to pid %d", haltsignal, pid); |
2118 | 0 | } |
2119 | | |
2120 | 0 | if (timeout == 0) |
2121 | 0 | return true; |
2122 | | |
2123 | 0 | ret = lxc_cmd_sock_rcv_state(state_client_fd, timeout); |
2124 | 0 | if (ret < 0) |
2125 | 0 | return false; |
2126 | | |
2127 | 0 | TRACE("Received state \"%s\"", lxc_state2str(ret)); |
2128 | 0 | if (ret != STOPPED) |
2129 | 0 | return false; |
2130 | | |
2131 | 0 | return true; |
2132 | 0 | } |
2133 | | |
2134 | 0 | WRAP_API_1(bool, lxcapi_shutdown, int) |
2135 | | |
2136 | | static bool lxcapi_createl(struct lxc_container *c, const char *t, |
2137 | | const char *bdevtype, struct bdev_specs *specs, int flags, ...) |
2138 | 0 | { |
2139 | 0 | bool bret = false; |
2140 | 0 | char **args = NULL; |
2141 | 0 | va_list ap; |
2142 | |
|
2143 | 0 | if (!c) |
2144 | 0 | return false; |
2145 | | |
2146 | 0 | current_config = c->lxc_conf; |
2147 | | |
2148 | | /* |
2149 | | * since we're going to wait for create to finish, I don't think we |
2150 | | * need to get a copy of the arguments. |
2151 | | */ |
2152 | 0 | va_start(ap, flags); |
2153 | 0 | args = lxc_va_arg_list_to_argv(ap, 0, 0); |
2154 | 0 | va_end(ap); |
2155 | 0 | if (!args) { |
2156 | 0 | ERROR("Failed to allocate memory"); |
2157 | 0 | goto out; |
2158 | 0 | } |
2159 | | |
2160 | 0 | bret = __lxcapi_create(c, t, bdevtype, specs, flags, args); |
2161 | |
|
2162 | 0 | out: |
2163 | 0 | free(args); |
2164 | 0 | current_config = NULL; |
2165 | 0 | return bret; |
2166 | 0 | } |
2167 | | |
2168 | | static void do_clear_unexp_config_line(struct lxc_conf *conf, const char *key) |
2169 | 182 | { |
2170 | 182 | if (strequal(key, "lxc.cgroup")) |
2171 | 1 | return clear_unexp_config_line(conf, key, true); |
2172 | | |
2173 | 181 | if (strequal(key, "lxc.network")) |
2174 | 0 | return clear_unexp_config_line(conf, key, true); |
2175 | | |
2176 | 181 | if (strequal(key, "lxc.net")) |
2177 | 1 | return clear_unexp_config_line(conf, key, true); |
2178 | | |
2179 | | /* Clear a network with a specific index. */ |
2180 | 180 | if (strnequal(key, "lxc.net.", 8)) { |
2181 | 95 | int ret; |
2182 | 95 | const char *idx; |
2183 | | |
2184 | 95 | idx = key + 8; |
2185 | 95 | ret = lxc_safe_uint(idx, &(unsigned int){0}); |
2186 | 95 | if (!ret) |
2187 | 95 | return clear_unexp_config_line(conf, key, true); |
2188 | 95 | } |
2189 | | |
2190 | 85 | if (strequal(key, "lxc.hook")) |
2191 | 1 | return clear_unexp_config_line(conf, key, true); |
2192 | | |
2193 | 84 | return clear_unexp_config_line(conf, key, false); |
2194 | 85 | } |
2195 | | |
2196 | | static bool do_lxcapi_clear_config_item(struct lxc_container *c, |
2197 | | const char *key) |
2198 | 0 | { |
2199 | 0 | int ret = 1; |
2200 | 0 | struct lxc_config_t *config; |
2201 | |
|
2202 | 0 | if (!c || !c->lxc_conf) |
2203 | 0 | return false; |
2204 | | |
2205 | 0 | if (container_mem_lock(c)) |
2206 | 0 | return false; |
2207 | | |
2208 | 0 | config = lxc_get_config(key); |
2209 | |
|
2210 | 0 | ret = config->clr(key, c->lxc_conf, NULL); |
2211 | 0 | if (!ret) |
2212 | 0 | do_clear_unexp_config_line(c->lxc_conf, key); |
2213 | |
|
2214 | 0 | container_mem_unlock(c); |
2215 | 0 | return ret == 0; |
2216 | 0 | } |
2217 | | |
2218 | 0 | WRAP_API_1(bool, lxcapi_clear_config_item, const char *) |
2219 | | |
2220 | | static inline bool enter_net_ns(struct lxc_container *c) |
2221 | 0 | { |
2222 | 0 | bool net_ns_entered; |
2223 | 0 | pid_t pid = do_lxcapi_init_pid(c); |
2224 | |
|
2225 | 0 | if (pid < 0) |
2226 | 0 | return false; |
2227 | | |
2228 | 0 | net_ns_entered = try_switch_to_ns(pid, "net", true); |
2229 | |
|
2230 | 0 | if ((geteuid() != 0 || (c->lxc_conf && !list_empty(&c->lxc_conf->id_map))) && |
2231 | 0 | (access("/proc/self/ns/user", F_OK) == 0)) |
2232 | 0 | if (!switch_to_ns(pid, "user")) |
2233 | 0 | return false; |
2234 | | |
2235 | 0 | if (!net_ns_entered) |
2236 | 0 | return switch_to_ns(pid, "net"); |
2237 | | |
2238 | 0 | return true; |
2239 | 0 | } |
2240 | | |
2241 | | /* Used by qsort and bsearch functions for comparing names. */ |
2242 | | static inline int string_cmp(char **first, char **second) |
2243 | 0 | { |
2244 | 0 | return strcmp(*first, *second); |
2245 | 0 | } |
2246 | | |
2247 | | /* Used by qsort and bsearch functions for comparing container names. */ |
2248 | | static inline int container_cmp(struct lxc_container **first, |
2249 | | struct lxc_container **second) |
2250 | 0 | { |
2251 | 0 | return strcmp((*first)->name, (*second)->name); |
2252 | 0 | } |
2253 | | |
2254 | | static bool add_to_array(char ***names, char *cname, int pos) |
2255 | 0 | { |
2256 | 0 | __do_free char *dup_cname = NULL; |
2257 | 0 | char **newnames; |
2258 | |
|
2259 | 0 | dup_cname = strdup(cname); |
2260 | 0 | if (!dup_cname) |
2261 | 0 | return false; |
2262 | | |
2263 | 0 | newnames = realloc(*names, (pos + 1) * sizeof(char *)); |
2264 | 0 | if (!newnames) |
2265 | 0 | return ret_set_errno(false, ENOMEM); |
2266 | | |
2267 | 0 | newnames[pos] = move_ptr(dup_cname); |
2268 | | |
2269 | | /* Sort the array as we will use binary search on it. */ |
2270 | 0 | qsort(newnames, pos + 1, sizeof(char *), |
2271 | 0 | (int (*)(const void *, const void *))string_cmp); |
2272 | |
|
2273 | 0 | *names = newnames; |
2274 | 0 | return true; |
2275 | 0 | } |
2276 | | |
2277 | | static bool add_to_clist(struct lxc_container ***list, struct lxc_container *c, |
2278 | | int pos, bool sort) |
2279 | 0 | { |
2280 | 0 | struct lxc_container **newlist; |
2281 | |
|
2282 | 0 | newlist = realloc(*list, (pos + 1) * sizeof(struct lxc_container *)); |
2283 | 0 | if (!newlist) |
2284 | 0 | return ret_set_errno(false, ENOMEM); |
2285 | | |
2286 | 0 | newlist[pos] = c; |
2287 | | |
2288 | | /* Sort the array as we will use binary search on it. */ |
2289 | 0 | if (sort) |
2290 | 0 | qsort(newlist, pos + 1, sizeof(struct lxc_container *), |
2291 | 0 | (int (*)(const void *, const void *))container_cmp); |
2292 | |
|
2293 | 0 | *list = newlist; |
2294 | 0 | return true; |
2295 | 0 | } |
2296 | | |
2297 | | static char **get_from_array(char ***names, char *cname, int size) |
2298 | 0 | { |
2299 | 0 | if (!*names) |
2300 | 0 | return NULL; |
2301 | | |
2302 | 0 | return bsearch(&cname, *names, size, sizeof(char *), |
2303 | 0 | (int (*)(const void *, const void *))string_cmp); |
2304 | 0 | } |
2305 | | |
2306 | | static bool array_contains(char ***names, char *cname, int size) |
2307 | 0 | { |
2308 | 0 | if (get_from_array(names, cname, size)) |
2309 | 0 | return true; |
2310 | | |
2311 | 0 | return false; |
2312 | 0 | } |
2313 | | |
2314 | | static char **do_lxcapi_get_interfaces(struct lxc_container *c) |
2315 | 0 | { |
2316 | 0 | pid_t pid; |
2317 | 0 | int i, count = 0, pipefd[2]; |
2318 | 0 | char **interfaces = NULL; |
2319 | 0 | char interface[IFNAMSIZ]; |
2320 | |
|
2321 | 0 | if (pipe2(pipefd, O_CLOEXEC)) |
2322 | 0 | return log_error_errno(NULL, errno, "Failed to create pipe"); |
2323 | | |
2324 | 0 | pid = fork(); |
2325 | 0 | if (pid < 0) { |
2326 | 0 | close(pipefd[0]); |
2327 | 0 | close(pipefd[1]); |
2328 | 0 | return log_error_errno(NULL, errno, "Failed to fork task to get interfaces information"); |
2329 | 0 | } |
2330 | | |
2331 | 0 | if (pid == 0) { |
2332 | 0 | call_cleaner(netns_freeifaddrs) struct netns_ifaddrs *ifaddrs = NULL; |
2333 | 0 | struct netns_ifaddrs *ifa = NULL; |
2334 | 0 | int ret = 1; |
2335 | 0 | int nbytes; |
2336 | | |
2337 | | /* close the read-end of the pipe */ |
2338 | 0 | close(pipefd[0]); |
2339 | |
|
2340 | 0 | if (!enter_net_ns(c)) { |
2341 | 0 | SYSERROR("Failed to enter network namespace"); |
2342 | 0 | goto out; |
2343 | 0 | } |
2344 | | |
2345 | | /* Grab the list of interfaces */ |
2346 | 0 | if (netns_getifaddrs(&ifaddrs, -1, &(bool){false})) { |
2347 | 0 | SYSERROR("Failed to get interfaces list"); |
2348 | 0 | goto out; |
2349 | 0 | } |
2350 | | |
2351 | | /* Iterate through the interfaces */ |
2352 | 0 | for (ifa = ifaddrs; ifa != NULL; |
2353 | 0 | ifa = ifa->ifa_next) { |
2354 | 0 | nbytes = lxc_write_nointr(pipefd[1], ifa->ifa_name, IFNAMSIZ); |
2355 | 0 | if (nbytes < 0) |
2356 | 0 | goto out; |
2357 | | |
2358 | 0 | count++; |
2359 | 0 | } |
2360 | | |
2361 | 0 | ret = 0; |
2362 | |
|
2363 | 0 | out: |
2364 | | /* close the write-end of the pipe, thus sending EOF to the reader */ |
2365 | 0 | close(pipefd[1]); |
2366 | 0 | _exit(ret); |
2367 | 0 | } |
2368 | | |
2369 | | /* close the write-end of the pipe */ |
2370 | 0 | close(pipefd[1]); |
2371 | |
|
2372 | 0 | while (lxc_read_nointr(pipefd[0], &interface, IFNAMSIZ) == IFNAMSIZ) { |
2373 | 0 | interface[IFNAMSIZ - 1] = '\0'; |
2374 | |
|
2375 | 0 | if (array_contains(&interfaces, interface, count)) |
2376 | 0 | continue; |
2377 | | |
2378 | 0 | if (!add_to_array(&interfaces, interface, count)) |
2379 | 0 | ERROR("Failed to add \"%s\" to array", interface); |
2380 | |
|
2381 | 0 | count++; |
2382 | 0 | } |
2383 | |
|
2384 | 0 | if (wait_for_pid(pid)) { |
2385 | 0 | for (i = 0; i < count; i++) |
2386 | 0 | free(interfaces[i]); |
2387 | |
|
2388 | 0 | free(interfaces); |
2389 | 0 | interfaces = NULL; |
2390 | 0 | } |
2391 | | |
2392 | | /* close the read-end of the pipe */ |
2393 | 0 | close(pipefd[0]); |
2394 | | |
2395 | | /* Append NULL to the array */ |
2396 | 0 | if (interfaces) |
2397 | 0 | interfaces = (char **)lxc_append_null_to_array((void **)interfaces, count); |
2398 | |
|
2399 | 0 | return interfaces; |
2400 | 0 | } |
2401 | | |
2402 | 0 | WRAP_API(char **, lxcapi_get_interfaces) |
2403 | | |
2404 | | static char **do_lxcapi_get_ips(struct lxc_container *c, const char *interface, |
2405 | | const char *family, int scope) |
2406 | 0 | { |
2407 | 0 | int i, ret; |
2408 | 0 | pid_t pid; |
2409 | 0 | int pipefd[2]; |
2410 | 0 | char address[INET6_ADDRSTRLEN]; |
2411 | 0 | int count = 0; |
2412 | 0 | char **addresses = NULL; |
2413 | |
|
2414 | 0 | ret = pipe2(pipefd, O_CLOEXEC); |
2415 | 0 | if (ret < 0) |
2416 | 0 | return log_error_errno(NULL, errno, "Failed to create pipe"); |
2417 | | |
2418 | 0 | pid = fork(); |
2419 | 0 | if (pid < 0) { |
2420 | 0 | SYSERROR("Failed to create new process"); |
2421 | 0 | close(pipefd[0]); |
2422 | 0 | close(pipefd[1]); |
2423 | 0 | return NULL; |
2424 | 0 | } |
2425 | | |
2426 | 0 | if (pid == 0) { |
2427 | 0 | call_cleaner(netns_freeifaddrs) struct netns_ifaddrs *ifaddrs = NULL; |
2428 | 0 | struct netns_ifaddrs *ifa = NULL; |
2429 | 0 | ssize_t nbytes; |
2430 | 0 | char addressOutputBuffer[INET6_ADDRSTRLEN]; |
2431 | 0 | char *address_ptr = NULL; |
2432 | 0 | void *address_ptr_tmp = NULL; |
2433 | | |
2434 | | /* close the read-end of the pipe */ |
2435 | 0 | close(pipefd[0]); |
2436 | |
|
2437 | 0 | if (!enter_net_ns(c)) { |
2438 | 0 | SYSERROR("Failed to attach to network namespace"); |
2439 | 0 | goto out; |
2440 | 0 | } |
2441 | | |
2442 | | /* Grab the list of interfaces */ |
2443 | 0 | if (netns_getifaddrs(&ifaddrs, -1, &(bool){false})) { |
2444 | 0 | SYSERROR("Failed to get interfaces list"); |
2445 | 0 | goto out; |
2446 | 0 | } |
2447 | | |
2448 | | /* Iterate through the interfaces */ |
2449 | 0 | for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) { |
2450 | 0 | if (ifa->ifa_addr == NULL) |
2451 | 0 | continue; |
2452 | | |
2453 | 0 | #pragma GCC diagnostic push |
2454 | 0 | #pragma GCC diagnostic ignored "-Wcast-align" |
2455 | | |
2456 | 0 | if (ifa->ifa_addr->sa_family == AF_INET) { |
2457 | 0 | if (family && !strequal(family, "inet")) |
2458 | 0 | continue; |
2459 | | |
2460 | 0 | address_ptr_tmp = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; |
2461 | 0 | } else { |
2462 | 0 | if (family && !strequal(family, "inet6")) |
2463 | 0 | continue; |
2464 | | |
2465 | 0 | if (((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id != (uint32_t)scope) |
2466 | 0 | continue; |
2467 | | |
2468 | 0 | address_ptr_tmp = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; |
2469 | 0 | } |
2470 | | |
2471 | 0 | #pragma GCC diagnostic pop |
2472 | | |
2473 | 0 | if (interface && !strequal(interface, ifa->ifa_name)) |
2474 | 0 | continue; |
2475 | 0 | else if (!interface && strequal("lo", ifa->ifa_name)) |
2476 | 0 | continue; |
2477 | | |
2478 | 0 | address_ptr = (char *)inet_ntop(ifa->ifa_addr->sa_family, address_ptr_tmp, |
2479 | 0 | addressOutputBuffer, |
2480 | 0 | sizeof(addressOutputBuffer)); |
2481 | 0 | if (!address_ptr) |
2482 | 0 | continue; |
2483 | | |
2484 | 0 | nbytes = lxc_write_nointr(pipefd[1], address_ptr, INET6_ADDRSTRLEN); |
2485 | 0 | if (nbytes != INET6_ADDRSTRLEN) { |
2486 | 0 | SYSERROR("Failed to send ipv6 address \"%s\"", address_ptr); |
2487 | 0 | goto out; |
2488 | 0 | } |
2489 | | |
2490 | 0 | count++; |
2491 | 0 | } |
2492 | | |
2493 | 0 | ret = 0; |
2494 | |
|
2495 | 0 | out: |
2496 | | /* close the write-end of the pipe, thus sending EOF to the reader */ |
2497 | 0 | close(pipefd[1]); |
2498 | 0 | _exit(ret); |
2499 | 0 | } |
2500 | | |
2501 | | /* close the write-end of the pipe */ |
2502 | 0 | close(pipefd[1]); |
2503 | |
|
2504 | 0 | while (lxc_read_nointr(pipefd[0], &address, INET6_ADDRSTRLEN) == INET6_ADDRSTRLEN) { |
2505 | 0 | address[INET6_ADDRSTRLEN - 1] = '\0'; |
2506 | |
|
2507 | 0 | if (!add_to_array(&addresses, address, count)) |
2508 | 0 | ERROR("PARENT: add_to_array failed"); |
2509 | |
|
2510 | 0 | count++; |
2511 | 0 | } |
2512 | |
|
2513 | 0 | if (wait_for_pid(pid)) { |
2514 | 0 | for (i = 0; i < count; i++) |
2515 | 0 | free(addresses[i]); |
2516 | |
|
2517 | 0 | free(addresses); |
2518 | 0 | addresses = NULL; |
2519 | 0 | } |
2520 | | |
2521 | | /* close the read-end of the pipe */ |
2522 | 0 | close(pipefd[0]); |
2523 | | |
2524 | | /* Append NULL to the array */ |
2525 | 0 | if (addresses) |
2526 | 0 | addresses = (char **)lxc_append_null_to_array((void **)addresses, count); |
2527 | |
|
2528 | 0 | return addresses; |
2529 | 0 | } |
2530 | | |
2531 | 0 | WRAP_API_3(char **, lxcapi_get_ips, const char *, const char *, int) |
2532 | | |
2533 | | static int do_lxcapi_get_config_item(struct lxc_container *c, const char *key, char *retv, int inlen) |
2534 | 6.67k | { |
2535 | 6.67k | int ret = -1; |
2536 | 6.67k | struct lxc_config_t *config; |
2537 | | |
2538 | 6.67k | if (!c || !c->lxc_conf) |
2539 | 0 | return -1; |
2540 | | |
2541 | 6.67k | if (container_mem_lock(c)) |
2542 | 0 | return -1; |
2543 | | |
2544 | 6.67k | config = lxc_get_config(key); |
2545 | | |
2546 | 6.67k | ret = config->get(key, retv, inlen, c->lxc_conf, NULL); |
2547 | | |
2548 | 6.67k | container_mem_unlock(c); |
2549 | 6.67k | return ret; |
2550 | 6.67k | } |
2551 | | |
2552 | 6.67k | WRAP_API_3(int, lxcapi_get_config_item, const char *, char *, int) |
2553 | | |
2554 | | static char* do_lxcapi_get_running_config_item(struct lxc_container *c, const char *key) |
2555 | 0 | { |
2556 | 0 | char *ret; |
2557 | |
|
2558 | 0 | if (!c || !c->lxc_conf) |
2559 | 0 | return NULL; |
2560 | | |
2561 | 0 | if (container_mem_lock(c)) |
2562 | 0 | return NULL; |
2563 | | |
2564 | 0 | ret = lxc_cmd_get_config_item(c->name, key, do_lxcapi_get_config_path(c)); |
2565 | 0 | container_mem_unlock(c); |
2566 | 0 | return ret; |
2567 | 0 | } |
2568 | | |
2569 | 0 | WRAP_API_1(char *, lxcapi_get_running_config_item, const char *) |
2570 | | |
2571 | | static int do_lxcapi_get_keys(struct lxc_container *c, const char *key, char *retv, int inlen) |
2572 | 0 | { |
2573 | 0 | int ret = -1; |
2574 | | |
2575 | | /* List all config items. */ |
2576 | 0 | if (!key) |
2577 | 0 | return lxc_list_config_items(retv, inlen); |
2578 | | |
2579 | 0 | if (!c || !c->lxc_conf) |
2580 | 0 | return -1; |
2581 | | |
2582 | 0 | if (container_mem_lock(c)) |
2583 | 0 | return -1; |
2584 | | |
2585 | | /* Support 'lxc.net.<idx>', i.e. 'lxc.net.0' |
2586 | | * This is an intelligent result to show which keys are valid given the |
2587 | | * type of nic it is. |
2588 | | */ |
2589 | 0 | if (strnequal(key, "lxc.net.", 8)) |
2590 | 0 | ret = lxc_list_net(c->lxc_conf, key, retv, inlen); |
2591 | 0 | else |
2592 | 0 | ret = lxc_list_subkeys(c->lxc_conf, key, retv, inlen); |
2593 | |
|
2594 | 0 | container_mem_unlock(c); |
2595 | 0 | return ret; |
2596 | 0 | } |
2597 | | |
2598 | 0 | WRAP_API_3(int, lxcapi_get_keys, const char *, char *, int) |
2599 | | |
2600 | | static bool do_lxcapi_save_config(struct lxc_container *c, const char *alt_file) |
2601 | 0 | { |
2602 | 0 | __do_close int fd_config = -EBADF, fd_rootfs = -EBADF; |
2603 | 0 | int lret = -1; |
2604 | 0 | bool bret = false, need_disklock = false; |
2605 | |
|
2606 | 0 | if (!alt_file) |
2607 | 0 | alt_file = c->configfile; |
2608 | |
|
2609 | 0 | if (!alt_file) |
2610 | 0 | return log_error(false, "No config file found"); |
2611 | | |
2612 | | /* If we haven't yet loaded a config, load the stock config. */ |
2613 | 0 | if (!c->lxc_conf) { |
2614 | 0 | if (!do_lxcapi_load_config(c, lxc_global_config_value("lxc.default_config"))) { |
2615 | 0 | return log_error(false, "Error loading default configuration file %s while saving %s", |
2616 | 0 | lxc_global_config_value("lxc.default_config"), c->name); |
2617 | 0 | } |
2618 | 0 | } |
2619 | | |
2620 | 0 | fd_rootfs = create_container_dir(c); |
2621 | 0 | if (fd_rootfs < 0) |
2622 | 0 | return log_error(false, "Failed to create container directory"); |
2623 | | |
2624 | | /* If we're writing to the container's config file, take the disk lock. |
2625 | | * Otherwise just take the memlock to protect the struct lxc_container |
2626 | | * while we're traversing it. |
2627 | | */ |
2628 | 0 | if (strequal(c->configfile, alt_file)) |
2629 | 0 | need_disklock = true; |
2630 | |
|
2631 | 0 | if (need_disklock) |
2632 | 0 | lret = container_disk_lock(c); |
2633 | 0 | else |
2634 | 0 | lret = container_mem_lock(c); |
2635 | 0 | if (lret) |
2636 | 0 | return log_error(false, "Failed to acquire lock"); |
2637 | | |
2638 | 0 | fd_config = open(alt_file, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, |
2639 | 0 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); |
2640 | 0 | if (fd_config < 0) { |
2641 | 0 | SYSERROR("Failed to open config file \"%s\"", alt_file); |
2642 | 0 | goto on_error; |
2643 | 0 | } |
2644 | | |
2645 | 0 | lret = write_config(fd_config, c->lxc_conf); |
2646 | 0 | if (lret < 0) { |
2647 | 0 | SYSERROR("Failed to write config file \"%s\"", alt_file); |
2648 | 0 | goto on_error; |
2649 | 0 | } |
2650 | | |
2651 | 0 | bret = true; |
2652 | 0 | TRACE("Saved config file \"%s\"", alt_file); |
2653 | |
|
2654 | 0 | on_error: |
2655 | 0 | if (need_disklock) |
2656 | 0 | container_disk_unlock(c); |
2657 | 0 | else |
2658 | 0 | container_mem_unlock(c); |
2659 | |
|
2660 | 0 | return bret; |
2661 | 0 | } |
2662 | | |
2663 | 0 | WRAP_API_1(bool, lxcapi_save_config, const char *) |
2664 | | |
2665 | | |
2666 | | static bool mod_rdep(struct lxc_container *c0, struct lxc_container *c, bool inc) |
2667 | 0 | { |
2668 | 0 | __do_close int fd = -EBADF; |
2669 | 0 | FILE *f1; |
2670 | 0 | struct stat fbuf; |
2671 | 0 | void *buf = NULL; |
2672 | 0 | char *del = NULL; |
2673 | 0 | char path[PATH_MAX]; |
2674 | 0 | char newpath[PATH_MAX]; |
2675 | 0 | int ret, n = 0, v = 0; |
2676 | 0 | bool bret = false; |
2677 | 0 | size_t len = 0, bytes = 0; |
2678 | |
|
2679 | 0 | if (container_disk_lock(c0)) |
2680 | 0 | return false; |
2681 | | |
2682 | 0 | ret = strnprintf(path, sizeof(path), "%s/%s/lxc_snapshots", c0->config_path, c0->name); |
2683 | 0 | if (ret < 0) |
2684 | 0 | goto out; |
2685 | | |
2686 | 0 | ret = strnprintf(newpath, sizeof(newpath), "%s\n%s\n", c->config_path, c->name); |
2687 | 0 | if (ret < 0) |
2688 | 0 | goto out; |
2689 | | |
2690 | | /* If we find an lxc-snapshot file using the old format only listing the |
2691 | | * number of snapshots we will keep using it. */ |
2692 | 0 | f1 = fopen(path, "re"); |
2693 | 0 | if (f1) { |
2694 | 0 | n = fscanf(f1, "%d", &v); |
2695 | 0 | fclose(f1); |
2696 | 0 | if (n == 1 && v == 0) { |
2697 | 0 | ret = remove(path); |
2698 | 0 | if (ret < 0) |
2699 | 0 | SYSERROR("Failed to remove \"%s\"", path); |
2700 | |
|
2701 | 0 | n = 0; |
2702 | 0 | } |
2703 | 0 | } |
2704 | |
|
2705 | 0 | if (n == 1) { |
2706 | 0 | v += inc ? 1 : -1; |
2707 | 0 | f1 = fopen(path, "we"); |
2708 | 0 | if (!f1) |
2709 | 0 | goto out; |
2710 | | |
2711 | 0 | if (fprintf(f1, "%d\n", v) < 0) { |
2712 | 0 | ERROR("Error writing new snapshots value"); |
2713 | 0 | fclose(f1); |
2714 | 0 | goto out; |
2715 | 0 | } |
2716 | | |
2717 | 0 | ret = fclose(f1); |
2718 | 0 | if (ret != 0) { |
2719 | 0 | SYSERROR("Error writing to or closing snapshots file"); |
2720 | 0 | goto out; |
2721 | 0 | } |
2722 | 0 | } else { |
2723 | | /* Here we know that we have or can use an lxc-snapshot file |
2724 | | * using the new format. */ |
2725 | 0 | if (inc) { |
2726 | 0 | fd = open(path, O_APPEND | O_WRONLY | O_CREAT | O_CLOEXEC, 0644); |
2727 | 0 | if (fd < 0) |
2728 | 0 | goto out; |
2729 | | |
2730 | 0 | ret = lxc_write_nointr(fd, newpath, strlen(newpath)); |
2731 | 0 | if (ret < 0) { |
2732 | 0 | ERROR("Error writing new snapshots entry"); |
2733 | 0 | goto out; |
2734 | 0 | } |
2735 | 0 | } else if (!inc) { |
2736 | 0 | fd = open(path, O_RDWR | O_CLOEXEC); |
2737 | 0 | if (fd < 0) |
2738 | 0 | goto out; |
2739 | | |
2740 | 0 | if (fstat(fd, &fbuf) < 0) |
2741 | 0 | goto out; |
2742 | | |
2743 | 0 | if (fbuf.st_size != 0) { |
2744 | 0 | buf = lxc_strmmap(NULL, fbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); |
2745 | 0 | if (buf == MAP_FAILED) { |
2746 | 0 | SYSERROR("Failed to create mapping %s", path); |
2747 | 0 | goto out; |
2748 | 0 | } |
2749 | | |
2750 | 0 | len = strlen(newpath); |
2751 | 0 | while ((del = strstr((char *)buf, newpath))) { |
2752 | 0 | memmove(del, del + len, strlen(del) - len + 1); |
2753 | 0 | bytes += len; |
2754 | 0 | } |
2755 | |
|
2756 | 0 | lxc_strmunmap(buf, fbuf.st_size); |
2757 | 0 | if (ftruncate(fd, fbuf.st_size - bytes) < 0) { |
2758 | 0 | SYSERROR("Failed to truncate file %s", path); |
2759 | 0 | goto out; |
2760 | 0 | } |
2761 | 0 | } |
2762 | 0 | } |
2763 | | |
2764 | | /* If the lxc-snapshot file is empty, remove it. */ |
2765 | 0 | if (fstat(fd, &fbuf) < 0) |
2766 | 0 | goto out; |
2767 | | |
2768 | 0 | if (!fbuf.st_size) { |
2769 | 0 | ret = remove(path); |
2770 | 0 | if (ret < 0) |
2771 | 0 | SYSERROR("Failed to remove \"%s\"", path); |
2772 | 0 | } |
2773 | 0 | } |
2774 | | |
2775 | 0 | bret = true; |
2776 | |
|
2777 | 0 | out: |
2778 | 0 | container_disk_unlock(c0); |
2779 | 0 | return bret; |
2780 | 0 | } |
2781 | | |
2782 | | void mod_all_rdeps(struct lxc_container *c, bool inc) |
2783 | 0 | { |
2784 | 0 | __do_free char *lxcpath = NULL, *lxcname = NULL; |
2785 | 0 | __do_fclose FILE *f = NULL; |
2786 | 0 | size_t pathlen = 0, namelen = 0; |
2787 | 0 | struct lxc_container *p; |
2788 | 0 | char path[PATH_MAX]; |
2789 | 0 | int ret; |
2790 | |
|
2791 | 0 | ret = strnprintf(path, sizeof(path), "%s/%s/lxc_rdepends", |
2792 | 0 | c->config_path, c->name); |
2793 | 0 | if (ret < 0) { |
2794 | 0 | ERROR("Path name too long"); |
2795 | 0 | return; |
2796 | 0 | } |
2797 | | |
2798 | 0 | f = fopen(path, "re"); |
2799 | 0 | if (!f) |
2800 | 0 | return; |
2801 | | |
2802 | 0 | while (getline(&lxcpath, &pathlen, f) != -1) { |
2803 | 0 | if (getline(&lxcname, &namelen, f) == -1) { |
2804 | 0 | ERROR("badly formatted file %s", path); |
2805 | 0 | return; |
2806 | 0 | } |
2807 | | |
2808 | 0 | remove_trailing_newlines(lxcpath); |
2809 | 0 | remove_trailing_newlines(lxcname); |
2810 | |
|
2811 | 0 | if ((p = lxc_container_new(lxcname, lxcpath)) == NULL) { |
2812 | 0 | ERROR("Unable to find dependent container %s:%s", |
2813 | 0 | lxcpath, lxcname); |
2814 | 0 | continue; |
2815 | 0 | } |
2816 | | |
2817 | 0 | if (!mod_rdep(p, c, inc)) |
2818 | 0 | ERROR("Failed to update snapshots file for %s:%s", |
2819 | 0 | lxcpath, lxcname); |
2820 | |
|
2821 | 0 | lxc_container_put(p); |
2822 | 0 | } |
2823 | 0 | } |
2824 | | |
2825 | | static bool has_fs_snapshots(struct lxc_container *c) |
2826 | 0 | { |
2827 | 0 | __do_fclose FILE *f = NULL; |
2828 | 0 | char path[PATH_MAX]; |
2829 | 0 | int ret, v; |
2830 | 0 | struct stat fbuf; |
2831 | |
|
2832 | 0 | ret = strnprintf(path, sizeof(path), "%s/%s/lxc_snapshots", c->config_path, |
2833 | 0 | c->name); |
2834 | 0 | if (ret < 0) |
2835 | 0 | return false; |
2836 | | |
2837 | | /* If the file doesn't exist there are no snapshots. */ |
2838 | 0 | if (stat(path, &fbuf) < 0) |
2839 | 0 | return false; |
2840 | | |
2841 | 0 | v = fbuf.st_size; |
2842 | 0 | if (v != 0) { |
2843 | 0 | f = fopen(path, "re"); |
2844 | 0 | if (!f) |
2845 | 0 | return false; |
2846 | | |
2847 | 0 | ret = fscanf(f, "%d", &v); |
2848 | 0 | if (ret != 1) |
2849 | 0 | INFO("Container uses new lxc-snapshots format %s", path); |
2850 | 0 | } |
2851 | | |
2852 | 0 | return v != 0; |
2853 | 0 | } |
2854 | | |
2855 | | static bool has_snapshots(struct lxc_container *c) |
2856 | 0 | { |
2857 | 0 | __do_closedir DIR *dir = NULL; |
2858 | 0 | char path[PATH_MAX]; |
2859 | 0 | struct dirent *direntp; |
2860 | 0 | int count = 0; |
2861 | |
|
2862 | 0 | if (!get_snappath_dir(c, path)) |
2863 | 0 | return false; |
2864 | | |
2865 | 0 | dir = opendir(path); |
2866 | 0 | if (!dir) |
2867 | 0 | return false; |
2868 | | |
2869 | 0 | while ((direntp = readdir(dir))) { |
2870 | 0 | if (strequal(direntp->d_name, ".")) |
2871 | 0 | continue; |
2872 | | |
2873 | 0 | if (strequal(direntp->d_name, "..")) |
2874 | 0 | continue; |
2875 | 0 | count++; |
2876 | 0 | break; |
2877 | 0 | } |
2878 | |
|
2879 | 0 | return count > 0; |
2880 | 0 | } |
2881 | | |
2882 | 0 | static bool do_destroy_container(struct lxc_conf *conf) { |
2883 | 0 | int ret; |
2884 | |
|
2885 | 0 | if (am_guest_unpriv()) { |
2886 | 0 | ret = userns_exec_full(conf, storage_destroy_wrapper, conf, |
2887 | 0 | "storage_destroy_wrapper"); |
2888 | 0 | if (ret < 0) |
2889 | 0 | return false; |
2890 | | |
2891 | 0 | return true; |
2892 | 0 | } |
2893 | | |
2894 | 0 | return storage_destroy(conf); |
2895 | 0 | } |
2896 | | |
2897 | | static int lxc_rmdir_onedev_wrapper(void *data) |
2898 | 0 | { |
2899 | 0 | char *arg = (char *) data; |
2900 | 0 | return lxc_rmdir_onedev(arg, "snaps"); |
2901 | 0 | } |
2902 | | |
2903 | | static int lxc_unlink_exec_wrapper(void *data) |
2904 | 0 | { |
2905 | 0 | char *arg = data; |
2906 | 0 | return unlink(arg); |
2907 | 0 | } |
2908 | | |
2909 | | static bool container_destroy(struct lxc_container *c, |
2910 | | struct lxc_storage *storage) |
2911 | 0 | { |
2912 | 0 | const char *p1; |
2913 | 0 | size_t len; |
2914 | 0 | struct lxc_conf *conf; |
2915 | 0 | char *path = NULL; |
2916 | 0 | bool bret = false; |
2917 | 0 | int ret = 0; |
2918 | |
|
2919 | 0 | if (!c || !do_lxcapi_is_defined(c)) |
2920 | 0 | return false; |
2921 | | |
2922 | 0 | conf = c->lxc_conf; |
2923 | 0 | if (container_disk_lock(c)) |
2924 | 0 | return false; |
2925 | | |
2926 | 0 | if (!is_stopped(c)) { |
2927 | | /* We should queue some sort of error - in c->error_string? */ |
2928 | 0 | ERROR("container %s is not stopped", c->name); |
2929 | 0 | goto out; |
2930 | 0 | } |
2931 | | |
2932 | 0 | if (conf && !list_empty(&conf->hooks[LXCHOOK_DESTROY])) { |
2933 | | /* Start of environment variable setup for hooks */ |
2934 | 0 | if (setenv("LXC_NAME", c->name, 1)) |
2935 | 0 | SYSERROR("Failed to set environment variable for container name"); |
2936 | |
|
2937 | 0 | if (conf->rcfile && setenv("LXC_CONFIG_FILE", conf->rcfile, 1)) |
2938 | 0 | SYSERROR("Failed to set environment variable for config path"); |
2939 | |
|
2940 | 0 | if (conf->rootfs.mount && setenv("LXC_ROOTFS_MOUNT", conf->rootfs.mount, 1)) |
2941 | 0 | SYSERROR("Failed to set environment variable for rootfs mount"); |
2942 | |
|
2943 | 0 | if (conf->rootfs.path && setenv("LXC_ROOTFS_PATH", conf->rootfs.path, 1)) |
2944 | 0 | SYSERROR("Failed to set environment variable for rootfs mount"); |
2945 | |
|
2946 | 0 | if (conf->console.path && setenv("LXC_CONSOLE", conf->console.path, 1)) |
2947 | 0 | SYSERROR("Failed to set environment variable for console path"); |
2948 | |
|
2949 | 0 | if (conf->console.log_path && setenv("LXC_CONSOLE_LOGPATH", conf->console.log_path, 1)) |
2950 | 0 | SYSERROR("Failed to set environment variable for console log"); |
2951 | | /* End of environment variable setup for hooks */ |
2952 | |
|
2953 | 0 | if (run_lxc_hooks(c->name, "destroy", conf, NULL)) { |
2954 | 0 | ERROR("Failed to execute clone hook for \"%s\"", c->name); |
2955 | 0 | goto out; |
2956 | 0 | } |
2957 | 0 | } |
2958 | | |
2959 | 0 | if (current_config && conf == current_config) { |
2960 | 0 | current_config = NULL; |
2961 | |
|
2962 | 0 | if (conf->logfd != -1) { |
2963 | 0 | close(conf->logfd); |
2964 | 0 | conf->logfd = -1; |
2965 | 0 | } |
2966 | 0 | } |
2967 | | |
2968 | | /* LXC is not managing the storage of the container. */ |
2969 | 0 | if (conf && !conf->rootfs.managed) |
2970 | 0 | goto on_success; |
2971 | | |
2972 | 0 | if (conf && conf->rootfs.path && conf->rootfs.mount) { |
2973 | 0 | if (!do_destroy_container(conf)) { |
2974 | 0 | ERROR("Error destroying rootfs for %s", c->name); |
2975 | 0 | goto out; |
2976 | 0 | } |
2977 | 0 | INFO("Destroyed rootfs for %s", c->name); |
2978 | 0 | } |
2979 | | |
2980 | 0 | mod_all_rdeps(c, false); |
2981 | |
|
2982 | 0 | p1 = do_lxcapi_get_config_path(c); |
2983 | | /* strlen(p1) |
2984 | | * + |
2985 | | * / |
2986 | | * + |
2987 | | * strlen(c->name) |
2988 | | * + |
2989 | | * / |
2990 | | * + |
2991 | | * strlen("config") = 6 |
2992 | | * + |
2993 | | * \0 |
2994 | | */ |
2995 | 0 | len = strlen(p1) + 1 + strlen(c->name) + 1 + strlen(LXC_CONFIG_FNAME) + 1; |
2996 | 0 | path = malloc(len); |
2997 | 0 | if (!path) { |
2998 | 0 | ERROR("Failed to allocate memory"); |
2999 | 0 | goto out; |
3000 | 0 | } |
3001 | | |
3002 | | /* For an overlay container the rootfs is considered immutable and |
3003 | | * cannot be removed when restoring from a snapshot. |
3004 | | */ |
3005 | 0 | if (storage && (strequal(storage->type, "overlay") || |
3006 | 0 | strequal(storage->type, "overlayfs")) && |
3007 | 0 | (storage->flags & LXC_STORAGE_INTERNAL_OVERLAY_RESTORE)) { |
3008 | 0 | ret = strnprintf(path, len, "%s/%s/%s", p1, c->name, LXC_CONFIG_FNAME); |
3009 | 0 | if (ret < 0) |
3010 | 0 | goto out; |
3011 | | |
3012 | 0 | if (am_guest_unpriv()) |
3013 | 0 | ret = userns_exec_1(conf, lxc_unlink_exec_wrapper, path, |
3014 | 0 | "lxc_unlink_exec_wrapper"); |
3015 | 0 | else |
3016 | 0 | ret = unlink(path); |
3017 | 0 | if (ret < 0) { |
3018 | 0 | SYSERROR("Failed to destroy config file \"%s\" for \"%s\"", |
3019 | 0 | path, c->name); |
3020 | 0 | goto out; |
3021 | 0 | } |
3022 | 0 | INFO("Destroyed config file \"%s\" for \"%s\"", path, c->name); |
3023 | |
|
3024 | 0 | bret = true; |
3025 | 0 | goto out; |
3026 | 0 | } |
3027 | | |
3028 | 0 | ret = strnprintf(path, len, "%s/%s", p1, c->name); |
3029 | 0 | if (ret < 0) |
3030 | 0 | goto out; |
3031 | | |
3032 | 0 | if (am_guest_unpriv()) |
3033 | 0 | ret = userns_exec_full(conf, lxc_rmdir_onedev_wrapper, path, |
3034 | 0 | "lxc_rmdir_onedev_wrapper"); |
3035 | 0 | else |
3036 | 0 | ret = lxc_rmdir_onedev(path, "snaps"); |
3037 | 0 | if (ret < 0) { |
3038 | 0 | ERROR("Failed to destroy directory \"%s\" for \"%s\"", path, |
3039 | 0 | c->name); |
3040 | 0 | goto out; |
3041 | 0 | } |
3042 | 0 | INFO("Destroyed directory \"%s\" for \"%s\"", path, c->name); |
3043 | |
|
3044 | 0 | on_success: |
3045 | 0 | bret = true; |
3046 | |
|
3047 | 0 | out: |
3048 | 0 | if (path) |
3049 | 0 | free(path); |
3050 | |
|
3051 | 0 | container_disk_unlock(c); |
3052 | 0 | return bret; |
3053 | 0 | } |
3054 | | |
3055 | | static bool do_lxcapi_destroy(struct lxc_container *c) |
3056 | 0 | { |
3057 | 0 | if (!c || !lxcapi_is_defined(c)) |
3058 | 0 | return false; |
3059 | | |
3060 | 0 | if (c->lxc_conf && c->lxc_conf->rootfs.managed) { |
3061 | 0 | if (has_snapshots(c)) { |
3062 | 0 | ERROR("Container %s has snapshots; not removing", c->name); |
3063 | 0 | return false; |
3064 | 0 | } |
3065 | | |
3066 | 0 | if (has_fs_snapshots(c)) { |
3067 | 0 | ERROR("container %s has snapshots on its rootfs", c->name); |
3068 | 0 | return false; |
3069 | 0 | } |
3070 | 0 | } |
3071 | | |
3072 | 0 | return container_destroy(c, NULL); |
3073 | 0 | } |
3074 | | |
3075 | 0 | WRAP_API(bool, lxcapi_destroy) |
3076 | | |
3077 | | static bool do_lxcapi_destroy_with_snapshots(struct lxc_container *c) |
3078 | 0 | { |
3079 | 0 | if (!c || !lxcapi_is_defined(c)) |
3080 | 0 | return false; |
3081 | | |
3082 | 0 | if (!lxcapi_snapshot_destroy_all(c)) { |
3083 | 0 | ERROR("Error deleting all snapshots"); |
3084 | 0 | return false; |
3085 | 0 | } |
3086 | | |
3087 | 0 | return lxcapi_destroy(c); |
3088 | 0 | } |
3089 | | |
3090 | 0 | WRAP_API(bool, lxcapi_destroy_with_snapshots) |
3091 | | |
3092 | | int lxc_set_config_item_locked(struct lxc_conf *conf, const char *key, |
3093 | | const char *v) |
3094 | 7.92k | { |
3095 | 7.92k | int ret; |
3096 | 7.92k | struct lxc_config_t *config; |
3097 | 7.92k | bool bret = true; |
3098 | | |
3099 | 7.92k | config = lxc_get_config(key); |
3100 | | |
3101 | 7.92k | ret = config->set(key, v, conf, NULL); |
3102 | 7.92k | if (ret < 0) |
3103 | 4.52k | return -EINVAL; |
3104 | | |
3105 | 3.40k | if (lxc_config_value_empty(v)) |
3106 | 182 | do_clear_unexp_config_line(conf, key); |
3107 | 3.21k | else |
3108 | 3.21k | bret = do_append_unexp_config_line(conf, key, v); |
3109 | 3.40k | if (!bret) |
3110 | 0 | return -ENOMEM; |
3111 | | |
3112 | 3.40k | return 0; |
3113 | 3.40k | } |
3114 | | |
3115 | | static bool do_set_config_item_locked(struct lxc_container *c, const char *key, |
3116 | | const char *v) |
3117 | 7.92k | { |
3118 | 7.92k | int ret; |
3119 | | |
3120 | 7.92k | if (!c->lxc_conf) |
3121 | 7.92k | c->lxc_conf = lxc_conf_init(); |
3122 | | |
3123 | 7.92k | if (!c->lxc_conf) |
3124 | 0 | return false; |
3125 | | |
3126 | 7.92k | ret = lxc_set_config_item_locked(c->lxc_conf, key, v); |
3127 | 7.92k | if (ret < 0) |
3128 | 4.52k | return false; |
3129 | | |
3130 | 3.40k | return true; |
3131 | 7.92k | } |
3132 | | |
3133 | | static bool do_lxcapi_set_config_item(struct lxc_container *c, const char *key, const char *v) |
3134 | 7.92k | { |
3135 | 7.92k | bool b = false; |
3136 | | |
3137 | 7.92k | if (!c) |
3138 | 0 | return false; |
3139 | | |
3140 | 7.92k | if (container_mem_lock(c)) |
3141 | 0 | return false; |
3142 | | |
3143 | 7.92k | b = do_set_config_item_locked(c, key, v); |
3144 | | |
3145 | 7.92k | container_mem_unlock(c); |
3146 | 7.92k | return b; |
3147 | 7.92k | } |
3148 | | |
3149 | 7.92k | WRAP_API_2(bool, lxcapi_set_config_item, const char *, const char *) |
3150 | | |
3151 | | static char *lxcapi_config_file_name(struct lxc_container *c) |
3152 | 0 | { |
3153 | 0 | if (!c || !c->configfile) |
3154 | 0 | return NULL; |
3155 | | |
3156 | 0 | return strdup(c->configfile); |
3157 | 0 | } |
3158 | | |
3159 | | static const char *lxcapi_get_config_path(struct lxc_container *c) |
3160 | 0 | { |
3161 | 0 | if (!c || !c->config_path) |
3162 | 0 | return NULL; |
3163 | | |
3164 | 0 | return (const char *)(c->config_path); |
3165 | 0 | } |
3166 | | |
3167 | | /* |
3168 | | * not for export |
3169 | | * Just recalculate the c->configfile based on the |
3170 | | * c->config_path, which must be set. |
3171 | | * The lxc_container must be locked or not yet public. |
3172 | | */ |
3173 | | static bool set_config_filename(struct lxc_container *c) |
3174 | 7.99k | { |
3175 | 7.99k | char *newpath; |
3176 | 7.99k | int len, ret; |
3177 | | |
3178 | 7.99k | if (!c->config_path) |
3179 | 0 | return false; |
3180 | | |
3181 | | /* $lxc_path + "/" + c->name + "/" + "config" + '\0' */ |
3182 | 7.99k | len = strlen(c->config_path) + 1 + strlen(c->name) + 1 + strlen(LXC_CONFIG_FNAME) + 1; |
3183 | 7.99k | newpath = malloc(len); |
3184 | 7.99k | if (!newpath) |
3185 | 0 | return false; |
3186 | | |
3187 | 7.99k | ret = strnprintf(newpath, len, "%s/%s/%s", c->config_path, c->name, LXC_CONFIG_FNAME); |
3188 | 7.99k | if (ret < 0) { |
3189 | 0 | fprintf(stderr, "Error printing out config file name\n"); |
3190 | 0 | free(newpath); |
3191 | 0 | return false; |
3192 | 0 | } |
3193 | | |
3194 | 7.99k | free(c->configfile); |
3195 | 7.99k | c->configfile = newpath; |
3196 | | |
3197 | 7.99k | return true; |
3198 | 7.99k | } |
3199 | | |
3200 | | static bool do_lxcapi_set_config_path(struct lxc_container *c, const char *path) |
3201 | 0 | { |
3202 | 0 | char *p; |
3203 | 0 | bool b = false; |
3204 | 0 | char *oldpath = NULL; |
3205 | |
|
3206 | 0 | if (!c) |
3207 | 0 | return b; |
3208 | | |
3209 | 0 | if (container_mem_lock(c)) |
3210 | 0 | return b; |
3211 | | |
3212 | 0 | p = strdup(path); |
3213 | 0 | if (!p) { |
3214 | 0 | ERROR("Out of memory setting new lxc path"); |
3215 | 0 | goto err; |
3216 | 0 | } |
3217 | | |
3218 | 0 | b = true; |
3219 | 0 | if (c->config_path) |
3220 | 0 | oldpath = c->config_path; |
3221 | 0 | c->config_path = p; |
3222 | | |
3223 | | /* Since we've changed the config path, we have to change the |
3224 | | * config file name too */ |
3225 | 0 | if (!set_config_filename(c)) { |
3226 | 0 | ERROR("Out of memory setting new config filename"); |
3227 | 0 | b = false; |
3228 | 0 | free(c->config_path); |
3229 | 0 | c->config_path = oldpath; |
3230 | 0 | oldpath = NULL; |
3231 | 0 | } |
3232 | |
|
3233 | 0 | err: |
3234 | 0 | free(oldpath); |
3235 | 0 | container_mem_unlock(c); |
3236 | 0 | return b; |
3237 | 0 | } |
3238 | | |
3239 | 0 | WRAP_API_1(bool, lxcapi_set_config_path, const char *) |
3240 | | |
3241 | | static bool do_lxcapi_set_cgroup_item(struct lxc_container *c, const char *subsys, const char *value) |
3242 | 0 | { |
3243 | 0 | call_cleaner(cgroup_exit) struct cgroup_ops *cgroup_ops = NULL; |
3244 | 0 | int ret; |
3245 | |
|
3246 | 0 | if (!c) |
3247 | 0 | return false; |
3248 | | |
3249 | 0 | if (is_stopped(c)) |
3250 | 0 | return false; |
3251 | | |
3252 | 0 | ret = cgroup_set(c->name, c->config_path, subsys, value); |
3253 | 0 | if (ret < 0 && ERRNO_IS_NOT_SUPPORTED(ret)) { |
3254 | 0 | cgroup_ops = cgroup_init(c->lxc_conf); |
3255 | 0 | if (!cgroup_ops) |
3256 | 0 | return false; |
3257 | | |
3258 | 0 | ret = cgroup_ops->set(cgroup_ops, subsys, value, c->name, c->config_path); |
3259 | 0 | } |
3260 | | |
3261 | 0 | return ret == 0; |
3262 | 0 | } |
3263 | | |
3264 | 0 | WRAP_API_2(bool, lxcapi_set_cgroup_item, const char *, const char *) |
3265 | | |
3266 | | static int do_lxcapi_get_cgroup_item(struct lxc_container *c, const char *subsys, char *retv, int inlen) |
3267 | 0 | { |
3268 | 0 | call_cleaner(cgroup_exit) struct cgroup_ops *cgroup_ops = NULL; |
3269 | 0 | int ret; |
3270 | |
|
3271 | 0 | if (!c) |
3272 | 0 | return -1; |
3273 | | |
3274 | 0 | if (is_stopped(c)) |
3275 | 0 | return -1; |
3276 | | |
3277 | 0 | ret = cgroup_get(c->name, c->config_path, subsys, retv, inlen); |
3278 | 0 | if (ret < 0 && ERRNO_IS_NOT_SUPPORTED(ret)) { |
3279 | 0 | cgroup_ops = cgroup_init(c->lxc_conf); |
3280 | 0 | if (!cgroup_ops) |
3281 | 0 | return -1; |
3282 | | |
3283 | 0 | return cgroup_ops->get(cgroup_ops, subsys, retv, inlen, c->name, c->config_path); |
3284 | 0 | } |
3285 | | |
3286 | 0 | return ret; |
3287 | 0 | } |
3288 | | |
3289 | 0 | WRAP_API_3(int, lxcapi_get_cgroup_item, const char *, char *, int) |
3290 | | |
3291 | | const char *lxc_get_global_config_item(const char *key) |
3292 | 0 | { |
3293 | 0 | return lxc_global_config_value(key); |
3294 | 0 | } |
3295 | | |
3296 | | const char *lxc_get_version(void) |
3297 | 0 | { |
3298 | 0 | return LXC_VERSION; |
3299 | 0 | } |
3300 | | |
3301 | | static int copy_file(const char *old, const char *new) |
3302 | 0 | { |
3303 | 0 | __do_close int fd_from = -EBADF, fd_to = -EBADF; |
3304 | 0 | ssize_t len, ret; |
3305 | 0 | char buf[8096]; |
3306 | 0 | struct stat sbuf; |
3307 | |
|
3308 | 0 | if (file_exists(new)) { |
3309 | 0 | ERROR("copy destination %s exists", new); |
3310 | 0 | return -1; |
3311 | 0 | } |
3312 | | |
3313 | 0 | fd_from = open(old, PROTECT_OPEN); |
3314 | 0 | if (fd_from < 0) |
3315 | 0 | return syserror("Error opening original file %s", old); |
3316 | | |
3317 | 0 | ret = fstat(fd_from, &sbuf); |
3318 | 0 | if (ret < 0) |
3319 | 0 | return sysinfo("Error stat'ing %s", old); |
3320 | | |
3321 | 0 | fd_to = open(new, PROTECT_OPEN_W | O_CREAT | O_EXCL, 0644); |
3322 | 0 | if (fd_to < 0) |
3323 | 0 | return syserror("Error opening new file %s", new); |
3324 | | |
3325 | 0 | for (;;) { |
3326 | 0 | len = lxc_read_nointr(fd_from, buf, 8096); |
3327 | 0 | if (len < 0) |
3328 | 0 | return syserror("Error reading old file %s", old); |
3329 | | |
3330 | 0 | if (len == 0) |
3331 | 0 | break; |
3332 | | |
3333 | 0 | ret = lxc_write_nointr(fd_to, buf, len); |
3334 | 0 | if (ret < len) |
3335 | 0 | return syserror("Error: write to new file %s was interrupted", new); |
3336 | 0 | } |
3337 | | |
3338 | | |
3339 | | /* We set mode, but not owner/group. */ |
3340 | 0 | ret = fchmod(fd_to, sbuf.st_mode); |
3341 | 0 | if (ret < 0) |
3342 | 0 | return syserror("Error setting mode on %s", new); |
3343 | | |
3344 | 0 | return 0; |
3345 | 0 | } |
3346 | | |
3347 | | static int copyhooks(struct lxc_container *oldc, struct lxc_container *c) |
3348 | 0 | { |
3349 | 0 | __do_free char *cpath = NULL; |
3350 | 0 | int i, len, ret; |
3351 | 0 | struct string_entry *entry; |
3352 | |
|
3353 | 0 | len = strlen(oldc->config_path) + strlen(oldc->name) + 3; |
3354 | 0 | cpath = malloc(len); |
3355 | 0 | if (!cpath) |
3356 | 0 | return ret_errno(ENOMEM); |
3357 | | |
3358 | 0 | ret = strnprintf(cpath, len, "%s/%s/", oldc->config_path, oldc->name); |
3359 | 0 | if (ret < 0) |
3360 | 0 | return -1; |
3361 | | |
3362 | 0 | for (i = 0; i < NUM_LXC_HOOKS; i++) { |
3363 | 0 | list_for_each_entry(entry, &c->lxc_conf->hooks[i], head) { |
3364 | 0 | __do_free char *hookname = NULL; |
3365 | 0 | char *fname, *new_hook; |
3366 | 0 | char tmppath[PATH_MAX]; |
3367 | |
|
3368 | 0 | fname = strrchr(entry->val, '/'); |
3369 | 0 | if (!fname) |
3370 | 0 | return 0; |
3371 | | |
3372 | | /* If this hook is public - ignore. */ |
3373 | 0 | if (!strnequal(entry->val, cpath, len - 1)) |
3374 | 0 | continue; |
3375 | | |
3376 | | /* copy the script, and change the entry in confile */ |
3377 | 0 | ret = strnprintf(tmppath, sizeof(tmppath), "%s/%s/%s", |
3378 | 0 | c->config_path, c->name, fname+1); |
3379 | 0 | if (ret < 0) |
3380 | 0 | return -1; |
3381 | | |
3382 | 0 | ret = copy_file(entry->val, tmppath); |
3383 | 0 | if (ret < 0) |
3384 | 0 | return -1; |
3385 | | |
3386 | 0 | new_hook = strdup(tmppath); |
3387 | 0 | if (!new_hook) |
3388 | 0 | return syserror("out of memory copying hook path"); |
3389 | | |
3390 | 0 | hookname = move_ptr(entry->val); |
3391 | 0 | entry->val = move_ptr(new_hook); |
3392 | 0 | } |
3393 | 0 | } |
3394 | | |
3395 | 0 | if (!clone_update_unexp_hooks(c->lxc_conf, oldc->config_path, |
3396 | 0 | c->config_path, oldc->name, c->name)) { |
3397 | 0 | return syserror_ret(-1, "Error saving new hooks in clone"); |
3398 | 0 | } |
3399 | | |
3400 | 0 | do_lxcapi_save_config(c, NULL); |
3401 | 0 | return 0; |
3402 | 0 | } |
3403 | | |
3404 | | static int copy_fstab(struct lxc_container *oldc, struct lxc_container *c) |
3405 | 0 | { |
3406 | 0 | char newpath[PATH_MAX]; |
3407 | 0 | char *oldpath = oldc->lxc_conf->fstab; |
3408 | 0 | int ret; |
3409 | |
|
3410 | 0 | if (!oldpath) |
3411 | 0 | return 0; |
3412 | | |
3413 | 0 | clear_unexp_config_line(c->lxc_conf, "lxc.mount.fstab", false); |
3414 | |
|
3415 | 0 | char *p = strrchr(oldpath, '/'); |
3416 | 0 | if (!p) |
3417 | 0 | return -1; |
3418 | | |
3419 | 0 | ret = strnprintf(newpath, sizeof(newpath), "%s/%s%s", |
3420 | 0 | c->config_path, c->name, p); |
3421 | 0 | if (ret < 0) { |
3422 | 0 | ERROR("error printing new path for %s", oldpath); |
3423 | 0 | return -1; |
3424 | 0 | } |
3425 | | |
3426 | 0 | if (file_exists(newpath)) { |
3427 | 0 | ERROR("error: fstab file %s exists", newpath); |
3428 | 0 | return -1; |
3429 | 0 | } |
3430 | | |
3431 | 0 | if (copy_file(oldpath, newpath) < 0) { |
3432 | 0 | ERROR("error: copying %s to %s", oldpath, newpath); |
3433 | 0 | return -1; |
3434 | 0 | } |
3435 | | |
3436 | 0 | free(c->lxc_conf->fstab); |
3437 | |
|
3438 | 0 | c->lxc_conf->fstab = strdup(newpath); |
3439 | 0 | if (!c->lxc_conf->fstab) { |
3440 | 0 | ERROR("error: allocating pathname"); |
3441 | 0 | return -1; |
3442 | 0 | } |
3443 | | |
3444 | 0 | if (!do_append_unexp_config_line(c->lxc_conf, "lxc.mount.fstab", newpath)) { |
3445 | 0 | ERROR("error saving new lxctab"); |
3446 | 0 | return -1; |
3447 | 0 | } |
3448 | | |
3449 | 0 | return 0; |
3450 | 0 | } |
3451 | | |
3452 | | static void copy_rdepends(struct lxc_container *c, struct lxc_container *c0) |
3453 | 0 | { |
3454 | 0 | char path0[PATH_MAX], path1[PATH_MAX]; |
3455 | 0 | int ret; |
3456 | |
|
3457 | 0 | ret = strnprintf(path0, sizeof(path0), "%s/%s/lxc_rdepends", c0->config_path, |
3458 | 0 | c0->name); |
3459 | 0 | if (ret < 0) { |
3460 | 0 | WARN("Error copying reverse dependencies"); |
3461 | 0 | return; |
3462 | 0 | } |
3463 | | |
3464 | 0 | ret = strnprintf(path1, sizeof(path1), "%s/%s/lxc_rdepends", c->config_path, |
3465 | 0 | c->name); |
3466 | 0 | if (ret < 0) { |
3467 | 0 | WARN("Error copying reverse dependencies"); |
3468 | 0 | return; |
3469 | 0 | } |
3470 | | |
3471 | 0 | if (!file_exists(path0)) { |
3472 | 0 | return; |
3473 | 0 | } |
3474 | | |
3475 | 0 | if (copy_file(path0, path1) < 0) { |
3476 | 0 | INFO("Error copying reverse dependencies"); |
3477 | 0 | return; |
3478 | 0 | } |
3479 | 0 | } |
3480 | | |
3481 | | static bool add_rdepends(struct lxc_container *c, struct lxc_container *c0) |
3482 | 0 | { |
3483 | 0 | __do_fclose FILE *f = NULL; |
3484 | 0 | int ret; |
3485 | 0 | char path[PATH_MAX]; |
3486 | |
|
3487 | 0 | ret = strnprintf(path, sizeof(path), "%s/%s/lxc_rdepends", c->config_path, c->name); |
3488 | 0 | if (ret < 0) |
3489 | 0 | return false; |
3490 | | |
3491 | 0 | f = fopen(path, "ae"); |
3492 | 0 | if (!f) |
3493 | 0 | return false; |
3494 | | |
3495 | | /* If anything goes wrong, just return an error. */ |
3496 | 0 | return fprintf(f, "%s\n%s\n", c0->config_path, c0->name) > 0; |
3497 | 0 | } |
3498 | | |
3499 | | /* |
3500 | | * If the fs natively supports snapshot clones with no penalty, |
3501 | | * then default to those even if not requested. |
3502 | | * Currently we only do this for btrfs. |
3503 | | */ |
3504 | | static bool should_default_to_snapshot(struct lxc_container *c0, |
3505 | | struct lxc_container *c1) |
3506 | 0 | { |
3507 | 0 | __do_free char *p0 = NULL, *p1 = NULL; |
3508 | 0 | int ret; |
3509 | 0 | size_t l0 = strlen(c0->config_path) + strlen(c0->name) + 2; |
3510 | 0 | size_t l1 = strlen(c1->config_path) + strlen(c1->name) + 2; |
3511 | 0 | char *rootfs = c0->lxc_conf->rootfs.path; |
3512 | |
|
3513 | 0 | p0 = must_realloc(NULL, l0 + 1); |
3514 | 0 | p1 = must_realloc(NULL, l1 + 1); |
3515 | 0 | ret = strnprintf(p0, l0, "%s/%s", c0->config_path, c0->name); |
3516 | 0 | if (ret < 0) |
3517 | 0 | return false; |
3518 | | |
3519 | 0 | ret = strnprintf(p1, l1, "%s/%s", c1->config_path, c1->name); |
3520 | 0 | if (ret < 0) |
3521 | 0 | return false; |
3522 | | |
3523 | 0 | if (!is_btrfs_fs(p0) || !is_btrfs_fs(p1)) |
3524 | 0 | return false; |
3525 | | |
3526 | 0 | if (is_btrfs_subvol(rootfs) <= 0) |
3527 | 0 | return false; |
3528 | | |
3529 | 0 | return btrfs_same_fs(p0, p1) == 0; |
3530 | 0 | } |
3531 | | |
3532 | | static int copy_storage(struct lxc_container *c0, struct lxc_container *c, |
3533 | | const char *newtype, int flags, const char *bdevdata, |
3534 | | uint64_t newsize) |
3535 | 0 | { |
3536 | 0 | struct lxc_storage *bdev; |
3537 | 0 | bool need_rdep; |
3538 | |
|
3539 | 0 | if (should_default_to_snapshot(c0, c)) |
3540 | 0 | flags |= LXC_CLONE_SNAPSHOT; |
3541 | |
|
3542 | 0 | bdev = storage_copy(c0, c->name, c->config_path, newtype, flags, |
3543 | 0 | bdevdata, newsize, &need_rdep); |
3544 | 0 | if (!bdev) { |
3545 | 0 | ERROR("Error copying storage."); |
3546 | 0 | return -1; |
3547 | 0 | } |
3548 | | |
3549 | | /* Set new rootfs. */ |
3550 | 0 | free(c->lxc_conf->rootfs.path); |
3551 | 0 | c->lxc_conf->rootfs.path = strdup(bdev->src); |
3552 | 0 | storage_put(bdev); |
3553 | |
|
3554 | 0 | if (!c->lxc_conf->rootfs.path) { |
3555 | 0 | ERROR("Out of memory while setting storage path."); |
3556 | 0 | return -1; |
3557 | 0 | } |
3558 | | |
3559 | | /* Append a new lxc.rootfs.path entry to the unexpanded config. */ |
3560 | 0 | clear_unexp_config_line(c->lxc_conf, "lxc.rootfs.path", false); |
3561 | 0 | if (!do_append_unexp_config_line(c->lxc_conf, "lxc.rootfs.path", |
3562 | 0 | c->lxc_conf->rootfs.path)) { |
3563 | 0 | ERROR("Error saving new rootfs to cloned config."); |
3564 | 0 | return -1; |
3565 | 0 | } |
3566 | | |
3567 | 0 | if (flags & LXC_CLONE_SNAPSHOT) |
3568 | 0 | copy_rdepends(c, c0); |
3569 | |
|
3570 | 0 | if (need_rdep) { |
3571 | 0 | if (!add_rdepends(c, c0)) |
3572 | 0 | WARN("Error adding reverse dependency from %s to %s", |
3573 | 0 | c->name, c0->name); |
3574 | 0 | } |
3575 | |
|
3576 | 0 | mod_all_rdeps(c, true); |
3577 | |
|
3578 | 0 | return 0; |
3579 | 0 | } |
3580 | | |
3581 | | struct clone_update_data { |
3582 | | struct lxc_container *c0; |
3583 | | struct lxc_container *c1; |
3584 | | int flags; |
3585 | | char **hookargs; |
3586 | | }; |
3587 | | |
3588 | | static int clone_update_rootfs(struct clone_update_data *data) |
3589 | 0 | { |
3590 | 0 | struct lxc_container *c0 = data->c0; |
3591 | 0 | struct lxc_container *c = data->c1; |
3592 | 0 | int flags = data->flags; |
3593 | 0 | char **hookargs = data->hookargs; |
3594 | 0 | int ret = -1; |
3595 | 0 | char path[PATH_MAX]; |
3596 | 0 | struct lxc_storage *bdev; |
3597 | 0 | FILE *fout; |
3598 | 0 | struct lxc_conf *conf = c->lxc_conf; |
3599 | | |
3600 | | /* update hostname in rootfs */ |
3601 | | /* we're going to mount, so run in a clean namespace to simplify cleanup */ |
3602 | |
|
3603 | 0 | (void)lxc_drop_groups(); |
3604 | |
|
3605 | 0 | if (setgid(0) < 0) { |
3606 | 0 | ERROR("Failed to setgid to 0"); |
3607 | 0 | return -1; |
3608 | 0 | } |
3609 | | |
3610 | 0 | if (setuid(0) < 0) { |
3611 | 0 | ERROR("Failed to setuid to 0"); |
3612 | 0 | return -1; |
3613 | 0 | } |
3614 | | |
3615 | 0 | if (unshare(CLONE_NEWNS) < 0) |
3616 | 0 | return -1; |
3617 | | |
3618 | 0 | ret = lxc_storage_prepare(conf); |
3619 | 0 | if (ret) |
3620 | 0 | return -1; |
3621 | 0 | bdev = conf->rootfs.storage; |
3622 | |
|
3623 | 0 | if (!strequal(bdev->type, "dir")) { |
3624 | 0 | if (unshare(CLONE_NEWNS) < 0) { |
3625 | 0 | ERROR("error unsharing mounts"); |
3626 | 0 | lxc_storage_put(conf); |
3627 | 0 | return -1; |
3628 | 0 | } |
3629 | | |
3630 | 0 | if (detect_shared_rootfs() && mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL)) |
3631 | 0 | SYSERROR("Failed to recursively turn root mount tree into dependent mount. Continuing..."); |
3632 | |
|
3633 | 0 | if (bdev->ops->mount(bdev) < 0) { |
3634 | 0 | lxc_storage_put(conf); |
3635 | 0 | return -1; |
3636 | 0 | } |
3637 | 0 | } else { /* TODO come up with a better way */ |
3638 | 0 | free(bdev->dest); |
3639 | 0 | bdev->dest = strdup(lxc_storage_get_path(bdev->src, bdev->type)); |
3640 | 0 | } |
3641 | | |
3642 | 0 | if (!list_empty(&conf->hooks[LXCHOOK_CLONE])) { |
3643 | | /* Start of environment variable setup for hooks */ |
3644 | 0 | if (c0->name && setenv("LXC_SRC_NAME", c0->name, 1)) |
3645 | 0 | SYSERROR("failed to set environment variable for source container name"); |
3646 | |
|
3647 | 0 | if (setenv("LXC_NAME", c->name, 1)) |
3648 | 0 | SYSERROR("failed to set environment variable for container name"); |
3649 | |
|
3650 | 0 | if (conf->rcfile && setenv("LXC_CONFIG_FILE", conf->rcfile, 1)) |
3651 | 0 | SYSERROR("failed to set environment variable for config path"); |
3652 | |
|
3653 | 0 | if (bdev->dest && setenv("LXC_ROOTFS_MOUNT", bdev->dest, 1)) |
3654 | 0 | SYSERROR("failed to set environment variable for rootfs mount"); |
3655 | |
|
3656 | 0 | if (conf->rootfs.path && setenv("LXC_ROOTFS_PATH", conf->rootfs.path, 1)) |
3657 | 0 | SYSERROR("failed to set environment variable for rootfs mount"); |
3658 | |
|
3659 | 0 | if (run_lxc_hooks(c->name, "clone", conf, hookargs)) { |
3660 | 0 | ERROR("Error executing clone hook for %s", c->name); |
3661 | 0 | lxc_storage_put(conf); |
3662 | 0 | return -1; |
3663 | 0 | } |
3664 | 0 | } |
3665 | | |
3666 | 0 | if (!(flags & LXC_CLONE_KEEPNAME)) { |
3667 | 0 | ret = strnprintf(path, sizeof(path), "%s/etc/hostname", bdev->dest); |
3668 | 0 | lxc_storage_put(conf); |
3669 | |
|
3670 | 0 | if (ret < 0) |
3671 | 0 | return -1; |
3672 | | |
3673 | 0 | if (!file_exists(path)) |
3674 | 0 | return 0; |
3675 | | |
3676 | 0 | if (!(fout = fopen(path, "we"))) { |
3677 | 0 | SYSERROR("unable to open %s: ignoring", path); |
3678 | 0 | return 0; |
3679 | 0 | } |
3680 | | |
3681 | 0 | if (fprintf(fout, "%s", c->name) < 0) { |
3682 | 0 | fclose(fout); |
3683 | 0 | return -1; |
3684 | 0 | } |
3685 | | |
3686 | 0 | if (fclose(fout) < 0) |
3687 | 0 | return -1; |
3688 | 0 | } else { |
3689 | 0 | lxc_storage_put(conf); |
3690 | 0 | } |
3691 | | |
3692 | 0 | return 0; |
3693 | 0 | } |
3694 | | |
3695 | | static int clone_update_rootfs_wrapper(void *data) |
3696 | 0 | { |
3697 | 0 | struct clone_update_data *arg = (struct clone_update_data *) data; |
3698 | 0 | return clone_update_rootfs(arg); |
3699 | 0 | } |
3700 | | |
3701 | | /* |
3702 | | * We want to support: |
3703 | | sudo lxc-clone -o o1 -n n1 -s -L|-fssize fssize -v|--vgname vgname \ |
3704 | | -p|--lvprefix lvprefix -t|--fstype fstype -B backingstore |
3705 | | |
3706 | | -s [ implies overlay] |
3707 | | -s -B overlay |
3708 | | |
3709 | | only rootfs gets converted (copied/snapshotted) on clone. |
3710 | | */ |
3711 | | |
3712 | | static int create_file_dirname(char *path, struct lxc_conf *conf) |
3713 | 0 | { |
3714 | 0 | __do_close int fd_rootfs = -EBADF; |
3715 | 0 | char *p; |
3716 | |
|
3717 | 0 | p = strrchr(path, '/'); |
3718 | 0 | if (!p) |
3719 | 0 | return -1; |
3720 | | |
3721 | 0 | *p = '\0'; |
3722 | 0 | fd_rootfs = do_create_container_dir(path, conf); |
3723 | 0 | *p = '/'; |
3724 | |
|
3725 | 0 | return fd_rootfs >= 0; |
3726 | 0 | } |
3727 | | |
3728 | | static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char *newname, |
3729 | | const char *lxcpath, int flags, |
3730 | | const char *bdevtype, const char *bdevdata, uint64_t newsize, |
3731 | | char **hookargs) |
3732 | 0 | { |
3733 | 0 | char newpath[PATH_MAX]; |
3734 | 0 | int fd, ret; |
3735 | 0 | struct clone_update_data data; |
3736 | 0 | size_t saved_unexp_len; |
3737 | 0 | pid_t pid; |
3738 | 0 | int storage_copied = 0; |
3739 | 0 | char *origroot = NULL, *saved_unexp_conf = NULL; |
3740 | 0 | struct lxc_container *c2 = NULL; |
3741 | |
|
3742 | 0 | if (!c || !do_lxcapi_is_defined(c)) |
3743 | 0 | return NULL; |
3744 | | |
3745 | 0 | if (container_mem_lock(c)) |
3746 | 0 | return NULL; |
3747 | 0 | if (!is_stopped(c) && !(flags & LXC_CLONE_ALLOW_RUNNING)) { |
3748 | 0 | ERROR("error: Original container (%s) is running. Use --allowrunning if you want to force a snapshot of the running container.", c->name); |
3749 | 0 | goto out; |
3750 | 0 | } |
3751 | | |
3752 | | /* Make sure the container doesn't yet exist. */ |
3753 | 0 | if (!newname) |
3754 | 0 | newname = c->name; |
3755 | |
|
3756 | 0 | if (!lxcpath) |
3757 | 0 | lxcpath = do_lxcapi_get_config_path(c); |
3758 | |
|
3759 | 0 | ret = strnprintf(newpath, sizeof(newpath), "%s/%s/%s", lxcpath, newname, LXC_CONFIG_FNAME); |
3760 | 0 | if (ret < 0) { |
3761 | 0 | SYSERROR("clone: failed making config pathname"); |
3762 | 0 | goto out; |
3763 | 0 | } |
3764 | | |
3765 | 0 | if (file_exists(newpath)) { |
3766 | 0 | ERROR("error: clone: %s exists", newpath); |
3767 | 0 | goto out; |
3768 | 0 | } |
3769 | | |
3770 | 0 | ret = create_file_dirname(newpath, c->lxc_conf); |
3771 | 0 | if (ret < 0 && errno != EEXIST) { |
3772 | 0 | ERROR("Error creating container dir for %s", newpath); |
3773 | 0 | goto out; |
3774 | 0 | } |
3775 | | |
3776 | | /* Copy the configuration. Tweak it as needed. */ |
3777 | 0 | if (c->lxc_conf->rootfs.path) { |
3778 | 0 | origroot = c->lxc_conf->rootfs.path; |
3779 | 0 | c->lxc_conf->rootfs.path = NULL; |
3780 | 0 | } |
3781 | |
|
3782 | 0 | fd = open(newpath, O_WRONLY | O_CREAT | O_CLOEXEC, |
3783 | 0 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); |
3784 | 0 | if (fd < 0) { |
3785 | 0 | SYSERROR("Failed to open \"%s\"", newpath); |
3786 | 0 | goto out; |
3787 | 0 | } |
3788 | | |
3789 | 0 | saved_unexp_conf = c->lxc_conf->unexpanded_config; |
3790 | 0 | saved_unexp_len = c->lxc_conf->unexpanded_len; |
3791 | 0 | c->lxc_conf->unexpanded_config = strdup(saved_unexp_conf); |
3792 | 0 | if (!c->lxc_conf->unexpanded_config) { |
3793 | 0 | close(fd); |
3794 | 0 | goto out; |
3795 | 0 | } |
3796 | | |
3797 | 0 | clear_unexp_config_line(c->lxc_conf, "lxc.rootfs.path", false); |
3798 | 0 | write_config(fd, c->lxc_conf); |
3799 | 0 | close(fd); |
3800 | |
|
3801 | 0 | c->lxc_conf->rootfs.path = origroot; |
3802 | |
|
3803 | 0 | free(c->lxc_conf->unexpanded_config); |
3804 | 0 | c->lxc_conf->unexpanded_config = saved_unexp_conf; |
3805 | 0 | saved_unexp_conf = NULL; |
3806 | 0 | c->lxc_conf->unexpanded_len = saved_unexp_len; |
3807 | |
|
3808 | 0 | ret = strnprintf(newpath, sizeof(newpath), "%s/%s/%s", lxcpath, newname, LXC_ROOTFS_DNAME); |
3809 | 0 | if (ret < 0) { |
3810 | 0 | SYSERROR("clone: failed making rootfs pathname"); |
3811 | 0 | goto out; |
3812 | 0 | } |
3813 | | |
3814 | 0 | ret = mkdir(newpath, 0755); |
3815 | 0 | if (ret < 0) { |
3816 | | /* For an overlay container the rootfs is considered immutable |
3817 | | * and will not have been removed when restoring from a |
3818 | | * snapshot. |
3819 | | */ |
3820 | 0 | if (errno != ENOENT && |
3821 | 0 | !(flags & LXC_STORAGE_INTERNAL_OVERLAY_RESTORE)) { |
3822 | 0 | SYSERROR("Failed to create directory \"%s\"", newpath); |
3823 | 0 | goto out; |
3824 | 0 | } |
3825 | 0 | } |
3826 | | |
3827 | 0 | if (am_guest_unpriv()) { |
3828 | 0 | if (chown_mapped_root(newpath, c->lxc_conf) < 0) { |
3829 | 0 | ERROR("Error chowning %s to container root", newpath); |
3830 | 0 | goto out; |
3831 | 0 | } |
3832 | 0 | } |
3833 | | |
3834 | 0 | c2 = lxc_container_new(newname, lxcpath); |
3835 | 0 | if (!c2) { |
3836 | 0 | ERROR("clone: failed to create new container (%s %s)", newname, |
3837 | 0 | lxcpath); |
3838 | 0 | goto out; |
3839 | 0 | } |
3840 | | |
3841 | | /* copy/snapshot rootfs's */ |
3842 | 0 | ret = copy_storage(c, c2, bdevtype, flags, bdevdata, newsize); |
3843 | 0 | if (ret < 0) |
3844 | 0 | goto out; |
3845 | | |
3846 | | /* update utsname */ |
3847 | 0 | if (!(flags & LXC_CLONE_KEEPNAME)) { |
3848 | 0 | clear_unexp_config_line(c2->lxc_conf, "lxc.utsname", false); |
3849 | 0 | clear_unexp_config_line(c2->lxc_conf, "lxc.uts.name", false); |
3850 | |
|
3851 | 0 | if (!do_set_config_item_locked(c2, "lxc.uts.name", newname)) { |
3852 | 0 | ERROR("Error setting new hostname"); |
3853 | 0 | goto out; |
3854 | 0 | } |
3855 | 0 | } |
3856 | | |
3857 | | /* copy hooks */ |
3858 | 0 | ret = copyhooks(c, c2); |
3859 | 0 | if (ret < 0) { |
3860 | 0 | ERROR("error copying hooks"); |
3861 | 0 | goto out; |
3862 | 0 | } |
3863 | | |
3864 | 0 | if (copy_fstab(c, c2) < 0) { |
3865 | 0 | ERROR("error copying fstab"); |
3866 | 0 | goto out; |
3867 | 0 | } |
3868 | | |
3869 | | /* update macaddrs */ |
3870 | 0 | if (!(flags & LXC_CLONE_KEEPMACADDR)) { |
3871 | 0 | if (!network_new_hwaddrs(c2->lxc_conf)) { |
3872 | 0 | ERROR("Error updating mac addresses"); |
3873 | 0 | goto out; |
3874 | 0 | } |
3875 | 0 | } |
3876 | | |
3877 | | /* Update absolute paths for overlay mount directories. */ |
3878 | 0 | if (ovl_update_abs_paths(c2->lxc_conf, c->config_path, c->name, lxcpath, newname) < 0) |
3879 | 0 | goto out; |
3880 | | |
3881 | | /* We've now successfully created c2's storage, so clear it out if we |
3882 | | * fail after this. |
3883 | | */ |
3884 | 0 | storage_copied = 1; |
3885 | |
|
3886 | 0 | if (!c2->save_config(c2, NULL)) |
3887 | 0 | goto out; |
3888 | | |
3889 | 0 | if ((pid = fork()) < 0) { |
3890 | 0 | SYSERROR("fork"); |
3891 | 0 | goto out; |
3892 | 0 | } |
3893 | | |
3894 | 0 | if (pid > 0) { |
3895 | 0 | ret = wait_for_pid(pid); |
3896 | 0 | if (ret) |
3897 | 0 | goto out; |
3898 | | |
3899 | 0 | container_mem_unlock(c); |
3900 | 0 | return c2; |
3901 | 0 | } |
3902 | | |
3903 | 0 | data.c0 = c; |
3904 | 0 | data.c1 = c2; |
3905 | 0 | data.flags = flags; |
3906 | 0 | data.hookargs = hookargs; |
3907 | |
|
3908 | 0 | if (am_guest_unpriv()) |
3909 | 0 | ret = userns_exec_full(c->lxc_conf, clone_update_rootfs_wrapper, |
3910 | 0 | &data, "clone_update_rootfs_wrapper"); |
3911 | 0 | else |
3912 | 0 | ret = clone_update_rootfs(&data); |
3913 | 0 | if (ret < 0) |
3914 | 0 | _exit(EXIT_FAILURE); |
3915 | | |
3916 | 0 | container_mem_unlock(c); |
3917 | 0 | _exit(EXIT_SUCCESS); |
3918 | | |
3919 | 0 | out: |
3920 | 0 | container_mem_unlock(c); |
3921 | 0 | if (c2) { |
3922 | 0 | if (!storage_copied) |
3923 | 0 | c2->lxc_conf->rootfs.path = NULL; |
3924 | |
|
3925 | 0 | c2->destroy(c2); |
3926 | 0 | lxc_container_put(c2); |
3927 | 0 | } |
3928 | |
|
3929 | 0 | return NULL; |
3930 | 0 | } |
3931 | | |
3932 | | static struct lxc_container *lxcapi_clone(struct lxc_container *c, const char *newname, |
3933 | | const char *lxcpath, int flags, |
3934 | | const char *bdevtype, const char *bdevdata, uint64_t newsize, |
3935 | | char **hookargs) |
3936 | 0 | { |
3937 | 0 | struct lxc_container * ret; |
3938 | |
|
3939 | 0 | current_config = c ? c->lxc_conf : NULL; |
3940 | 0 | ret = do_lxcapi_clone(c, newname, lxcpath, flags, bdevtype, bdevdata, newsize, hookargs); |
3941 | 0 | current_config = NULL; |
3942 | |
|
3943 | 0 | return ret; |
3944 | 0 | } |
3945 | | |
3946 | | static bool do_lxcapi_rename(struct lxc_container *c, const char *newname) |
3947 | 0 | { |
3948 | 0 | struct lxc_storage *bdev; |
3949 | 0 | struct lxc_container *newc; |
3950 | |
|
3951 | 0 | if (!c || !c->name || !c->config_path || !c->lxc_conf) |
3952 | 0 | return false; |
3953 | | |
3954 | 0 | if (has_fs_snapshots(c) || has_snapshots(c)) { |
3955 | 0 | ERROR("Renaming a container with snapshots is not supported"); |
3956 | 0 | return false; |
3957 | 0 | } |
3958 | | |
3959 | 0 | if (lxc_storage_prepare(c->lxc_conf)) { |
3960 | 0 | ERROR("Failed to find original backing store type"); |
3961 | 0 | return false; |
3962 | 0 | } |
3963 | 0 | bdev = c->lxc_conf->rootfs.storage; |
3964 | |
|
3965 | 0 | newc = lxcapi_clone(c, newname, c->config_path, LXC_CLONE_KEEPMACADDR, NULL, bdev->type, 0, NULL); |
3966 | 0 | lxc_storage_put(c->lxc_conf); |
3967 | 0 | if (!newc) { |
3968 | 0 | lxc_container_put(newc); |
3969 | 0 | return false; |
3970 | 0 | } |
3971 | | |
3972 | 0 | if (newc && lxcapi_is_defined(newc)) |
3973 | 0 | lxc_container_put(newc); |
3974 | |
|
3975 | 0 | if (!container_destroy(c, NULL)) { |
3976 | 0 | ERROR("Could not destroy existing container %s", c->name); |
3977 | 0 | return false; |
3978 | 0 | } |
3979 | | |
3980 | 0 | return true; |
3981 | 0 | } |
3982 | | |
3983 | 0 | WRAP_API_1(bool, lxcapi_rename, const char *) |
3984 | | |
3985 | | static int lxcapi_attach(struct lxc_container *c, |
3986 | | lxc_attach_exec_t exec_function, void *exec_payload, |
3987 | | lxc_attach_options_t *options, pid_t *attached_process) |
3988 | 0 | { |
3989 | 0 | int ret; |
3990 | |
|
3991 | 0 | if (!c) |
3992 | 0 | return -1; |
3993 | | |
3994 | 0 | current_config = c->lxc_conf; |
3995 | |
|
3996 | 0 | ret = lxc_attach(c, exec_function, exec_payload, options, |
3997 | 0 | attached_process); |
3998 | 0 | current_config = NULL; |
3999 | 0 | return ret; |
4000 | 0 | } |
4001 | | |
4002 | | static int do_lxcapi_attach_run_wait(struct lxc_container *c, |
4003 | | lxc_attach_options_t *options, |
4004 | | const char *program, |
4005 | | const char *const argv[]) |
4006 | 0 | { |
4007 | 0 | lxc_attach_command_t command; |
4008 | 0 | pid_t pid; |
4009 | 0 | int ret; |
4010 | |
|
4011 | 0 | if (!c) |
4012 | 0 | return -1; |
4013 | | |
4014 | 0 | command.program = (char *)program; |
4015 | 0 | command.argv = (char **)argv; |
4016 | |
|
4017 | 0 | ret = lxc_attach(c, lxc_attach_run_command, &command, options, &pid); |
4018 | 0 | if (ret < 0) |
4019 | 0 | return ret; |
4020 | | |
4021 | 0 | return lxc_wait_for_pid_status(pid); |
4022 | 0 | } |
4023 | | |
4024 | | static int lxcapi_attach_run_wait(struct lxc_container *c, |
4025 | | lxc_attach_options_t *options, |
4026 | | const char *program, const char *const argv[]) |
4027 | 0 | { |
4028 | 0 | int ret; |
4029 | |
|
4030 | 0 | current_config = c ? c->lxc_conf : NULL; |
4031 | 0 | ret = do_lxcapi_attach_run_wait(c, options, program, argv); |
4032 | 0 | current_config = NULL; |
4033 | |
|
4034 | 0 | return ret; |
4035 | 0 | } |
4036 | | |
4037 | | static int get_next_index(const char *lxcpath, char *cname) |
4038 | 0 | { |
4039 | 0 | __do_free char *fname = NULL; |
4040 | 0 | struct stat sb; |
4041 | 0 | int i = 0, ret; |
4042 | |
|
4043 | 0 | fname = must_realloc(NULL, strlen(lxcpath) + 20); |
4044 | |
|
4045 | 0 | for (;;) { |
4046 | 0 | sprintf(fname, "%s/snap%d", lxcpath, i); |
4047 | |
|
4048 | 0 | ret = stat(fname, &sb); |
4049 | 0 | if (ret != 0) |
4050 | 0 | return i; |
4051 | | |
4052 | 0 | i++; |
4053 | 0 | } |
4054 | 0 | } |
4055 | | |
4056 | | static bool get_snappath_dir(struct lxc_container *c, char *snappath) |
4057 | 0 | { |
4058 | 0 | int ret; |
4059 | | |
4060 | | /* |
4061 | | * If the old style snapshot path exists, use it |
4062 | | * /var/lib/lxc -> /var/lib/lxcsnaps |
4063 | | */ |
4064 | 0 | ret = strnprintf(snappath, PATH_MAX, "%ssnaps", c->config_path); |
4065 | 0 | if (ret < 0) |
4066 | 0 | return false; |
4067 | | |
4068 | 0 | if (dir_exists(snappath)) { |
4069 | 0 | ret = strnprintf(snappath, PATH_MAX, "%ssnaps/%s", c->config_path, c->name); |
4070 | 0 | if (ret < 0) |
4071 | 0 | return false; |
4072 | | |
4073 | 0 | return true; |
4074 | 0 | } |
4075 | | |
4076 | | /* |
4077 | | * Use the new style path |
4078 | | * /var/lib/lxc -> /var/lib/lxc + c->name + /snaps + \0 |
4079 | | */ |
4080 | 0 | ret = strnprintf(snappath, PATH_MAX, "%s/%s/snaps", c->config_path, c->name); |
4081 | 0 | if (ret < 0) |
4082 | 0 | return false; |
4083 | | |
4084 | 0 | return true; |
4085 | 0 | } |
4086 | | |
4087 | | static int do_lxcapi_snapshot(struct lxc_container *c, const char *commentfile) |
4088 | 0 | { |
4089 | 0 | __do_free char *dfnam = NULL; |
4090 | 0 | int len; |
4091 | 0 | int i, flags, ret; |
4092 | 0 | time_t timer; |
4093 | 0 | struct tm tm_info; |
4094 | 0 | struct lxc_container *c2; |
4095 | 0 | char snappath[PATH_MAX], newname[20]; |
4096 | 0 | char buffer[25]; |
4097 | 0 | FILE *f; |
4098 | |
|
4099 | 0 | if (!c || !lxcapi_is_defined(c)) |
4100 | 0 | return -1; |
4101 | | |
4102 | 0 | if (!storage_can_backup(c->lxc_conf)) { |
4103 | 0 | ERROR("%s's backing store cannot be backed up", c->name); |
4104 | 0 | ERROR("Your container must use another backing store type"); |
4105 | 0 | return -1; |
4106 | 0 | } |
4107 | | |
4108 | 0 | if (!get_snappath_dir(c, snappath)) |
4109 | 0 | return -1; |
4110 | | |
4111 | 0 | i = get_next_index(snappath, c->name); |
4112 | |
|
4113 | 0 | if (lxc_mkdir_p(snappath, 0755) < 0) { |
4114 | 0 | ERROR("Failed to create snapshot directory %s", snappath); |
4115 | 0 | return -1; |
4116 | 0 | } |
4117 | | |
4118 | 0 | ret = strnprintf(newname, 20, "snap%d", i); |
4119 | 0 | if (ret < 0) |
4120 | 0 | return -1; |
4121 | | |
4122 | | /* |
4123 | | * We pass LXC_CLONE_SNAPSHOT to make sure that a rdepends file entry is |
4124 | | * created in the original container |
4125 | | */ |
4126 | 0 | flags = LXC_CLONE_SNAPSHOT | LXC_CLONE_KEEPMACADDR | LXC_CLONE_KEEPNAME | |
4127 | 0 | LXC_CLONE_KEEPBDEVTYPE | LXC_CLONE_MAYBE_SNAPSHOT; |
4128 | 0 | if (storage_lxc_is_dir(c->lxc_conf)) { |
4129 | 0 | ERROR("Snapshot of directory-backed container requested"); |
4130 | 0 | ERROR("Making a copy-clone. If you do want snapshots, then"); |
4131 | 0 | ERROR("please create overlay clone first, snapshot that"); |
4132 | 0 | ERROR("and keep the original container pristine"); |
4133 | 0 | flags &= ~LXC_CLONE_SNAPSHOT | LXC_CLONE_MAYBE_SNAPSHOT; |
4134 | 0 | } |
4135 | |
|
4136 | 0 | c2 = do_lxcapi_clone(c, newname, snappath, flags, NULL, NULL, 0, NULL); |
4137 | 0 | if (!c2) { |
4138 | 0 | ERROR("Failed to clone of %s:%s", c->config_path, c->name); |
4139 | 0 | return -1; |
4140 | 0 | } |
4141 | | |
4142 | 0 | lxc_container_put(c2); |
4143 | | |
4144 | | /* Now write down the creation time. */ |
4145 | 0 | time(&timer); |
4146 | |
|
4147 | 0 | if (!localtime_r(&timer, &tm_info)) { |
4148 | 0 | ERROR("Failed to get localtime"); |
4149 | 0 | return -1; |
4150 | 0 | } |
4151 | | |
4152 | 0 | strftime(buffer, 25, "%Y:%m:%d %H:%M:%S", &tm_info); |
4153 | |
|
4154 | 0 | len = strlen(snappath) + 1 + strlen(newname) + 1 + strlen(LXC_TIMESTAMP_FNAME) + 1; |
4155 | 0 | dfnam = must_realloc(NULL, len); |
4156 | 0 | ret = strnprintf(dfnam, len, "%s/%s/%s", snappath, newname, LXC_TIMESTAMP_FNAME); |
4157 | 0 | if (ret < 0) |
4158 | 0 | return -1; |
4159 | 0 | f = fopen(dfnam, "we"); |
4160 | 0 | if (!f) { |
4161 | 0 | ERROR("Failed to open %s", dfnam); |
4162 | 0 | return -1; |
4163 | 0 | } |
4164 | | |
4165 | 0 | if (fprintf(f, "%s", buffer) < 0) { |
4166 | 0 | SYSERROR("Writing timestamp"); |
4167 | 0 | fclose(f); |
4168 | 0 | return -1; |
4169 | 0 | } |
4170 | | |
4171 | 0 | ret = fclose(f); |
4172 | 0 | if (ret != 0) { |
4173 | 0 | SYSERROR("Writing timestamp"); |
4174 | 0 | return -1; |
4175 | 0 | } |
4176 | | |
4177 | 0 | if (commentfile) { |
4178 | 0 | __do_free char *path = NULL; |
4179 | | /* $p / $name / comment \0 */ |
4180 | 0 | len = strlen(snappath) + 1 + strlen(newname) + 1 + strlen(LXC_COMMENT_FNAME) + 1; |
4181 | |
|
4182 | 0 | path = must_realloc(NULL, len); |
4183 | 0 | ret = strnprintf(path, len, "%s/%s/%s", snappath, newname, LXC_COMMENT_FNAME); |
4184 | 0 | if (ret < 0) |
4185 | 0 | return -1; |
4186 | 0 | return copy_file(commentfile, path) < 0 ? -1 : i; |
4187 | 0 | } |
4188 | | |
4189 | 0 | return i; |
4190 | 0 | } |
4191 | | |
4192 | 0 | WRAP_API_1(int, lxcapi_snapshot, const char *) |
4193 | | |
4194 | | static void lxcsnap_free(struct lxc_snapshot *s) |
4195 | 0 | { |
4196 | 0 | free(s->name); |
4197 | 0 | free(s->comment_pathname); |
4198 | 0 | free(s->timestamp); |
4199 | 0 | free(s->lxcpath); |
4200 | 0 | } |
4201 | | |
4202 | | static char *get_snapcomment_path(char *snappath, char *name) |
4203 | 0 | { |
4204 | 0 | __do_free char *s = NULL; |
4205 | | /* $snappath/$name/comment */ |
4206 | 0 | int ret, len = strlen(snappath) + strlen(name) + 10; |
4207 | |
|
4208 | 0 | s = malloc(len); |
4209 | 0 | if (!s) |
4210 | 0 | return NULL; |
4211 | | |
4212 | 0 | ret = strnprintf(s, len, "%s/%s/comment", snappath, name); |
4213 | 0 | if (ret < 0) |
4214 | 0 | return NULL; |
4215 | | |
4216 | 0 | return move_ptr(s); |
4217 | 0 | } |
4218 | | |
4219 | | static char *get_timestamp(char* snappath, char *name) |
4220 | 0 | { |
4221 | 0 | __do_free char *s = NULL; |
4222 | 0 | __do_fclose FILE *fin = NULL; |
4223 | 0 | char path[PATH_MAX]; |
4224 | 0 | int ret, len; |
4225 | |
|
4226 | 0 | ret = strnprintf(path, sizeof(path), "%s/%s/ts", snappath, name); |
4227 | 0 | if (ret < 0) |
4228 | 0 | return NULL; |
4229 | | |
4230 | 0 | fin = fopen(path, "re"); |
4231 | 0 | if (!fin) |
4232 | 0 | return NULL; |
4233 | | |
4234 | 0 | (void) fseek(fin, 0, SEEK_END); |
4235 | 0 | len = ftell(fin); |
4236 | 0 | (void) fseek(fin, 0, SEEK_SET); |
4237 | 0 | if (len > 0) { |
4238 | 0 | s = malloc(len+1); |
4239 | 0 | if (s) { |
4240 | 0 | ssize_t nbytes; |
4241 | |
|
4242 | 0 | s[len] = '\0'; |
4243 | 0 | nbytes = fread(s, 1, len, fin); |
4244 | 0 | if (nbytes < 0 || nbytes != (ssize_t)len) |
4245 | 0 | return log_error_errno(NULL, errno, "reading timestamp"); |
4246 | 0 | } |
4247 | 0 | } |
4248 | | |
4249 | 0 | return move_ptr(s); |
4250 | 0 | } |
4251 | | |
4252 | | static int do_lxcapi_snapshot_list(struct lxc_container *c, struct lxc_snapshot **ret_snaps) |
4253 | 0 | { |
4254 | 0 | __do_closedir DIR *dir = NULL; |
4255 | 0 | char snappath[PATH_MAX], path2[PATH_MAX]; |
4256 | 0 | int count = 0, ret; |
4257 | 0 | struct dirent *direntp; |
4258 | 0 | struct lxc_snapshot *snaps =NULL, *nsnaps; |
4259 | |
|
4260 | 0 | if (!c || !lxcapi_is_defined(c)) |
4261 | 0 | return -1; |
4262 | | |
4263 | 0 | if (!get_snappath_dir(c, snappath)) { |
4264 | 0 | ERROR("path name too long"); |
4265 | 0 | return -1; |
4266 | 0 | } |
4267 | | |
4268 | 0 | dir = opendir(snappath); |
4269 | 0 | if (!dir) { |
4270 | 0 | INFO("Failed to open %s - assuming no snapshots", snappath); |
4271 | 0 | return 0; |
4272 | 0 | } |
4273 | | |
4274 | 0 | while ((direntp = readdir(dir))) { |
4275 | 0 | if (strequal(direntp->d_name, ".")) |
4276 | 0 | continue; |
4277 | | |
4278 | 0 | if (strequal(direntp->d_name, "..")) |
4279 | 0 | continue; |
4280 | | |
4281 | 0 | ret = strnprintf(path2, sizeof(path2), "%s/%s/%s", snappath, direntp->d_name, LXC_CONFIG_FNAME); |
4282 | 0 | if (ret < 0) { |
4283 | 0 | ERROR("pathname too long"); |
4284 | 0 | goto out_free; |
4285 | 0 | } |
4286 | | |
4287 | 0 | if (!file_exists(path2)) |
4288 | 0 | continue; |
4289 | | |
4290 | 0 | nsnaps = realloc(snaps, (count + 1)*sizeof(*snaps)); |
4291 | 0 | if (!nsnaps) { |
4292 | 0 | SYSERROR("Out of memory"); |
4293 | 0 | goto out_free; |
4294 | 0 | } |
4295 | | |
4296 | 0 | snaps = nsnaps; |
4297 | 0 | snaps[count].free = lxcsnap_free; |
4298 | 0 | snaps[count].name = strdup(direntp->d_name); |
4299 | 0 | if (!snaps[count].name) |
4300 | 0 | goto out_free; |
4301 | | |
4302 | 0 | snaps[count].lxcpath = strdup(snappath); |
4303 | 0 | if (!snaps[count].lxcpath) { |
4304 | 0 | free(snaps[count].name); |
4305 | 0 | goto out_free; |
4306 | 0 | } |
4307 | | |
4308 | 0 | snaps[count].comment_pathname = get_snapcomment_path(snappath, direntp->d_name); |
4309 | 0 | snaps[count].timestamp = get_timestamp(snappath, direntp->d_name); |
4310 | 0 | count++; |
4311 | 0 | } |
4312 | | |
4313 | 0 | *ret_snaps = snaps; |
4314 | 0 | return count; |
4315 | | |
4316 | 0 | out_free: |
4317 | 0 | if (snaps) { |
4318 | 0 | for (int i = 0; i < count; i++) |
4319 | 0 | lxcsnap_free(&snaps[i]); |
4320 | |
|
4321 | 0 | free(snaps); |
4322 | 0 | } |
4323 | |
|
4324 | 0 | return -1; |
4325 | 0 | } |
4326 | | |
4327 | 0 | WRAP_API_1(int, lxcapi_snapshot_list, struct lxc_snapshot **) |
4328 | | |
4329 | | static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snapname, const char *newname) |
4330 | 0 | { |
4331 | 0 | char clonelxcpath[PATH_MAX]; |
4332 | 0 | int flags = 0; |
4333 | 0 | struct lxc_container *snap, *rest; |
4334 | 0 | struct lxc_storage *bdev; |
4335 | 0 | bool b = false; |
4336 | |
|
4337 | 0 | if (!c || !c->name || !c->config_path) |
4338 | 0 | return false; |
4339 | | |
4340 | 0 | if (has_fs_snapshots(c)) { |
4341 | 0 | ERROR("container rootfs has dependent snapshots"); |
4342 | 0 | return false; |
4343 | 0 | } |
4344 | | |
4345 | 0 | if (lxc_storage_prepare(c->lxc_conf)) { |
4346 | 0 | ERROR("Failed to find original backing store type"); |
4347 | 0 | return false; |
4348 | 0 | } |
4349 | 0 | bdev = c->lxc_conf->rootfs.storage; |
4350 | | |
4351 | | /* For an overlay container the rootfs is considered immutable |
4352 | | * and cannot be removed when restoring from a snapshot. We pass this |
4353 | | * internal flag along to communicate this to various parts of the |
4354 | | * codebase. |
4355 | | */ |
4356 | 0 | if (strequal(bdev->type, "overlay") || strequal(bdev->type, "overlayfs")) |
4357 | 0 | bdev->flags |= LXC_STORAGE_INTERNAL_OVERLAY_RESTORE; |
4358 | |
|
4359 | 0 | if (!newname) |
4360 | 0 | newname = c->name; |
4361 | |
|
4362 | 0 | if (!get_snappath_dir(c, clonelxcpath)) { |
4363 | 0 | lxc_storage_put(c->lxc_conf); |
4364 | 0 | return false; |
4365 | 0 | } |
4366 | | /* how should we lock this? */ |
4367 | | |
4368 | 0 | snap = lxc_container_new(snapname, clonelxcpath); |
4369 | 0 | if (!snap || !lxcapi_is_defined(snap)) { |
4370 | 0 | ERROR("Could not open snapshot %s", snapname); |
4371 | |
|
4372 | 0 | if (snap) |
4373 | 0 | lxc_container_put(snap); |
4374 | |
|
4375 | 0 | lxc_storage_put(c->lxc_conf); |
4376 | 0 | return false; |
4377 | 0 | } |
4378 | | |
4379 | 0 | if (strequal(c->name, newname)) { |
4380 | 0 | if (!container_destroy(c, bdev)) { |
4381 | 0 | ERROR("Could not destroy existing container %s", newname); |
4382 | 0 | lxc_container_put(snap); |
4383 | 0 | lxc_storage_put(c->lxc_conf); |
4384 | 0 | return false; |
4385 | 0 | } |
4386 | 0 | } |
4387 | | |
4388 | 0 | if (!strequal(bdev->type, "dir") && !strequal(bdev->type, "loop")) |
4389 | 0 | flags = LXC_CLONE_SNAPSHOT | LXC_CLONE_MAYBE_SNAPSHOT; |
4390 | |
|
4391 | 0 | if (strequal(bdev->type, "overlay") || strequal(bdev->type, "overlayfs")) |
4392 | 0 | flags |= LXC_STORAGE_INTERNAL_OVERLAY_RESTORE; |
4393 | |
|
4394 | 0 | rest = lxcapi_clone(snap, newname, c->config_path, flags, bdev->type, |
4395 | 0 | NULL, 0, NULL); |
4396 | 0 | lxc_storage_put(c->lxc_conf); |
4397 | 0 | if (rest && lxcapi_is_defined(rest)) |
4398 | 0 | b = true; |
4399 | |
|
4400 | 0 | if (rest) |
4401 | 0 | lxc_container_put(rest); |
4402 | |
|
4403 | 0 | lxc_container_put(snap); |
4404 | 0 | return b; |
4405 | 0 | } |
4406 | | |
4407 | 0 | WRAP_API_2(bool, lxcapi_snapshot_restore, const char *, const char *) |
4408 | | |
4409 | | static bool do_snapshot_destroy(const char *snapname, const char *clonelxcpath) |
4410 | 0 | { |
4411 | 0 | struct lxc_container *snap = NULL; |
4412 | 0 | bool bret = false; |
4413 | |
|
4414 | 0 | snap = lxc_container_new(snapname, clonelxcpath); |
4415 | 0 | if (!snap) { |
4416 | 0 | ERROR("Could not find snapshot %s", snapname); |
4417 | 0 | goto err; |
4418 | 0 | } |
4419 | | |
4420 | 0 | if (!do_lxcapi_destroy(snap)) { |
4421 | 0 | ERROR("Could not destroy snapshot %s", snapname); |
4422 | 0 | goto err; |
4423 | 0 | } |
4424 | | |
4425 | 0 | bret = true; |
4426 | |
|
4427 | 0 | err: |
4428 | 0 | if (snap) |
4429 | 0 | lxc_container_put(snap); |
4430 | |
|
4431 | 0 | return bret; |
4432 | 0 | } |
4433 | | |
4434 | | static bool remove_all_snapshots(const char *path) |
4435 | 0 | { |
4436 | 0 | __do_closedir DIR *dir = NULL; |
4437 | 0 | struct dirent *direntp; |
4438 | 0 | bool bret = true; |
4439 | |
|
4440 | 0 | dir = opendir(path); |
4441 | 0 | if (!dir) { |
4442 | 0 | SYSERROR("opendir on snapshot path %s", path); |
4443 | 0 | return false; |
4444 | 0 | } |
4445 | | |
4446 | 0 | while ((direntp = readdir(dir))) { |
4447 | 0 | if (strequal(direntp->d_name, ".")) |
4448 | 0 | continue; |
4449 | | |
4450 | 0 | if (strequal(direntp->d_name, "..")) |
4451 | 0 | continue; |
4452 | | |
4453 | 0 | if (!do_snapshot_destroy(direntp->d_name, path)) { |
4454 | 0 | bret = false; |
4455 | 0 | continue; |
4456 | 0 | } |
4457 | 0 | } |
4458 | |
|
4459 | 0 | if (rmdir(path)) |
4460 | 0 | SYSERROR("Error removing directory %s", path); |
4461 | |
|
4462 | 0 | return bret; |
4463 | 0 | } |
4464 | | |
4465 | | static bool do_lxcapi_snapshot_destroy(struct lxc_container *c, const char *snapname) |
4466 | 0 | { |
4467 | 0 | char clonelxcpath[PATH_MAX]; |
4468 | |
|
4469 | 0 | if (!c || !c->name || !c->config_path || !snapname) |
4470 | 0 | return false; |
4471 | | |
4472 | 0 | if (!get_snappath_dir(c, clonelxcpath)) |
4473 | 0 | return false; |
4474 | | |
4475 | 0 | return do_snapshot_destroy(snapname, clonelxcpath); |
4476 | 0 | } |
4477 | | |
4478 | 0 | WRAP_API_1(bool, lxcapi_snapshot_destroy, const char *) |
4479 | | |
4480 | | static bool do_lxcapi_snapshot_destroy_all(struct lxc_container *c) |
4481 | 0 | { |
4482 | 0 | char clonelxcpath[PATH_MAX]; |
4483 | |
|
4484 | 0 | if (!c || !c->name || !c->config_path) |
4485 | 0 | return false; |
4486 | | |
4487 | 0 | if (!get_snappath_dir(c, clonelxcpath)) |
4488 | 0 | return false; |
4489 | | |
4490 | 0 | return remove_all_snapshots(clonelxcpath); |
4491 | 0 | } |
4492 | | |
4493 | 0 | WRAP_API(bool, lxcapi_snapshot_destroy_all) |
4494 | | |
4495 | | static bool do_lxcapi_may_control(struct lxc_container *c) |
4496 | 0 | { |
4497 | 0 | if (!c) |
4498 | 0 | return false; |
4499 | | |
4500 | 0 | return lxc_try_cmd(c->name, c->config_path) == 0; |
4501 | 0 | } |
4502 | | |
4503 | 0 | WRAP_API(bool, lxcapi_may_control) |
4504 | | |
4505 | | static bool do_add_remove_node(pid_t init_pid, const char *path, bool add, |
4506 | | struct stat *st) |
4507 | 0 | { |
4508 | 0 | int ret; |
4509 | 0 | char *tmp; |
4510 | 0 | pid_t pid; |
4511 | 0 | char chrootpath[PATH_MAX]; |
4512 | 0 | char *directory_path = NULL; |
4513 | |
|
4514 | 0 | pid = fork(); |
4515 | 0 | if (pid < 0) { |
4516 | 0 | SYSERROR("Failed to fork()"); |
4517 | 0 | return false; |
4518 | 0 | } |
4519 | | |
4520 | 0 | if (pid) { |
4521 | 0 | ret = wait_for_pid(pid); |
4522 | 0 | if (ret != 0) { |
4523 | 0 | ERROR("Failed to create device node"); |
4524 | 0 | return false; |
4525 | 0 | } |
4526 | | |
4527 | 0 | return true; |
4528 | 0 | } |
4529 | | |
4530 | | /* prepare the path */ |
4531 | 0 | ret = strnprintf(chrootpath, sizeof(chrootpath), "/proc/%d/root", init_pid); |
4532 | 0 | if (ret < 0) |
4533 | 0 | return false; |
4534 | | |
4535 | 0 | ret = chroot(chrootpath); |
4536 | 0 | if (ret < 0) |
4537 | 0 | _exit(EXIT_FAILURE); |
4538 | | |
4539 | 0 | ret = chdir("/"); |
4540 | 0 | if (ret < 0) |
4541 | 0 | _exit(EXIT_FAILURE); |
4542 | | |
4543 | | /* remove path if it exists */ |
4544 | 0 | ret = faccessat(AT_FDCWD, path, F_OK, AT_SYMLINK_NOFOLLOW); |
4545 | 0 | if(ret == 0) { |
4546 | 0 | ret = unlink(path); |
4547 | 0 | if (ret < 0) { |
4548 | 0 | SYSERROR("Failed to remove \"%s\"", path); |
4549 | 0 | _exit(EXIT_FAILURE); |
4550 | 0 | } |
4551 | 0 | } |
4552 | | |
4553 | 0 | if (!add) |
4554 | 0 | _exit(EXIT_SUCCESS); |
4555 | | |
4556 | | /* create any missing directories */ |
4557 | 0 | tmp = strdup(path); |
4558 | 0 | if (!tmp) |
4559 | 0 | _exit(EXIT_FAILURE); |
4560 | | |
4561 | 0 | directory_path = dirname(tmp); |
4562 | 0 | ret = lxc_mkdir_p(directory_path, 0755); |
4563 | 0 | if (ret < 0 && errno != EEXIST) { |
4564 | 0 | SYSERROR("Failed to create path \"%s\"", directory_path); |
4565 | 0 | free(tmp); |
4566 | 0 | _exit(EXIT_FAILURE); |
4567 | 0 | } |
4568 | | |
4569 | | /* create the device node */ |
4570 | 0 | ret = mknod(path, st->st_mode, st->st_rdev); |
4571 | 0 | free(tmp); |
4572 | 0 | if (ret < 0) { |
4573 | 0 | SYSERROR("Failed to create device node at \"%s\"", path); |
4574 | 0 | _exit(EXIT_FAILURE); |
4575 | 0 | } |
4576 | | |
4577 | 0 | _exit(EXIT_SUCCESS); |
4578 | 0 | } |
4579 | | |
4580 | | static bool add_remove_device_node(struct lxc_container *c, const char *src_path, const char *dest_path, bool add) |
4581 | 0 | { |
4582 | 0 | int ret; |
4583 | 0 | struct stat st; |
4584 | 0 | char value[LXC_MAX_BUFFER]; |
4585 | 0 | const char *p; |
4586 | 0 | pid_t init_pid; |
4587 | | |
4588 | | /* make sure container is running */ |
4589 | 0 | if (!do_lxcapi_is_running(c)) { |
4590 | 0 | ERROR("container is not running"); |
4591 | 0 | return false; |
4592 | 0 | } |
4593 | | |
4594 | | /* use src_path if dest_path is NULL otherwise use dest_path */ |
4595 | 0 | p = dest_path ? dest_path : src_path; |
4596 | | |
4597 | | /* make sure we can access p */ |
4598 | 0 | if(access(p, F_OK) < 0 || stat(p, &st) < 0) |
4599 | 0 | return false; |
4600 | | |
4601 | | /* continue if path is character device or block device */ |
4602 | 0 | if (S_ISCHR(st.st_mode)) |
4603 | 0 | ret = strnprintf(value, sizeof(value), "c %d:%d rwm", major(st.st_rdev), minor(st.st_rdev)); |
4604 | 0 | else if (S_ISBLK(st.st_mode)) |
4605 | 0 | ret = strnprintf(value, sizeof(value), "b %d:%d rwm", major(st.st_rdev), minor(st.st_rdev)); |
4606 | 0 | else |
4607 | 0 | return false; |
4608 | 0 | if (ret < 0) |
4609 | 0 | return false; |
4610 | | |
4611 | 0 | init_pid = do_lxcapi_init_pid(c); |
4612 | 0 | if (init_pid < 0) { |
4613 | 0 | ERROR("Failed to get init pid"); |
4614 | 0 | return false; |
4615 | 0 | } |
4616 | | |
4617 | 0 | if (!do_add_remove_node(init_pid, p, add, &st)) |
4618 | 0 | return false; |
4619 | | |
4620 | | /* add or remove device to/from cgroup access list */ |
4621 | 0 | if (add) { |
4622 | 0 | if (!do_lxcapi_set_cgroup_item(c, "devices.allow", value)) { |
4623 | 0 | ERROR("set_cgroup_item failed while adding the device node"); |
4624 | 0 | return false; |
4625 | 0 | } |
4626 | 0 | } else { |
4627 | 0 | if (!do_lxcapi_set_cgroup_item(c, "devices.deny", value)) { |
4628 | 0 | ERROR("set_cgroup_item failed while removing the device node"); |
4629 | 0 | return false; |
4630 | 0 | } |
4631 | 0 | } |
4632 | | |
4633 | 0 | return true; |
4634 | 0 | } |
4635 | | |
4636 | | static bool do_lxcapi_add_device_node(struct lxc_container *c, const char *src_path, const char *dest_path) |
4637 | 0 | { |
4638 | | // cannot mknod if we're not privileged wrt init_user_ns |
4639 | 0 | if (am_host_unpriv()) { |
4640 | 0 | ERROR(LXC_UNPRIV_EOPNOTSUPP, __FUNCTION__); |
4641 | 0 | return false; |
4642 | 0 | } |
4643 | | |
4644 | 0 | return add_remove_device_node(c, src_path, dest_path, true); |
4645 | 0 | } |
4646 | | |
4647 | 0 | WRAP_API_2(bool, lxcapi_add_device_node, const char *, const char *) |
4648 | | |
4649 | | static bool do_lxcapi_remove_device_node(struct lxc_container *c, const char *src_path, const char *dest_path) |
4650 | 0 | { |
4651 | 0 | if (am_guest_unpriv()) { |
4652 | 0 | ERROR(LXC_UNPRIV_EOPNOTSUPP, __FUNCTION__); |
4653 | 0 | return false; |
4654 | 0 | } |
4655 | | |
4656 | 0 | return add_remove_device_node(c, src_path, dest_path, false); |
4657 | 0 | } |
4658 | | |
4659 | 0 | WRAP_API_2(bool, lxcapi_remove_device_node, const char *, const char *) |
4660 | | |
4661 | | static bool do_lxcapi_attach_interface(struct lxc_container *c, |
4662 | | const char *ifname, |
4663 | | const char *dst_ifname) |
4664 | 0 | { |
4665 | 0 | pid_t init_pid; |
4666 | 0 | int ret = 0; |
4667 | |
|
4668 | 0 | if (am_guest_unpriv()) { |
4669 | 0 | ERROR(LXC_UNPRIV_EOPNOTSUPP, __FUNCTION__); |
4670 | 0 | return false; |
4671 | 0 | } |
4672 | | |
4673 | 0 | if (!ifname) { |
4674 | 0 | ERROR("No source interface name given"); |
4675 | 0 | return false; |
4676 | 0 | } |
4677 | | |
4678 | 0 | ret = lxc_netdev_isup(ifname); |
4679 | 0 | if (ret > 0) { |
4680 | | /* netdev of ifname is up. */ |
4681 | 0 | ret = lxc_netdev_down(ifname); |
4682 | 0 | if (ret) |
4683 | 0 | goto err; |
4684 | 0 | } |
4685 | | |
4686 | 0 | init_pid = do_lxcapi_init_pid(c); |
4687 | 0 | if (init_pid < 0) { |
4688 | 0 | ERROR("Failed to get init pid"); |
4689 | 0 | goto err; |
4690 | 0 | } |
4691 | | |
4692 | 0 | ret = lxc_netdev_move_by_name(ifname, init_pid, dst_ifname); |
4693 | 0 | if (ret) |
4694 | 0 | goto err; |
4695 | | |
4696 | 0 | INFO("Moved network device \"%s\" to network namespace of %d", ifname, init_pid); |
4697 | 0 | return true; |
4698 | | |
4699 | 0 | err: |
4700 | 0 | return false; |
4701 | 0 | } |
4702 | | |
4703 | 0 | WRAP_API_2(bool, lxcapi_attach_interface, const char *, const char *) |
4704 | | |
4705 | | static bool do_lxcapi_detach_interface(struct lxc_container *c, |
4706 | | const char *ifname, |
4707 | | const char *dst_ifname) |
4708 | 0 | { |
4709 | 0 | int ret; |
4710 | 0 | pid_t pid, pid_outside; |
4711 | 0 | __do_free char *physname = NULL; |
4712 | | |
4713 | | /* |
4714 | | * TODO - if this is a physical device, then we need am_host_unpriv. |
4715 | | * But for other types guest privilege suffices. |
4716 | | */ |
4717 | 0 | if (am_guest_unpriv()) { |
4718 | 0 | ERROR(LXC_UNPRIV_EOPNOTSUPP, __FUNCTION__); |
4719 | 0 | return false; |
4720 | 0 | } |
4721 | | |
4722 | 0 | if (!ifname) { |
4723 | 0 | ERROR("No source interface name given"); |
4724 | 0 | return false; |
4725 | 0 | } |
4726 | | |
4727 | 0 | pid_outside = lxc_raw_getpid(); |
4728 | 0 | pid = fork(); |
4729 | 0 | if (pid < 0) { |
4730 | 0 | ERROR("Failed to fork"); |
4731 | 0 | return false; |
4732 | 0 | } |
4733 | | |
4734 | 0 | if (pid == 0) { /* child */ |
4735 | 0 | pid_t init_pid; |
4736 | |
|
4737 | 0 | init_pid = do_lxcapi_init_pid(c); |
4738 | 0 | if (init_pid < 0) { |
4739 | 0 | ERROR("Failed to get init pid"); |
4740 | 0 | _exit(EXIT_FAILURE); |
4741 | 0 | } |
4742 | 0 | if (!switch_to_ns(init_pid, "net")) { |
4743 | 0 | ERROR("Failed to enter network namespace"); |
4744 | 0 | _exit(EXIT_FAILURE); |
4745 | 0 | } |
4746 | | |
4747 | | /* create new mount namespace for use with remounting /sys and is_wlan() below. */ |
4748 | 0 | ret = unshare(CLONE_NEWNS); |
4749 | 0 | if (ret < 0) { |
4750 | 0 | ERROR("Failed to unshare mount namespace"); |
4751 | 0 | _exit(EXIT_FAILURE); |
4752 | 0 | } |
4753 | | |
4754 | | /* set / recursively as private so that mount propagation doesn't affect us. */ |
4755 | 0 | if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0) < 0) { |
4756 | 0 | ERROR("Failed to recursively set / as private in mount namespace"); |
4757 | 0 | _exit(EXIT_FAILURE); |
4758 | 0 | } |
4759 | | |
4760 | 0 | ret = lxc_netdev_isup(ifname); |
4761 | 0 | if (ret < 0) { |
4762 | 0 | ERROR("Failed to determine whether network device \"%s\" is up", ifname); |
4763 | 0 | _exit(EXIT_FAILURE); |
4764 | 0 | } |
4765 | | |
4766 | | /* netdev of ifname is up. */ |
4767 | 0 | if (ret) { |
4768 | 0 | ret = lxc_netdev_down(ifname); |
4769 | 0 | if (ret) { |
4770 | 0 | ERROR("Failed to set network device \"%s\" down", ifname); |
4771 | 0 | _exit(EXIT_FAILURE); |
4772 | 0 | } |
4773 | 0 | } |
4774 | | |
4775 | | /* remount /sys so is_wlan() can check if this device is a wlan device. */ |
4776 | 0 | lxc_attach_remount_sys_proc(); |
4777 | 0 | physname = is_wlan(ifname); |
4778 | 0 | if (physname) |
4779 | 0 | ret = lxc_netdev_move_wlan(physname, ifname, pid_outside, dst_ifname); |
4780 | 0 | else |
4781 | 0 | ret = lxc_netdev_move_by_name(ifname, pid_outside, dst_ifname); |
4782 | | |
4783 | | /* -EINVAL means there is no netdev named as ifname. */ |
4784 | 0 | if (ret < 0) { |
4785 | 0 | if (ret == -EINVAL) |
4786 | 0 | ERROR("Network device \"%s\" not found", ifname); |
4787 | 0 | else |
4788 | 0 | ERROR("Failed to remove network device \"%s\"", ifname); |
4789 | |
|
4790 | 0 | _exit(EXIT_FAILURE); |
4791 | 0 | } |
4792 | | |
4793 | 0 | _exit(EXIT_SUCCESS); |
4794 | 0 | } |
4795 | | |
4796 | 0 | ret = wait_for_pid(pid); |
4797 | 0 | if (ret != 0) |
4798 | 0 | return false; |
4799 | | |
4800 | 0 | INFO("Moved network device \"%s\" to network namespace of %d", ifname, pid_outside); |
4801 | 0 | return true; |
4802 | 0 | } |
4803 | | |
4804 | 0 | WRAP_API_2(bool, lxcapi_detach_interface, const char *, const char *) |
4805 | | |
4806 | | static int do_lxcapi_migrate(struct lxc_container *c, unsigned int cmd, |
4807 | | struct migrate_opts *opts, unsigned int size) |
4808 | 0 | { |
4809 | 0 | int ret = -1; |
4810 | 0 | struct migrate_opts *valid_opts = opts; |
4811 | 0 | uint64_t features_to_check = 0; |
4812 | | |
4813 | | /* If the caller has a bigger (newer) struct migrate_opts, let's make |
4814 | | * sure that the stuff on the end is zero, i.e. that they didn't ask us |
4815 | | * to do anything special. |
4816 | | */ |
4817 | 0 | if (size > sizeof(*opts)) { |
4818 | 0 | unsigned char *addr; |
4819 | 0 | unsigned char *end; |
4820 | |
|
4821 | 0 | addr = (void *)opts + sizeof(*opts); |
4822 | 0 | end = (void *)opts + size; |
4823 | |
|
4824 | 0 | for (; addr < end; addr++) |
4825 | 0 | if (*addr) |
4826 | 0 | return -E2BIG; |
4827 | 0 | } |
4828 | | |
4829 | | /* If the caller has a smaller struct, let's zero out the end for them |
4830 | | * so we don't accidentally use bits of it that they didn't know about |
4831 | | * to initialize. |
4832 | | */ |
4833 | 0 | if (size < sizeof(*opts)) { |
4834 | 0 | valid_opts = malloc(sizeof(*opts)); |
4835 | 0 | if (!valid_opts) |
4836 | 0 | return -ENOMEM; |
4837 | | |
4838 | 0 | memset(valid_opts, 0, sizeof(*opts)); |
4839 | 0 | memcpy(valid_opts, opts, size); |
4840 | 0 | } |
4841 | | |
4842 | 0 | switch (cmd) { |
4843 | 0 | case MIGRATE_PRE_DUMP: |
4844 | 0 | if (!do_lxcapi_is_running(c)) { |
4845 | 0 | ERROR("container is not running"); |
4846 | 0 | goto on_error; |
4847 | 0 | } |
4848 | | |
4849 | 0 | ret = !__criu_pre_dump(c, valid_opts); |
4850 | 0 | break; |
4851 | 0 | case MIGRATE_DUMP: |
4852 | 0 | if (!do_lxcapi_is_running(c)) { |
4853 | 0 | ERROR("container is not running"); |
4854 | 0 | goto on_error; |
4855 | 0 | } |
4856 | | |
4857 | 0 | ret = !__criu_dump(c, valid_opts); |
4858 | 0 | break; |
4859 | 0 | case MIGRATE_RESTORE: |
4860 | 0 | if (do_lxcapi_is_running(c)) { |
4861 | 0 | ERROR("container is already running"); |
4862 | 0 | goto on_error; |
4863 | 0 | } |
4864 | | |
4865 | 0 | ret = !__criu_restore(c, valid_opts); |
4866 | 0 | break; |
4867 | 0 | case MIGRATE_FEATURE_CHECK: |
4868 | 0 | features_to_check = valid_opts->features_to_check; |
4869 | 0 | ret = !__criu_check_feature(&features_to_check); |
4870 | 0 | if (ret) { |
4871 | | /* Something went wrong. Let's let the caller |
4872 | | * know which feature checks failed. */ |
4873 | 0 | valid_opts->features_to_check = features_to_check; |
4874 | 0 | } |
4875 | 0 | break; |
4876 | 0 | default: |
4877 | 0 | ERROR("invalid migrate command %u", cmd); |
4878 | 0 | ret = -EINVAL; |
4879 | 0 | } |
4880 | | |
4881 | 0 | on_error: |
4882 | 0 | if (size < sizeof(*opts)) |
4883 | 0 | free(valid_opts); |
4884 | |
|
4885 | 0 | return ret; |
4886 | 0 | } |
4887 | | |
4888 | 0 | WRAP_API_3(int, lxcapi_migrate, unsigned int, struct migrate_opts *, unsigned int) |
4889 | | |
4890 | | static bool do_lxcapi_checkpoint(struct lxc_container *c, char *directory, bool stop, bool verbose) |
4891 | 0 | { |
4892 | 0 | struct migrate_opts opts; |
4893 | |
|
4894 | 0 | memset(&opts, 0, sizeof(opts)); |
4895 | |
|
4896 | 0 | opts.directory = directory; |
4897 | 0 | opts.stop = stop; |
4898 | 0 | opts.verbose = verbose; |
4899 | |
|
4900 | 0 | return !do_lxcapi_migrate(c, MIGRATE_DUMP, &opts, sizeof(opts)); |
4901 | 0 | } |
4902 | | |
4903 | 0 | WRAP_API_3(bool, lxcapi_checkpoint, char *, bool, bool) |
4904 | | |
4905 | | static bool do_lxcapi_restore(struct lxc_container *c, char *directory, bool verbose) |
4906 | 0 | { |
4907 | 0 | struct migrate_opts opts; |
4908 | |
|
4909 | 0 | memset(&opts, 0, sizeof(opts)); |
4910 | |
|
4911 | 0 | opts.directory = directory; |
4912 | 0 | opts.verbose = verbose; |
4913 | |
|
4914 | 0 | return !do_lxcapi_migrate(c, MIGRATE_RESTORE, &opts, sizeof(opts)); |
4915 | 0 | } |
4916 | | |
4917 | 0 | WRAP_API_2(bool, lxcapi_restore, char *, bool) |
4918 | | |
4919 | | /* @st_mode is the st_mode field of the stat(source) return struct */ |
4920 | | static int create_mount_target(const char *dest, mode_t st_mode) |
4921 | 0 | { |
4922 | 0 | char *dirdup, *destdirname; |
4923 | 0 | struct stat sb; |
4924 | 0 | int ret; |
4925 | |
|
4926 | 0 | dirdup = strdup(dest); |
4927 | 0 | if (!dirdup) { |
4928 | 0 | SYSERROR("Failed to duplicate target name \"%s\"", dest); |
4929 | 0 | return -1; |
4930 | 0 | } |
4931 | 0 | destdirname = dirname(dirdup); |
4932 | |
|
4933 | 0 | ret = lxc_mkdir_p(destdirname, 0755); |
4934 | 0 | if (ret < 0) { |
4935 | 0 | SYSERROR("Failed to create \"%s\"", destdirname); |
4936 | 0 | free(dirdup); |
4937 | 0 | return ret; |
4938 | 0 | } |
4939 | 0 | free(dirdup); |
4940 | |
|
4941 | 0 | if (stat(dest, &sb) == 0) { |
4942 | 0 | if (S_ISDIR(st_mode) && S_ISDIR(sb.st_mode)) |
4943 | 0 | return 0; |
4944 | | |
4945 | 0 | if (S_ISREG(st_mode) && S_ISREG(sb.st_mode)) |
4946 | 0 | return 0; |
4947 | | |
4948 | 0 | if (remove(dest) < 0) { |
4949 | 0 | SYSERROR("Failed to remove existing mount target \"%s\"", dest); |
4950 | 0 | return -1; |
4951 | 0 | } |
4952 | 0 | } else if (errno != ENOENT) { |
4953 | 0 | SYSERROR("Failed to stat existing mount target \"%s\"", dest); |
4954 | 0 | return -1; |
4955 | 0 | } |
4956 | | |
4957 | 0 | if (S_ISDIR(st_mode)) |
4958 | 0 | ret = mkdir(dest, 0000); |
4959 | 0 | else |
4960 | 0 | ret = mknod(dest, S_IFREG | 0000, 0); |
4961 | |
|
4962 | 0 | if (ret == 0) |
4963 | 0 | TRACE("Created mount target \"%s\"", dest); |
4964 | 0 | else if (ret < 0 && errno != EEXIST) { |
4965 | 0 | SYSERROR("Failed to create mount target \"%s\"", dest); |
4966 | 0 | return -1; |
4967 | 0 | } |
4968 | | |
4969 | 0 | return 0; |
4970 | 0 | } |
4971 | | |
4972 | | static int do_lxcapi_mount(struct lxc_container *c, const char *source, |
4973 | | const char *target, const char *filesystemtype, |
4974 | | unsigned long mountflags, const void *data, |
4975 | | struct lxc_mount *mnt) |
4976 | 0 | { |
4977 | 0 | char *suff, *sret; |
4978 | 0 | char template[PATH_MAX], path[PATH_MAX]; |
4979 | 0 | pid_t pid, init_pid; |
4980 | 0 | struct stat sb; |
4981 | 0 | bool lxc_is_dir; |
4982 | 0 | int ret = -1, fd = -EBADF; |
4983 | |
|
4984 | 0 | if (!c || !c->lxc_conf) { |
4985 | 0 | ERROR("Container or configuration is NULL"); |
4986 | 0 | return -EINVAL; |
4987 | 0 | } |
4988 | | |
4989 | 0 | if (!c->lxc_conf->shmount.path_host) { |
4990 | 0 | ERROR("Host path to shared mountpoint must be specified in the config\n"); |
4991 | 0 | return -EINVAL; |
4992 | 0 | } |
4993 | | |
4994 | 0 | ret = strnprintf(template, sizeof(template), "%s/.lxcmount_XXXXXX", c->lxc_conf->shmount.path_host); |
4995 | 0 | if (ret < 0) { |
4996 | 0 | SYSERROR("Error writing shmounts tempdir name"); |
4997 | 0 | goto out; |
4998 | 0 | } |
4999 | | |
5000 | | /* Create a temporary file / dir under the shared mountpoint */ |
5001 | 0 | if (!source || strequal(source, "")) { |
5002 | | /* If source is not specified, maybe we want to mount a filesystem? */ |
5003 | 0 | sb.st_mode = S_IFDIR; |
5004 | 0 | } else { |
5005 | 0 | ret = stat(source, &sb); |
5006 | 0 | if (ret < 0) { |
5007 | 0 | SYSERROR("Error getting stat info about the source \"%s\"", source); |
5008 | 0 | goto out; |
5009 | 0 | } |
5010 | 0 | } |
5011 | | |
5012 | 0 | lxc_is_dir = (S_ISDIR(sb.st_mode) != 0); |
5013 | 0 | if (lxc_is_dir) { |
5014 | 0 | sret = mkdtemp(template); |
5015 | 0 | if (!sret) { |
5016 | 0 | SYSERROR("Could not create shmounts temporary dir"); |
5017 | 0 | goto out; |
5018 | 0 | } |
5019 | 0 | } else { |
5020 | 0 | fd = lxc_make_tmpfile(template, false); |
5021 | 0 | if (fd < 0) { |
5022 | 0 | SYSERROR("Could not create shmounts temporary file"); |
5023 | 0 | goto out; |
5024 | 0 | } |
5025 | 0 | } |
5026 | | |
5027 | | /* Do the fork */ |
5028 | 0 | pid = fork(); |
5029 | 0 | if (pid < 0) { |
5030 | 0 | SYSERROR("Could not fork"); |
5031 | 0 | goto out; |
5032 | 0 | } |
5033 | | |
5034 | 0 | if (pid == 0) { |
5035 | | /* Do the mount */ |
5036 | 0 | ret = mount(source, template, filesystemtype, mountflags, data); |
5037 | 0 | if (ret < 0) { |
5038 | 0 | SYSERROR("Failed to mount onto \"%s\"", template); |
5039 | 0 | _exit(EXIT_FAILURE); |
5040 | 0 | } |
5041 | 0 | TRACE("Mounted \"%s\" onto \"%s\"", source, template); |
5042 | |
|
5043 | 0 | init_pid = do_lxcapi_init_pid(c); |
5044 | 0 | if (init_pid < 0) { |
5045 | 0 | ERROR("Failed to obtain container's init pid"); |
5046 | 0 | _exit(EXIT_FAILURE); |
5047 | 0 | } |
5048 | | |
5049 | | /* Enter the container namespaces */ |
5050 | 0 | if (!list_empty(&c->lxc_conf->id_map)) { |
5051 | 0 | if (!switch_to_ns(init_pid, "user")) { |
5052 | 0 | ERROR("Failed to enter user namespace"); |
5053 | 0 | _exit(EXIT_FAILURE); |
5054 | 0 | } |
5055 | | |
5056 | 0 | if (!lxc_switch_uid_gid(0, 0)) |
5057 | 0 | _exit(EXIT_FAILURE); |
5058 | 0 | } |
5059 | | |
5060 | 0 | if (!switch_to_ns(init_pid, "mnt")) { |
5061 | 0 | ERROR("Failed to enter mount namespace"); |
5062 | 0 | _exit(EXIT_FAILURE); |
5063 | 0 | } |
5064 | | |
5065 | 0 | ret = create_mount_target(target, sb.st_mode); |
5066 | 0 | if (ret < 0) |
5067 | 0 | _exit(EXIT_FAILURE); |
5068 | | |
5069 | 0 | suff = strrchr(template, '/'); |
5070 | 0 | if (!suff) |
5071 | 0 | goto cleanup_target_in_child; |
5072 | | |
5073 | 0 | ret = strnprintf(path, sizeof(path), "%s%s", c->lxc_conf->shmount.path_cont, suff); |
5074 | 0 | if (ret < 0) { |
5075 | 0 | SYSERROR("Error writing container mountpoint name"); |
5076 | 0 | goto cleanup_target_in_child; |
5077 | 0 | } |
5078 | | |
5079 | 0 | ret = mount(path, target, NULL, MS_MOVE | MS_REC, NULL); |
5080 | 0 | if (ret < 0) { |
5081 | 0 | SYSERROR("Failed to move the mount from \"%s\" to \"%s\"", path, target); |
5082 | 0 | goto cleanup_target_in_child; |
5083 | 0 | } |
5084 | 0 | TRACE("Moved mount from \"%s\" to \"%s\"", path, target); |
5085 | |
|
5086 | 0 | _exit(EXIT_SUCCESS); |
5087 | | |
5088 | 0 | cleanup_target_in_child: |
5089 | 0 | (void)remove(target); |
5090 | 0 | _exit(EXIT_FAILURE); |
5091 | 0 | } |
5092 | | |
5093 | 0 | ret = wait_for_pid(pid); |
5094 | 0 | if (ret < 0) |
5095 | 0 | SYSERROR("Wait for the child with pid %ld failed", (long)pid); |
5096 | 0 | else |
5097 | 0 | ret = 0; |
5098 | |
|
5099 | 0 | if (umount2(template, MNT_DETACH)) |
5100 | 0 | SYSWARN("Failed to remove temporary mount \"%s\"", template); |
5101 | |
|
5102 | 0 | if (lxc_is_dir) |
5103 | 0 | (void)rmdir(template); |
5104 | 0 | else |
5105 | 0 | (void)unlink(template); |
5106 | |
|
5107 | 0 | out: |
5108 | 0 | if (fd >= 0) |
5109 | 0 | close(fd); |
5110 | |
|
5111 | 0 | return ret; |
5112 | 0 | } |
5113 | | |
5114 | 0 | WRAP_API_6(int, lxcapi_mount, const char *, const char *, const char *, |
5115 | | unsigned long, const void *, struct lxc_mount *) |
5116 | | |
5117 | | static int do_lxcapi_umount(struct lxc_container *c, const char *target, |
5118 | | unsigned long flags, struct lxc_mount *mnt) |
5119 | 0 | { |
5120 | 0 | pid_t pid, init_pid; |
5121 | 0 | int ret = -1; |
5122 | |
|
5123 | 0 | if (!c || !c->lxc_conf) { |
5124 | 0 | ERROR("Container or configuration is NULL"); |
5125 | 0 | return -EINVAL; |
5126 | 0 | } |
5127 | | |
5128 | | /* Do the fork */ |
5129 | 0 | pid = fork(); |
5130 | 0 | if (pid < 0) { |
5131 | 0 | SYSERROR("Could not fork"); |
5132 | 0 | return -1; |
5133 | 0 | } |
5134 | | |
5135 | 0 | if (pid == 0) { |
5136 | 0 | init_pid = do_lxcapi_init_pid(c); |
5137 | 0 | if (init_pid < 0) { |
5138 | 0 | ERROR("Failed to obtain container's init pid"); |
5139 | 0 | _exit(EXIT_FAILURE); |
5140 | 0 | } |
5141 | | |
5142 | | /* Enter the container namespaces */ |
5143 | 0 | if (!list_empty(&c->lxc_conf->id_map)) { |
5144 | 0 | if (!switch_to_ns(init_pid, "user")) { |
5145 | 0 | ERROR("Failed to enter user namespace"); |
5146 | 0 | _exit(EXIT_FAILURE); |
5147 | 0 | } |
5148 | 0 | } |
5149 | | |
5150 | 0 | if (!switch_to_ns(init_pid, "mnt")) { |
5151 | 0 | ERROR("Failed to enter mount namespace"); |
5152 | 0 | _exit(EXIT_FAILURE); |
5153 | 0 | } |
5154 | | |
5155 | | /* Do the unmount */ |
5156 | 0 | ret = umount2(target, flags); |
5157 | 0 | if (ret < 0) { |
5158 | 0 | SYSERROR("Failed to umount \"%s\"", target); |
5159 | 0 | _exit(EXIT_FAILURE); |
5160 | 0 | } |
5161 | | |
5162 | 0 | _exit(EXIT_SUCCESS); |
5163 | 0 | } |
5164 | | |
5165 | 0 | ret = wait_for_pid(pid); |
5166 | 0 | if (ret < 0) { |
5167 | 0 | SYSERROR("Wait for the child with pid %ld failed", (long)pid); |
5168 | 0 | return -ret; |
5169 | 0 | } |
5170 | | |
5171 | 0 | return 0; |
5172 | 0 | } |
5173 | | |
5174 | 0 | WRAP_API_3(int, lxcapi_umount, const char *, unsigned long, struct lxc_mount*) |
5175 | | |
5176 | | static int lxcapi_attach_run_waitl(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char *arg, ...) |
5177 | 0 | { |
5178 | 0 | va_list ap; |
5179 | 0 | const char **argv; |
5180 | 0 | int ret; |
5181 | |
|
5182 | 0 | if (!c) |
5183 | 0 | return -1; |
5184 | | |
5185 | 0 | current_config = c->lxc_conf; |
5186 | |
|
5187 | 0 | va_start(ap, arg); |
5188 | 0 | argv = lxc_va_arg_list_to_argv_const(ap, 1); |
5189 | 0 | va_end(ap); |
5190 | |
|
5191 | 0 | if (!argv) { |
5192 | 0 | ERROR("Memory allocation error."); |
5193 | 0 | ret = -1; |
5194 | 0 | goto out; |
5195 | 0 | } |
5196 | 0 | argv[0] = arg; |
5197 | |
|
5198 | 0 | ret = do_lxcapi_attach_run_wait(c, options, program, (const char * const *)argv); |
5199 | 0 | free((void*)argv); |
5200 | |
|
5201 | 0 | out: |
5202 | 0 | current_config = NULL; |
5203 | 0 | return ret; |
5204 | 0 | } |
5205 | | |
5206 | | static int do_lxcapi_seccomp_notify_fd(struct lxc_container *c) |
5207 | 0 | { |
5208 | 0 | if (!c || !c->lxc_conf) |
5209 | 0 | return ret_set_errno(-1, -EINVAL); |
5210 | | |
5211 | 0 | return lxc_seccomp_get_notify_fd(&c->lxc_conf->seccomp); |
5212 | 0 | } |
5213 | | |
5214 | 0 | WRAP_API(int, lxcapi_seccomp_notify_fd) |
5215 | | |
5216 | | static int do_lxcapi_seccomp_notify_fd_active(struct lxc_container *c) |
5217 | 0 | { |
5218 | 0 | if (!c || !c->lxc_conf) |
5219 | 0 | return ret_set_errno(-1, -EINVAL); |
5220 | | |
5221 | 0 | return lxc_cmd_get_seccomp_notify_fd(c->name, c->config_path); |
5222 | 0 | } |
5223 | | |
5224 | 0 | WRAP_API(int, lxcapi_seccomp_notify_fd_active) |
5225 | | |
5226 | | static bool do_lxcapi_set_timeout(struct lxc_container *c, int timeout) |
5227 | 0 | { |
5228 | 0 | if (!c) |
5229 | 0 | return false; |
5230 | | |
5231 | 0 | if (!(timeout > 0 || timeout == -1)) |
5232 | 0 | return false; |
5233 | | |
5234 | 0 | c->rcv_timeout = (timeout == -1) ? 0 : timeout; |
5235 | |
|
5236 | 0 | return true; |
5237 | 0 | } |
5238 | | |
5239 | 0 | WRAP_API_1(bool, lxcapi_set_timeout, int) |
5240 | | |
5241 | | struct lxc_container *lxc_container_new(const char *name, const char *configpath) |
5242 | 7.99k | { |
5243 | 7.99k | struct lxc_container *c; |
5244 | 7.99k | size_t len; |
5245 | 7.99k | int rc; |
5246 | | |
5247 | 7.99k | if (!name) |
5248 | 0 | return NULL; |
5249 | | |
5250 | 7.99k | c = malloc(sizeof(*c)); |
5251 | 7.99k | if (!c) { |
5252 | 0 | fprintf(stderr, "Failed to allocate memory for %s\n", name); |
5253 | 0 | return NULL; |
5254 | 0 | } |
5255 | 7.99k | memset(c, 0, sizeof(*c)); |
5256 | | |
5257 | 7.99k | if (configpath) |
5258 | 0 | c->config_path = strdup(configpath); |
5259 | 7.99k | else |
5260 | 7.99k | c->config_path = strdup(lxc_global_config_value("lxc.lxcpath")); |
5261 | 7.99k | if (!c->config_path) { |
5262 | 0 | fprintf(stderr, "Failed to allocate memory for %s\n", name); |
5263 | 0 | goto err; |
5264 | 0 | } |
5265 | | |
5266 | 7.99k | remove_trailing_slashes(c->config_path); |
5267 | | |
5268 | 7.99k | len = strlen(name); |
5269 | 7.99k | c->name = malloc(len + 1); |
5270 | 7.99k | if (!c->name) { |
5271 | 0 | fprintf(stderr, "Failed to allocate memory for %s\n", name); |
5272 | 0 | goto err; |
5273 | 0 | } |
5274 | 7.99k | (void)strlcpy(c->name, name, len + 1); |
5275 | | |
5276 | 7.99k | c->numthreads = 1; |
5277 | 7.99k | c->slock = lxc_newlock(c->config_path, name); |
5278 | 7.99k | if (!c->slock) { |
5279 | 0 | fprintf(stderr, "Failed to create lock for %s\n", name); |
5280 | 0 | goto err; |
5281 | 0 | } |
5282 | | |
5283 | 7.99k | c->privlock = lxc_newlock(NULL, NULL); |
5284 | 7.99k | if (!c->privlock) { |
5285 | 0 | fprintf(stderr, "Failed to create private lock for %s\n", name); |
5286 | 0 | goto err; |
5287 | 0 | } |
5288 | | |
5289 | 7.99k | if (!set_config_filename(c)) { |
5290 | 0 | fprintf(stderr, "Failed to create config file name for %s\n", name); |
5291 | 0 | goto err; |
5292 | 0 | } |
5293 | | |
5294 | 7.99k | if (file_exists(c->configfile) && !lxcapi_load_config(c, NULL)) { |
5295 | 0 | fprintf(stderr, "Failed to load config for %s\n", name); |
5296 | 0 | goto err; |
5297 | 0 | } |
5298 | | |
5299 | 7.99k | rc = ongoing_create(c); |
5300 | 7.99k | switch (rc) { |
5301 | 0 | case LXC_CREATE_INCOMPLETE: |
5302 | 0 | SYSERROR("Failed to complete container creation for %s", c->name); |
5303 | 0 | container_destroy(c, NULL); |
5304 | 0 | lxcapi_clear_config(c); |
5305 | 0 | break; |
5306 | 0 | case LXC_CREATE_ONGOING: |
5307 | | /* container creation going on */ |
5308 | 0 | break; |
5309 | 0 | case LXC_CREATE_FAILED: |
5310 | | /* container creation failed */ |
5311 | 0 | if (errno != EACCES && errno != EPERM) { |
5312 | | /* insufficient privileges */ |
5313 | 0 | SYSERROR("Failed checking for incomplete container %s creation", c->name); |
5314 | 0 | goto err; |
5315 | 0 | } |
5316 | 0 | break; |
5317 | 7.99k | } |
5318 | | |
5319 | 7.99k | c->daemonize = true; |
5320 | 7.99k | c->pidfile = NULL; |
5321 | | |
5322 | | /* Assign the member functions. */ |
5323 | 7.99k | c->is_defined = lxcapi_is_defined; |
5324 | 7.99k | c->state = lxcapi_state; |
5325 | 7.99k | c->is_running = lxcapi_is_running; |
5326 | 7.99k | c->freeze = lxcapi_freeze; |
5327 | 7.99k | c->unfreeze = lxcapi_unfreeze; |
5328 | 7.99k | c->console = lxcapi_console; |
5329 | 7.99k | c->console_getfd = lxcapi_console_getfd; |
5330 | 7.99k | c->devpts_fd = lxcapi_devpts_fd; |
5331 | 7.99k | c->init_pid = lxcapi_init_pid; |
5332 | 7.99k | c->init_pidfd = lxcapi_init_pidfd; |
5333 | 7.99k | c->load_config = lxcapi_load_config; |
5334 | 7.99k | c->want_daemonize = lxcapi_want_daemonize; |
5335 | 7.99k | c->want_close_all_fds = lxcapi_want_close_all_fds; |
5336 | 7.99k | c->start = lxcapi_start; |
5337 | 7.99k | c->startl = lxcapi_startl; |
5338 | 7.99k | c->stop = lxcapi_stop; |
5339 | 7.99k | c->config_file_name = lxcapi_config_file_name; |
5340 | 7.99k | c->wait = lxcapi_wait; |
5341 | 7.99k | c->set_config_item = lxcapi_set_config_item; |
5342 | 7.99k | c->destroy = lxcapi_destroy; |
5343 | 7.99k | c->destroy_with_snapshots = lxcapi_destroy_with_snapshots; |
5344 | 7.99k | c->rename = lxcapi_rename; |
5345 | 7.99k | c->save_config = lxcapi_save_config; |
5346 | 7.99k | c->get_keys = lxcapi_get_keys; |
5347 | 7.99k | c->create = lxcapi_create; |
5348 | 7.99k | c->createl = lxcapi_createl; |
5349 | 7.99k | c->shutdown = lxcapi_shutdown; |
5350 | 7.99k | c->reboot = lxcapi_reboot; |
5351 | 7.99k | c->reboot2 = lxcapi_reboot2; |
5352 | 7.99k | c->clear_config = lxcapi_clear_config; |
5353 | 7.99k | c->clear_config_item = lxcapi_clear_config_item; |
5354 | 7.99k | c->get_config_item = lxcapi_get_config_item; |
5355 | 7.99k | c->get_running_config_item = lxcapi_get_running_config_item; |
5356 | 7.99k | c->get_cgroup_item = lxcapi_get_cgroup_item; |
5357 | 7.99k | c->set_cgroup_item = lxcapi_set_cgroup_item; |
5358 | 7.99k | c->get_config_path = lxcapi_get_config_path; |
5359 | 7.99k | c->set_config_path = lxcapi_set_config_path; |
5360 | 7.99k | c->clone = lxcapi_clone; |
5361 | 7.99k | c->get_interfaces = lxcapi_get_interfaces; |
5362 | 7.99k | c->get_ips = lxcapi_get_ips; |
5363 | 7.99k | c->attach = lxcapi_attach; |
5364 | 7.99k | c->attach_run_wait = lxcapi_attach_run_wait; |
5365 | 7.99k | c->attach_run_waitl = lxcapi_attach_run_waitl; |
5366 | 7.99k | c->snapshot = lxcapi_snapshot; |
5367 | 7.99k | c->snapshot_list = lxcapi_snapshot_list; |
5368 | 7.99k | c->snapshot_restore = lxcapi_snapshot_restore; |
5369 | 7.99k | c->snapshot_destroy = lxcapi_snapshot_destroy; |
5370 | 7.99k | c->snapshot_destroy_all = lxcapi_snapshot_destroy_all; |
5371 | 7.99k | c->may_control = lxcapi_may_control; |
5372 | 7.99k | c->add_device_node = lxcapi_add_device_node; |
5373 | 7.99k | c->remove_device_node = lxcapi_remove_device_node; |
5374 | 7.99k | c->attach_interface = lxcapi_attach_interface; |
5375 | 7.99k | c->detach_interface = lxcapi_detach_interface; |
5376 | 7.99k | c->checkpoint = lxcapi_checkpoint; |
5377 | 7.99k | c->restore = lxcapi_restore; |
5378 | 7.99k | c->migrate = lxcapi_migrate; |
5379 | 7.99k | c->console_log = lxcapi_console_log; |
5380 | 7.99k | c->mount = lxcapi_mount; |
5381 | 7.99k | c->umount = lxcapi_umount; |
5382 | 7.99k | c->seccomp_notify_fd = lxcapi_seccomp_notify_fd; |
5383 | 7.99k | c->seccomp_notify_fd_active = lxcapi_seccomp_notify_fd_active; |
5384 | 7.99k | c->set_timeout = lxcapi_set_timeout; |
5385 | | |
5386 | 7.99k | return c; |
5387 | | |
5388 | 0 | err: |
5389 | 0 | lxc_container_free(c); |
5390 | 0 | return NULL; |
5391 | 7.99k | } |
5392 | | |
5393 | | int lxc_get_wait_states(const char **states) |
5394 | 0 | { |
5395 | 0 | int i; |
5396 | |
|
5397 | 0 | if (states) |
5398 | 0 | for (i=0; i<MAX_STATE; i++) |
5399 | 0 | states[i] = lxc_state2str(i); |
5400 | |
|
5401 | 0 | return MAX_STATE; |
5402 | 0 | } |
5403 | | |
5404 | | /* |
5405 | | * These next two could probably be done smarter with reusing a common function |
5406 | | * with different iterators and tests... |
5407 | | */ |
5408 | | int list_defined_containers(const char *lxcpath, char ***names, |
5409 | | struct lxc_container ***cret) |
5410 | 0 | { |
5411 | 0 | __do_closedir DIR *dir = NULL; |
5412 | 0 | size_t array_len = 0, name_array_len = 0, ct_array_len = 0; |
5413 | 0 | struct dirent *direntp; |
5414 | 0 | struct lxc_container *c; |
5415 | |
|
5416 | 0 | if (!lxcpath) |
5417 | 0 | lxcpath = lxc_global_config_value("lxc.lxcpath"); |
5418 | |
|
5419 | 0 | dir = opendir(lxcpath); |
5420 | 0 | if (!dir) { |
5421 | 0 | SYSERROR("opendir on lxcpath"); |
5422 | 0 | return -1; |
5423 | 0 | } |
5424 | | |
5425 | 0 | if (cret) |
5426 | 0 | *cret = NULL; |
5427 | |
|
5428 | 0 | if (names) |
5429 | 0 | *names = NULL; |
5430 | |
|
5431 | 0 | while ((direntp = readdir(dir))) { |
5432 | | /* Ignore '.', '..' and any hidden directory. */ |
5433 | 0 | if (strnequal(direntp->d_name, ".", 1)) |
5434 | 0 | continue; |
5435 | | |
5436 | 0 | if (!config_file_exists(lxcpath, direntp->d_name)) |
5437 | 0 | continue; |
5438 | | |
5439 | 0 | if (cret) { |
5440 | 0 | c = lxc_container_new(direntp->d_name, lxcpath); |
5441 | 0 | if (!c) { |
5442 | 0 | INFO("Container %s:%s has a config but could not be loaded", |
5443 | 0 | lxcpath, direntp->d_name); |
5444 | 0 | continue; |
5445 | 0 | } |
5446 | | |
5447 | 0 | if (!do_lxcapi_is_defined(c)) { |
5448 | 0 | INFO("Container %s:%s has a config but is not defined", |
5449 | 0 | lxcpath, direntp->d_name); |
5450 | |
|
5451 | 0 | lxc_container_put(c); |
5452 | 0 | continue; |
5453 | 0 | } |
5454 | 0 | } |
5455 | | |
5456 | 0 | if (names) { |
5457 | 0 | if (!add_to_array(names, direntp->d_name, array_len)) |
5458 | 0 | goto free_bad; |
5459 | 0 | name_array_len++; |
5460 | 0 | } |
5461 | | |
5462 | 0 | if (cret) { |
5463 | 0 | if (!add_to_clist(cret, c, array_len, true)) { |
5464 | 0 | lxc_container_put(c); |
5465 | 0 | goto free_bad; |
5466 | 0 | } |
5467 | 0 | ct_array_len++; |
5468 | 0 | } |
5469 | | |
5470 | 0 | array_len++; |
5471 | 0 | } |
5472 | | |
5473 | 0 | return array_len; |
5474 | | |
5475 | 0 | free_bad: |
5476 | 0 | if (names && *names) { |
5477 | 0 | for (size_t i = 0; i < name_array_len; i++) |
5478 | 0 | free((*names)[i]); |
5479 | 0 | free(*names); |
5480 | 0 | } |
5481 | |
|
5482 | 0 | if (cret && *cret) { |
5483 | 0 | for (size_t i = 0; i < ct_array_len; i++) |
5484 | 0 | lxc_container_put((*cret)[i]); |
5485 | 0 | free(*cret); |
5486 | 0 | } |
5487 | |
|
5488 | 0 | return -1; |
5489 | 0 | } |
5490 | | |
5491 | | int list_active_containers(const char *lxcpath, char ***nret, |
5492 | | struct lxc_container ***cret) |
5493 | 0 | { |
5494 | 0 | __do_free char *line = NULL; |
5495 | 0 | __do_fclose FILE *f = NULL; |
5496 | 0 | int i, ret = -1, cret_cnt = 0, ct_name_cnt = 0; |
5497 | 0 | int lxcpath_len; |
5498 | 0 | char **ct_name = NULL; |
5499 | 0 | size_t len = 0; |
5500 | 0 | struct lxc_container *c = NULL; |
5501 | 0 | bool is_hashed; |
5502 | |
|
5503 | 0 | if (!lxcpath) |
5504 | 0 | lxcpath = lxc_global_config_value("lxc.lxcpath"); |
5505 | 0 | lxcpath_len = strlen(lxcpath); |
5506 | |
|
5507 | 0 | if (cret) |
5508 | 0 | *cret = NULL; |
5509 | |
|
5510 | 0 | if (nret) |
5511 | 0 | *nret = NULL; |
5512 | |
|
5513 | 0 | f = fopen("/proc/net/unix", "re"); |
5514 | 0 | if (!f) |
5515 | 0 | return -1; |
5516 | | |
5517 | 0 | while (getline(&line, &len, f) != -1) { |
5518 | 0 | char *p, *p2; |
5519 | |
|
5520 | 0 | p = strstr(line, " @"); |
5521 | 0 | if (!p) |
5522 | 0 | continue; |
5523 | 0 | p += 2; |
5524 | |
|
5525 | 0 | is_hashed = false; |
5526 | |
|
5527 | 0 | if (strnequal(p, lxcpath, lxcpath_len)) { |
5528 | 0 | p += lxcpath_len; |
5529 | 0 | } else if (strnequal(p, "lxc/", 4)) { |
5530 | 0 | p += 4; |
5531 | 0 | is_hashed = true; |
5532 | 0 | } else { |
5533 | 0 | continue; |
5534 | 0 | } |
5535 | | |
5536 | 0 | while (*p == '/') |
5537 | 0 | p++; |
5538 | | |
5539 | | /* Now p is the start of lxc_name. */ |
5540 | 0 | p2 = strchr(p, '/'); |
5541 | 0 | if (!p2 || !strnequal(p2, "/command", 8)) |
5542 | 0 | continue; |
5543 | 0 | *p2 = '\0'; |
5544 | |
|
5545 | 0 | if (is_hashed) { |
5546 | 0 | char *recvpath = lxc_cmd_get_lxcpath(p); |
5547 | 0 | if (!recvpath) |
5548 | 0 | continue; |
5549 | | |
5550 | 0 | if (!strnequal(lxcpath, recvpath, lxcpath_len)) { |
5551 | 0 | free(recvpath); |
5552 | 0 | continue; |
5553 | 0 | } |
5554 | 0 | free(recvpath); |
5555 | |
|
5556 | 0 | p = lxc_cmd_get_name(p); |
5557 | 0 | if (!p) |
5558 | 0 | continue; |
5559 | 0 | } |
5560 | | |
5561 | 0 | if (array_contains(&ct_name, p, ct_name_cnt)) { |
5562 | 0 | if (is_hashed) |
5563 | 0 | free(p); |
5564 | 0 | continue; |
5565 | 0 | } |
5566 | | |
5567 | 0 | if (!add_to_array(&ct_name, p, ct_name_cnt)) { |
5568 | 0 | if (is_hashed) |
5569 | 0 | free(p); |
5570 | 0 | goto free_cret_list; |
5571 | 0 | } |
5572 | | |
5573 | 0 | ct_name_cnt++; |
5574 | |
|
5575 | 0 | if (!cret) { |
5576 | 0 | if (is_hashed) |
5577 | 0 | free(p); |
5578 | 0 | continue; |
5579 | 0 | } |
5580 | | |
5581 | 0 | c = lxc_container_new(p, lxcpath); |
5582 | 0 | if (!c) { |
5583 | 0 | INFO("Container %s:%s is running but could not be loaded", lxcpath, p); |
5584 | 0 | if (is_hashed) |
5585 | 0 | free(p); |
5586 | |
|
5587 | 0 | goto free_cret_list; |
5588 | 0 | } |
5589 | | |
5590 | 0 | if (is_hashed) |
5591 | 0 | free(p); |
5592 | | |
5593 | | /* |
5594 | | * If this is an anonymous container, then is_defined *can* |
5595 | | * return false. So we don't do that check. Count on the |
5596 | | * fact that the command socket exists. |
5597 | | */ |
5598 | |
|
5599 | 0 | if (!add_to_clist(cret, c, cret_cnt, true)) { |
5600 | 0 | lxc_container_put(c); |
5601 | 0 | goto free_cret_list; |
5602 | 0 | } |
5603 | | |
5604 | 0 | cret_cnt++; |
5605 | 0 | } |
5606 | | |
5607 | 0 | if (nret && cret && cret_cnt != ct_name_cnt) { |
5608 | 0 | if (c) |
5609 | 0 | lxc_container_put(c); |
5610 | 0 | goto free_cret_list; |
5611 | 0 | } |
5612 | | |
5613 | 0 | ret = ct_name_cnt; |
5614 | 0 | if (nret) |
5615 | 0 | *nret = ct_name; |
5616 | 0 | else |
5617 | 0 | goto free_ct_name; |
5618 | | |
5619 | 0 | goto out; |
5620 | | |
5621 | 0 | free_cret_list: |
5622 | 0 | if (cret && *cret) { |
5623 | 0 | for (i = 0; i < cret_cnt; i++) |
5624 | 0 | lxc_container_put((*cret)[i]); |
5625 | 0 | free(*cret); |
5626 | 0 | } |
5627 | |
|
5628 | 0 | free_ct_name: |
5629 | 0 | if (ct_name) { |
5630 | 0 | for (i = 0; i < ct_name_cnt; i++) |
5631 | 0 | free(ct_name[i]); |
5632 | 0 | free(ct_name); |
5633 | 0 | } |
5634 | |
|
5635 | 0 | out: |
5636 | 0 | return ret; |
5637 | 0 | } |
5638 | | |
5639 | | int list_all_containers(const char *lxcpath, char ***nret, |
5640 | | struct lxc_container ***cret) |
5641 | 0 | { |
5642 | 0 | int active_cnt, ct_cnt, ct_list_cnt, ret; |
5643 | 0 | char **active_name = NULL, **ct_name = NULL; |
5644 | 0 | struct lxc_container **ct_list = NULL; |
5645 | |
|
5646 | 0 | ct_cnt = list_defined_containers(lxcpath, &ct_name, NULL); |
5647 | 0 | if (ct_cnt < 0) |
5648 | 0 | return ct_cnt; |
5649 | | |
5650 | 0 | active_cnt = list_active_containers(lxcpath, &active_name, NULL); |
5651 | 0 | if (active_cnt < 0) { |
5652 | 0 | ret = active_cnt; |
5653 | 0 | goto free_ct_name; |
5654 | 0 | } |
5655 | | |
5656 | 0 | ret = -EINVAL; |
5657 | 0 | for (int i = 0; i < active_cnt; i++) { |
5658 | 0 | if (array_contains(&ct_name, active_name[i], ct_cnt)) |
5659 | 0 | continue; |
5660 | | |
5661 | 0 | if (!add_to_array(&ct_name, active_name[i], ct_cnt)) |
5662 | 0 | goto free_active_name; |
5663 | | |
5664 | 0 | ct_cnt++; |
5665 | 0 | } |
5666 | | |
5667 | 0 | if (cret) { |
5668 | 0 | ct_list_cnt = 0; |
5669 | 0 | for (int i = 0; i < ct_cnt; i++) { |
5670 | 0 | __put_lxc_container struct lxc_container *c = NULL; |
5671 | |
|
5672 | 0 | c = lxc_container_new(ct_name[i], lxcpath); |
5673 | 0 | if (!c) { |
5674 | 0 | WARN("Container %s:%s could not be loaded", lxcpath, ct_name[i]); |
5675 | 0 | goto free_ct_list; |
5676 | 0 | } |
5677 | | |
5678 | 0 | if (!add_to_clist(&ct_list, c, ct_list_cnt, false)) |
5679 | 0 | goto free_ct_list; |
5680 | | |
5681 | 0 | ct_list_cnt++; |
5682 | 0 | move_ptr(c); |
5683 | 0 | } |
5684 | | |
5685 | 0 | *cret = ct_list; |
5686 | 0 | } |
5687 | | |
5688 | 0 | for (int i = 0; i < active_cnt; i++) |
5689 | 0 | free(active_name[i]); |
5690 | 0 | free(active_name); |
5691 | |
|
5692 | 0 | if (nret) { |
5693 | 0 | *nret = ct_name; |
5694 | 0 | } else { |
5695 | 0 | for (int i = 0; i < ct_cnt; i++) |
5696 | 0 | free(ct_name[i]); |
5697 | 0 | free(ct_name); |
5698 | 0 | } |
5699 | |
|
5700 | 0 | return ct_cnt; |
5701 | | |
5702 | 0 | free_ct_list: |
5703 | 0 | for (int i = 0; i < ct_list_cnt; i++) |
5704 | 0 | lxc_container_put(ct_list[i]); |
5705 | 0 | free(ct_list); |
5706 | |
|
5707 | 0 | free_active_name: |
5708 | 0 | for (int i = 0; i < active_cnt; i++) |
5709 | 0 | free(active_name[i]); |
5710 | 0 | free(active_name); |
5711 | |
|
5712 | 0 | free_ct_name: |
5713 | 0 | for (int i = 0; i < ct_cnt; i++) |
5714 | 0 | free(ct_name[i]); |
5715 | 0 | free(ct_name); |
5716 | |
|
5717 | 0 | return ret; |
5718 | 0 | } |
5719 | | |
5720 | | bool lxc_config_item_is_supported(const char *key) |
5721 | 0 | { |
5722 | 0 | return !!lxc_get_config_exact(key); |
5723 | 0 | } |
5724 | | |
5725 | | bool lxc_has_api_extension(const char *extension) |
5726 | 0 | { |
5727 | | /* The NULL API extension is always present. :) */ |
5728 | 0 | if (!extension) |
5729 | 0 | return true; |
5730 | | |
5731 | 0 | for (size_t i = 0; i < nr_api_extensions; i++) |
5732 | 0 | if (strequal(api_extensions[i], extension)) |
5733 | 0 | return true; |
5734 | | |
5735 | 0 | return false; |
5736 | 0 | } |