]>
Commit | Line | Data |
---|---|---|
72d0e1cb SG |
1 | /* liblxcapi |
2 | * | |
3 | * Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>. | |
4 | * Copyright © 2012 Canonical Ltd. | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2, as | |
8 | * published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License along | |
16 | * with this program; if not, write to the Free Software Foundation, Inc., | |
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 | */ | |
19 | ||
9be53773 SH |
20 | #define _GNU_SOURCE |
21 | #include <unistd.h> | |
22 | #include <sys/types.h> | |
23 | #include <sys/wait.h> | |
24 | #include <errno.h> | |
25 | #include <sched.h> | |
26 | #include "config.h" | |
72d0e1cb SG |
27 | #include "lxc.h" |
28 | #include "state.h" | |
29 | #include "lxccontainer.h" | |
30 | #include "conf.h" | |
72d0e1cb SG |
31 | #include "confile.h" |
32 | #include "cgroup.h" | |
33 | #include "commands.h" | |
b6b918a1 | 34 | #include "version.h" |
72d0e1cb | 35 | #include "log.h" |
9be53773 | 36 | #include "bdev.h" |
2a59a681 | 37 | #include <lxc/utils.h> |
e51d4895 | 38 | #include <lxc/monitor.h> |
72d0e1cb | 39 | |
9be53773 SH |
40 | /* Define unshare() if missing from the C library */ |
41 | /* this is also in attach.c and lxccontainer.c: commonize it in utils.c */ | |
42 | #ifndef HAVE_UNSHARE | |
43 | static int unshare(int flags) | |
44 | { | |
45 | #ifdef __NR_unshare | |
46 | return syscall(__NR_unshare, flags); | |
47 | #else | |
48 | errno = ENOSYS; | |
49 | return -1; | |
50 | #endif | |
51 | } | |
52 | #else | |
53 | int unshare(int); | |
54 | #endif | |
55 | ||
72d0e1cb SG |
56 | lxc_log_define(lxc_container, lxc); |
57 | ||
58 | /* LOCKING | |
59 | * c->privlock protects the struct lxc_container from multiple threads. | |
60 | * c->slock protects the on-disk container data | |
61 | * NOTHING mutexes two independent programs with their own struct | |
62 | * lxc_container for the same c->name, between API calls. For instance, | |
63 | * c->config_read(); c->start(); Between those calls, data on disk | |
64 | * could change (which shouldn't bother the caller unless for instance | |
65 | * the rootfs get moved). c->config_read(); update; c->config_write(); | |
66 | * Two such updaters could race. The callers should therefore check their | |
67 | * results. Trying to prevent that would necessarily expose us to deadlocks | |
68 | * due to hung callers. So I prefer to keep the locks only within our own | |
69 | * functions, not across functions. | |
70 | * | |
71 | * If you're going to fork while holding a lxccontainer, increment | |
72 | * c->numthreads (under privlock) before forking. When deleting, | |
73 | * decrement numthreads under privlock, then if it hits 0 you can delete. | |
74 | * Do not ever use a lxccontainer whose numthreads you did not bump. | |
75 | */ | |
76 | ||
77 | static void lxc_container_free(struct lxc_container *c) | |
78 | { | |
79 | if (!c) | |
80 | return; | |
81 | ||
82 | if (c->configfile) { | |
83 | free(c->configfile); | |
84 | c->configfile = NULL; | |
85 | } | |
86 | if (c->error_string) { | |
87 | free(c->error_string); | |
88 | c->error_string = NULL; | |
89 | } | |
d95db067 DE |
90 | if (c->slock) { |
91 | sem_close(c->slock); | |
92 | c->slock = NULL; | |
93 | } | |
72d0e1cb | 94 | if (c->privlock) { |
43d1aa34 | 95 | sem_t *l = c->privlock; |
72d0e1cb | 96 | c->privlock = NULL; |
43d1aa34 SH |
97 | sem_destroy(l); |
98 | free(l); | |
72d0e1cb SG |
99 | } |
100 | if (c->name) { | |
101 | free(c->name); | |
102 | c->name = NULL; | |
103 | } | |
d95db067 DE |
104 | if (c->lxc_conf) { |
105 | lxc_conf_free(c->lxc_conf); | |
106 | c->lxc_conf = NULL; | |
107 | } | |
2a59a681 SH |
108 | if (c->config_path) { |
109 | free(c->config_path); | |
110 | c->config_path = NULL; | |
111 | } | |
72d0e1cb SG |
112 | free(c); |
113 | } | |
114 | ||
43d1aa34 SH |
115 | /* |
116 | * Consider the following case: | |
117 | freer | racing get()er | |
118 | ================================================================== | |
119 | lxc_container_put() | lxc_container_get() | |
120 | \ lxclock(c->privlock) | c->numthreads < 1? (no) | |
121 | \ c->numthreads = 0 | \ lxclock(c->privlock) -> waits | |
122 | \ lxcunlock() | \ | |
123 | \ lxc_container_free() | \ lxclock() returns | |
124 | | \ c->numthreads < 1 -> return 0 | |
125 | \ \ (free stuff) | | |
126 | \ \ sem_destroy(privlock) | | |
127 | ||
128 | * When the get()er checks numthreads the first time, one of the following | |
129 | * is true: | |
130 | * 1. freer has set numthreads = 0. get() returns 0 | |
131 | * 2. freer is between lxclock and setting numthreads to 0. get()er will | |
132 | * sem_wait on privlock, get lxclock after freer() drops it, then see | |
133 | * numthreads is 0 and exit without touching lxclock again.. | |
134 | * 3. freer has not yet locked privlock. If get()er runs first, then put()er | |
135 | * will see --numthreads = 1 and not call lxc_container_free(). | |
136 | */ | |
137 | ||
72d0e1cb SG |
138 | int lxc_container_get(struct lxc_container *c) |
139 | { | |
140 | if (!c) | |
141 | return 0; | |
142 | ||
43d1aa34 SH |
143 | // if someone else has already started freeing the container, don't |
144 | // try to take the lock, which may be invalid | |
145 | if (c->numthreads < 1) | |
146 | return 0; | |
147 | ||
72d0e1cb SG |
148 | if (lxclock(c->privlock, 0)) |
149 | return 0; | |
150 | if (c->numthreads < 1) { | |
151 | // bail without trying to unlock, bc the privlock is now probably | |
152 | // in freed memory | |
153 | return 0; | |
154 | } | |
155 | c->numthreads++; | |
156 | lxcunlock(c->privlock); | |
157 | return 1; | |
158 | } | |
159 | ||
160 | int lxc_container_put(struct lxc_container *c) | |
161 | { | |
162 | if (!c) | |
163 | return -1; | |
164 | if (lxclock(c->privlock, 0)) | |
165 | return -1; | |
166 | if (--c->numthreads < 1) { | |
167 | lxcunlock(c->privlock); | |
168 | lxc_container_free(c); | |
169 | return 1; | |
170 | } | |
171 | lxcunlock(c->privlock); | |
172 | return 0; | |
173 | } | |
174 | ||
175 | static bool file_exists(char *f) | |
176 | { | |
177 | struct stat statbuf; | |
178 | ||
179 | return stat(f, &statbuf) == 0; | |
180 | } | |
181 | ||
182 | static bool lxcapi_is_defined(struct lxc_container *c) | |
183 | { | |
184 | struct stat statbuf; | |
185 | bool ret = false; | |
186 | int statret; | |
187 | ||
188 | if (!c) | |
189 | return false; | |
190 | ||
191 | if (lxclock(c->privlock, 0)) | |
192 | return false; | |
193 | if (!c->configfile) | |
194 | goto out; | |
195 | statret = stat(c->configfile, &statbuf); | |
196 | if (statret != 0) | |
197 | goto out; | |
198 | ret = true; | |
199 | ||
200 | out: | |
201 | lxcunlock(c->privlock); | |
202 | return ret; | |
203 | } | |
204 | ||
205 | static const char *lxcapi_state(struct lxc_container *c) | |
206 | { | |
207 | const char *ret; | |
208 | lxc_state_t s; | |
209 | ||
210 | if (!c) | |
211 | return NULL; | |
212 | if (lxclock(c->slock, 0)) | |
213 | return NULL; | |
13f5be62 | 214 | s = lxc_getstate(c->name, c->config_path); |
72d0e1cb SG |
215 | ret = lxc_state2str(s); |
216 | lxcunlock(c->slock); | |
217 | ||
218 | return ret; | |
219 | } | |
220 | ||
794dd120 SH |
221 | static bool is_stopped_nolock(struct lxc_container *c) |
222 | { | |
223 | lxc_state_t s; | |
13f5be62 | 224 | s = lxc_getstate(c->name, c->config_path); |
794dd120 SH |
225 | return (s == STOPPED); |
226 | } | |
227 | ||
72d0e1cb SG |
228 | static bool lxcapi_is_running(struct lxc_container *c) |
229 | { | |
230 | const char *s; | |
231 | ||
232 | if (!c) | |
233 | return false; | |
234 | s = lxcapi_state(c); | |
235 | if (!s || strcmp(s, "STOPPED") == 0) | |
236 | return false; | |
237 | return true; | |
238 | } | |
239 | ||
240 | static bool lxcapi_freeze(struct lxc_container *c) | |
241 | { | |
242 | int ret; | |
243 | if (!c) | |
244 | return false; | |
245 | ||
246 | if (lxclock(c->slock, 0)) | |
247 | return false; | |
9123e471 | 248 | ret = lxc_freeze(c->name, c->config_path); |
72d0e1cb SG |
249 | lxcunlock(c->slock); |
250 | if (ret) | |
251 | return false; | |
252 | return true; | |
253 | } | |
254 | ||
255 | static bool lxcapi_unfreeze(struct lxc_container *c) | |
256 | { | |
257 | int ret; | |
258 | if (!c) | |
259 | return false; | |
260 | ||
261 | if (lxclock(c->slock, 0)) | |
262 | return false; | |
9123e471 | 263 | ret = lxc_unfreeze(c->name, c->config_path); |
72d0e1cb SG |
264 | lxcunlock(c->slock); |
265 | if (ret) | |
266 | return false; | |
267 | return true; | |
268 | } | |
269 | ||
270 | static pid_t lxcapi_init_pid(struct lxc_container *c) | |
271 | { | |
272 | pid_t ret; | |
273 | if (!c) | |
274 | return -1; | |
275 | ||
276 | if (lxclock(c->slock, 0)) | |
277 | return -1; | |
13f5be62 | 278 | ret = get_init_pid(c->name, c->config_path); |
72d0e1cb SG |
279 | lxcunlock(c->slock); |
280 | return ret; | |
281 | } | |
282 | ||
12a50cc6 | 283 | static bool load_config_locked(struct lxc_container *c, const char *fname) |
8eb5694b SH |
284 | { |
285 | if (!c->lxc_conf) | |
286 | c->lxc_conf = lxc_conf_init(); | |
287 | if (c->lxc_conf && !lxc_config_read(fname, c->lxc_conf)) | |
288 | return true; | |
289 | return false; | |
290 | } | |
291 | ||
12a50cc6 | 292 | static bool lxcapi_load_config(struct lxc_container *c, const char *alt_file) |
72d0e1cb SG |
293 | { |
294 | bool ret = false; | |
12a50cc6 | 295 | const char *fname; |
72d0e1cb SG |
296 | if (!c) |
297 | return false; | |
298 | ||
299 | fname = c->configfile; | |
300 | if (alt_file) | |
301 | fname = alt_file; | |
302 | if (!fname) | |
303 | return false; | |
304 | if (lxclock(c->slock, 0)) | |
305 | return false; | |
8eb5694b | 306 | ret = load_config_locked(c, fname); |
72d0e1cb SG |
307 | lxcunlock(c->slock); |
308 | return ret; | |
309 | } | |
310 | ||
311 | static void lxcapi_want_daemonize(struct lxc_container *c) | |
312 | { | |
313 | if (!c) | |
314 | return; | |
315 | c->daemonize = 1; | |
316 | } | |
317 | ||
12a50cc6 | 318 | static bool lxcapi_wait(struct lxc_container *c, const char *state, int timeout) |
7a44c8b4 SG |
319 | { |
320 | int ret; | |
321 | ||
322 | if (!c) | |
323 | return false; | |
324 | ||
67e571de | 325 | ret = lxc_wait(c->name, state, timeout, c->config_path); |
7a44c8b4 SG |
326 | return ret == 0; |
327 | } | |
328 | ||
329 | ||
330 | static bool wait_on_daemonized_start(struct lxc_container *c) | |
331 | { | |
332 | /* we'll probably want to make this timeout configurable? */ | |
697fa639 | 333 | int timeout = 5, ret, status; |
7a44c8b4 | 334 | |
697fa639 SH |
335 | /* |
336 | * our child is going to fork again, then exit. reap the | |
337 | * child | |
338 | */ | |
339 | ret = wait(&status); | |
340 | if (ret == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) | |
341 | DEBUG("failed waiting for first dual-fork child"); | |
7a44c8b4 SG |
342 | return lxcapi_wait(c, "RUNNING", timeout); |
343 | } | |
344 | ||
72d0e1cb SG |
345 | /* |
346 | * I can't decide if it'd be more convenient for callers if we accept '...', | |
347 | * or a null-terminated array (i.e. execl vs execv) | |
348 | */ | |
12a50cc6 | 349 | static bool lxcapi_start(struct lxc_container *c, int useinit, char * const argv[]) |
72d0e1cb SG |
350 | { |
351 | int ret; | |
352 | struct lxc_conf *conf; | |
353 | int daemonize = 0; | |
354 | char *default_args[] = { | |
355 | "/sbin/init", | |
356 | '\0', | |
357 | }; | |
358 | ||
359 | /* container exists */ | |
360 | if (!c) | |
361 | return false; | |
362 | /* container has been setup */ | |
363 | if (!c->lxc_conf) | |
364 | return false; | |
365 | ||
366 | /* is this app meant to be run through lxcinit, as in lxc-execute? */ | |
367 | if (useinit && !argv) | |
368 | return false; | |
369 | ||
370 | if (lxclock(c->privlock, 0)) | |
371 | return false; | |
372 | conf = c->lxc_conf; | |
373 | daemonize = c->daemonize; | |
374 | lxcunlock(c->privlock); | |
375 | ||
376 | if (useinit) { | |
13f5be62 | 377 | ret = lxc_execute(c->name, argv, 1, conf, c->config_path); |
72d0e1cb SG |
378 | return ret == 0 ? true : false; |
379 | } | |
380 | ||
381 | if (!argv) | |
382 | argv = default_args; | |
383 | ||
384 | /* | |
385 | * say, I'm not sure - what locks do we want here? Any? | |
386 | * Is liblxc's locking enough here to protect the on disk | |
387 | * container? We don't want to exclude things like lxc_info | |
388 | * while container is running... | |
389 | */ | |
390 | if (daemonize) { | |
391 | if (!lxc_container_get(c)) | |
392 | return false; | |
e51d4895 | 393 | lxc_monitord_spawn(c->config_path); |
72d0e1cb SG |
394 | pid_t pid = fork(); |
395 | if (pid < 0) { | |
396 | lxc_container_put(c); | |
397 | return false; | |
398 | } | |
399 | if (pid != 0) | |
7a44c8b4 | 400 | return wait_on_daemonized_start(c); |
697fa639 SH |
401 | /* second fork to be reparented by init */ |
402 | pid = fork(); | |
403 | if (pid < 0) { | |
404 | SYSERROR("Error doing dual-fork"); | |
405 | return false; | |
406 | } | |
407 | if (pid != 0) | |
408 | exit(0); | |
72d0e1cb | 409 | /* like daemon(), chdir to / and redirect 0,1,2 to /dev/null */ |
c278cef2 SH |
410 | if (chdir("/")) { |
411 | SYSERROR("Error chdir()ing to /."); | |
412 | return false; | |
413 | } | |
72d0e1cb SG |
414 | close(0); |
415 | close(1); | |
416 | close(2); | |
417 | open("/dev/null", O_RDONLY); | |
418 | open("/dev/null", O_RDWR); | |
419 | open("/dev/null", O_RDWR); | |
420 | setsid(); | |
421 | } | |
422 | ||
72d0e1cb SG |
423 | reboot: |
424 | conf->reboot = 0; | |
13f5be62 | 425 | ret = lxc_start(c->name, argv, conf, c->config_path); |
72d0e1cb SG |
426 | |
427 | if (conf->reboot) { | |
428 | INFO("container requested reboot"); | |
429 | conf->reboot = 0; | |
72d0e1cb SG |
430 | goto reboot; |
431 | } | |
432 | ||
433 | if (daemonize) { | |
434 | lxc_container_put(c); | |
435 | exit (ret == 0 ? true : false); | |
436 | } else { | |
437 | return (ret == 0 ? true : false); | |
438 | } | |
439 | } | |
440 | ||
441 | /* | |
442 | * note there MUST be an ending NULL | |
443 | */ | |
444 | static bool lxcapi_startl(struct lxc_container *c, int useinit, ...) | |
445 | { | |
446 | va_list ap; | |
447 | char **inargs = NULL, **temp; | |
448 | int n_inargs = 0; | |
449 | bool bret = false; | |
450 | ||
451 | /* container exists */ | |
452 | if (!c) | |
453 | return false; | |
454 | ||
455 | /* build array of arguments if any */ | |
456 | va_start(ap, useinit); | |
457 | while (1) { | |
458 | char *arg; | |
459 | arg = va_arg(ap, char *); | |
460 | if (!arg) | |
461 | break; | |
462 | n_inargs++; | |
463 | temp = realloc(inargs, n_inargs * sizeof(*inargs)); | |
586d4e9b SH |
464 | if (!temp) { |
465 | va_end(ap); | |
72d0e1cb | 466 | goto out; |
586d4e9b | 467 | } |
72d0e1cb SG |
468 | inargs = temp; |
469 | inargs[n_inargs - 1] = strdup(arg); // not sure if it's safe not to copy | |
470 | } | |
471 | va_end(ap); | |
472 | ||
473 | /* add trailing NULL */ | |
474 | if (n_inargs) { | |
475 | n_inargs++; | |
476 | temp = realloc(inargs, n_inargs * sizeof(*inargs)); | |
477 | if (!temp) | |
478 | goto out; | |
479 | inargs = temp; | |
480 | inargs[n_inargs - 1] = NULL; | |
481 | } | |
482 | ||
483 | bret = lxcapi_start(c, useinit, inargs); | |
484 | ||
485 | out: | |
486 | if (inargs) { | |
487 | int i; | |
488 | for (i = 0; i < n_inargs; i++) { | |
489 | if (inargs[i]) | |
490 | free(inargs[i]); | |
491 | } | |
492 | free(inargs); | |
493 | } | |
494 | ||
495 | return bret; | |
496 | } | |
497 | ||
498 | static bool lxcapi_stop(struct lxc_container *c) | |
499 | { | |
500 | int ret; | |
501 | ||
502 | if (!c) | |
503 | return false; | |
504 | ||
13f5be62 | 505 | ret = lxc_stop(c->name, c->config_path); |
72d0e1cb SG |
506 | |
507 | return ret == 0; | |
72d0e1cb SG |
508 | } |
509 | ||
510 | static bool valid_template(char *t) | |
511 | { | |
512 | struct stat statbuf; | |
513 | int statret; | |
514 | ||
515 | statret = stat(t, &statbuf); | |
516 | if (statret == 0) | |
517 | return true; | |
518 | return false; | |
519 | } | |
520 | ||
521 | /* | |
522 | * create the standard expected container dir | |
523 | */ | |
524 | static bool create_container_dir(struct lxc_container *c) | |
525 | { | |
526 | char *s; | |
527 | int len, ret; | |
528 | ||
2a59a681 | 529 | len = strlen(c->config_path) + strlen(c->name) + 2; |
72d0e1cb SG |
530 | s = malloc(len); |
531 | if (!s) | |
532 | return false; | |
2a59a681 | 533 | ret = snprintf(s, len, "%s/%s", c->config_path, c->name); |
72d0e1cb SG |
534 | if (ret < 0 || ret >= len) { |
535 | free(s); | |
536 | return false; | |
537 | } | |
538 | ret = mkdir(s, 0755); | |
539 | if (ret) { | |
540 | if (errno == EEXIST) | |
541 | ret = 0; | |
542 | else | |
543 | SYSERROR("failed to create container path for %s\n", c->name); | |
544 | } | |
545 | free(s); | |
546 | return ret == 0; | |
547 | } | |
548 | ||
549 | /* | |
550 | * backing stores not (yet) supported | |
551 | * for ->create, argv contains the arguments to pass to the template, | |
552 | * terminated by NULL. If no arguments, you can just pass NULL. | |
553 | */ | |
12a50cc6 | 554 | static bool lxcapi_create(struct lxc_container *c, char *t, char *const argv[]) |
72d0e1cb SG |
555 | { |
556 | bool bret = false; | |
557 | pid_t pid; | |
9be53773 SH |
558 | char *tpath = NULL, **newargv; |
559 | int ret, len, nargs = 0; | |
72d0e1cb SG |
560 | |
561 | if (!c) | |
562 | return false; | |
563 | ||
564 | len = strlen(LXCTEMPLATEDIR) + strlen(t) + strlen("/lxc-") + 1; | |
565 | tpath = malloc(len); | |
566 | if (!tpath) | |
567 | return false; | |
568 | ret = snprintf(tpath, len, "%s/lxc-%s", LXCTEMPLATEDIR, t); | |
569 | if (ret < 0 || ret >= len) | |
570 | goto out; | |
571 | if (!valid_template(tpath)) { | |
572 | ERROR("bad template: %s\n", t); | |
573 | goto out; | |
574 | } | |
575 | ||
72d0e1cb SG |
576 | if (!c->save_config(c, NULL)) { |
577 | ERROR("failed to save starting configuration for %s\n", c->name); | |
578 | goto out; | |
579 | } | |
580 | ||
5a3d2e1e | 581 | /* container is already created if we have a config and rootfs.path is accessible */ |
e51d4895 | 582 | if (lxcapi_is_defined(c) && c->lxc_conf && c->lxc_conf->rootfs.path && access(c->lxc_conf->rootfs.path, F_OK) == 0) |
a741a85d | 583 | goto out; |
5a3d2e1e | 584 | |
72d0e1cb | 585 | /* we're going to fork. but since we'll wait for our child, we |
9be53773 | 586 | * don't need to lxc_container_get */ |
72d0e1cb SG |
587 | |
588 | if (lxclock(c->slock, 0)) { | |
589 | ERROR("failed to grab global container lock for %s\n", c->name); | |
590 | goto out; | |
591 | } | |
592 | ||
593 | pid = fork(); | |
594 | if (pid < 0) { | |
595 | SYSERROR("failed to fork task for container creation template\n"); | |
596 | goto out_unlock; | |
597 | } | |
598 | ||
599 | if (pid == 0) { // child | |
600 | char *patharg, *namearg; | |
601 | int i; | |
602 | ||
603 | close(0); | |
604 | close(1); | |
605 | close(2); | |
606 | open("/dev/null", O_RDONLY); | |
607 | open("/dev/null", O_RDWR); | |
608 | open("/dev/null", O_RDWR); | |
609 | ||
610 | /* | |
611 | * create our new array, pre-pend the template name and | |
612 | * base args | |
613 | */ | |
614 | if (argv) | |
615 | for (; argv[nargs]; nargs++) ; | |
616 | nargs += 3; // template, path and name args | |
617 | newargv = malloc(nargs * sizeof(*newargv)); | |
618 | if (!newargv) | |
619 | exit(1); | |
620 | newargv[0] = t; | |
621 | ||
2a59a681 | 622 | len = strlen(c->config_path) + strlen(c->name) + strlen("--path=") + 2; |
72d0e1cb SG |
623 | patharg = malloc(len); |
624 | if (!patharg) | |
625 | exit(1); | |
2a59a681 | 626 | ret = snprintf(patharg, len, "--path=%s/%s", c->config_path, c->name); |
72d0e1cb SG |
627 | if (ret < 0 || ret >= len) |
628 | exit(1); | |
629 | newargv[1] = patharg; | |
630 | len = strlen("--name=") + strlen(c->name) + 1; | |
631 | namearg = malloc(len); | |
632 | if (!namearg) | |
633 | exit(1); | |
634 | ret = snprintf(namearg, len, "--name=%s", c->name); | |
635 | if (ret < 0 || ret >= len) | |
636 | exit(1); | |
637 | newargv[2] = namearg; | |
638 | ||
639 | /* add passed-in args */ | |
640 | if (argv) | |
641 | for (i = 3; i < nargs; i++) | |
642 | newargv[i] = argv[i-3]; | |
643 | ||
644 | /* add trailing NULL */ | |
645 | nargs++; | |
646 | newargv = realloc(newargv, nargs * sizeof(*newargv)); | |
647 | if (!newargv) | |
648 | exit(1); | |
649 | newargv[nargs - 1] = NULL; | |
650 | ||
651 | /* execute */ | |
e6a19d26 | 652 | execv(tpath, newargv); |
72d0e1cb SG |
653 | SYSERROR("failed to execute template %s", tpath); |
654 | exit(1); | |
655 | } | |
656 | ||
9be53773 SH |
657 | if (wait_for_pid(pid) != 0) { |
658 | ERROR("container creation template for %s failed\n", c->name); | |
8eb5694b SH |
659 | goto out_unlock; |
660 | } | |
661 | ||
662 | // now clear out the lxc_conf we have, reload from the created | |
663 | // container | |
664 | if (c->lxc_conf) | |
665 | lxc_conf_free(c->lxc_conf); | |
666 | c->lxc_conf = NULL; | |
667 | bret = load_config_locked(c, c->configfile); | |
72d0e1cb SG |
668 | |
669 | out_unlock: | |
670 | lxcunlock(c->slock); | |
671 | out: | |
672 | if (tpath) | |
673 | free(tpath); | |
674 | return bret; | |
675 | } | |
676 | ||
677 | static bool lxcapi_shutdown(struct lxc_container *c, int timeout) | |
678 | { | |
679 | bool retv; | |
680 | pid_t pid; | |
681 | ||
682 | if (!c) | |
683 | return false; | |
684 | ||
685 | if (!timeout) | |
686 | timeout = -1; | |
687 | if (!c->is_running(c)) | |
688 | return true; | |
689 | pid = c->init_pid(c); | |
690 | if (pid <= 0) | |
691 | return true; | |
692 | kill(pid, SIGPWR); | |
693 | retv = c->wait(c, "STOPPED", timeout); | |
f6144ed4 | 694 | if (!retv && timeout > 0) { |
72d0e1cb SG |
695 | c->stop(c); |
696 | retv = c->wait(c, "STOPPED", 0); // 0 means don't wait | |
697 | } | |
698 | return retv; | |
699 | } | |
700 | ||
701 | static bool lxcapi_createl(struct lxc_container *c, char *t, ...) | |
702 | { | |
703 | bool bret = false; | |
704 | char **args = NULL, **temp; | |
705 | va_list ap; | |
706 | int nargs = 0; | |
707 | ||
708 | if (!c) | |
709 | return false; | |
710 | ||
711 | /* | |
712 | * since we're going to wait for create to finish, I don't think we | |
713 | * need to get a copy of the arguments. | |
714 | */ | |
715 | va_start(ap, t); | |
716 | while (1) { | |
717 | char *arg; | |
718 | arg = va_arg(ap, char *); | |
719 | if (!arg) | |
720 | break; | |
721 | nargs++; | |
83cab6e0 | 722 | temp = realloc(args, (nargs+1) * sizeof(*args)); |
41670788 SH |
723 | if (!temp) { |
724 | va_end(ap); | |
72d0e1cb | 725 | goto out; |
41670788 | 726 | } |
72d0e1cb SG |
727 | args = temp; |
728 | args[nargs - 1] = arg; | |
729 | } | |
730 | va_end(ap); | |
63e414f8 SH |
731 | if (args) |
732 | args[nargs] = NULL; | |
72d0e1cb SG |
733 | |
734 | bret = c->create(c, t, args); | |
735 | ||
736 | out: | |
737 | if (args) | |
738 | free(args); | |
739 | return bret; | |
740 | } | |
741 | ||
12a50cc6 | 742 | static bool lxcapi_clear_config_item(struct lxc_container *c, const char *key) |
72d0e1cb SG |
743 | { |
744 | int ret; | |
745 | ||
746 | if (!c || !c->lxc_conf) | |
747 | return false; | |
748 | if (lxclock(c->privlock, 0)) { | |
749 | return false; | |
750 | } | |
751 | ret = lxc_clear_config_item(c->lxc_conf, key); | |
752 | lxcunlock(c->privlock); | |
753 | return ret == 0; | |
754 | } | |
755 | ||
12a50cc6 | 756 | static int lxcapi_get_config_item(struct lxc_container *c, const char *key, char *retv, int inlen) |
72d0e1cb SG |
757 | { |
758 | int ret; | |
759 | ||
760 | if (!c || !c->lxc_conf) | |
761 | return -1; | |
762 | if (lxclock(c->privlock, 0)) { | |
763 | return -1; | |
764 | } | |
765 | ret = lxc_get_config_item(c->lxc_conf, key, retv, inlen); | |
766 | lxcunlock(c->privlock); | |
767 | return ret; | |
768 | } | |
769 | ||
12a50cc6 | 770 | static int lxcapi_get_keys(struct lxc_container *c, const char *key, char *retv, int inlen) |
72d0e1cb SG |
771 | { |
772 | if (!key) | |
773 | return lxc_listconfigs(retv, inlen); | |
774 | /* | |
775 | * Support 'lxc.network.<idx>', i.e. 'lxc.network.0' | |
776 | * This is an intelligent result to show which keys are valid given | |
777 | * the type of nic it is | |
778 | */ | |
779 | if (!c || !c->lxc_conf) | |
780 | return -1; | |
781 | if (lxclock(c->privlock, 0)) | |
782 | return -1; | |
783 | int ret = -1; | |
784 | if (strncmp(key, "lxc.network.", 12) == 0) | |
785 | ret = lxc_list_nicconfigs(c->lxc_conf, key, retv, inlen); | |
786 | lxcunlock(c->privlock); | |
787 | return ret; | |
788 | } | |
789 | ||
790 | ||
791 | /* default config file - should probably come through autoconf */ | |
bb9702b5 | 792 | #define LXC_DEFAULT_CONFIG "/etc/lxc/default.conf" |
12a50cc6 | 793 | static bool lxcapi_save_config(struct lxc_container *c, const char *alt_file) |
72d0e1cb SG |
794 | { |
795 | if (!alt_file) | |
796 | alt_file = c->configfile; | |
797 | if (!alt_file) | |
798 | return false; // should we write to stdout if no file is specified? | |
799 | if (!c->lxc_conf) | |
800 | if (!c->load_config(c, LXC_DEFAULT_CONFIG)) { | |
801 | ERROR("Error loading default configuration file %s while saving %s\n", LXC_DEFAULT_CONFIG, c->name); | |
802 | return false; | |
803 | } | |
804 | ||
5a3d2e1e SG |
805 | if (!create_container_dir(c)) |
806 | return false; | |
807 | ||
72d0e1cb SG |
808 | FILE *fout = fopen(alt_file, "w"); |
809 | if (!fout) | |
810 | return false; | |
811 | if (lxclock(c->privlock, 0)) { | |
812 | fclose(fout); | |
813 | return false; | |
814 | } | |
815 | write_config(fout, c->lxc_conf); | |
816 | fclose(fout); | |
817 | lxcunlock(c->privlock); | |
818 | return true; | |
819 | } | |
820 | ||
821 | static bool lxcapi_destroy(struct lxc_container *c) | |
822 | { | |
823 | pid_t pid; | |
72d0e1cb SG |
824 | |
825 | if (!c) | |
826 | return false; | |
827 | ||
5a3d2e1e | 828 | /* container is already destroyed if we don't have a config and rootfs.path is not accessible */ |
e51d4895 | 829 | if (!lxcapi_is_defined(c) && (!c->lxc_conf || !c->lxc_conf->rootfs.path || access(c->lxc_conf->rootfs.path, F_OK) != 0)) |
5a3d2e1e SG |
830 | return false; |
831 | ||
72d0e1cb SG |
832 | pid = fork(); |
833 | if (pid < 0) | |
834 | return false; | |
835 | if (pid == 0) { // child | |
e6a19d26 | 836 | execlp("lxc-destroy", "lxc-destroy", "-n", c->name, "-P", c->config_path, NULL); |
72d0e1cb SG |
837 | perror("execl"); |
838 | exit(1); | |
839 | } | |
840 | ||
9be53773 SH |
841 | if (wait_for_pid(pid) < 0) { |
842 | ERROR("Error destroying container %s", c->name); | |
72d0e1cb SG |
843 | return false; |
844 | } | |
845 | ||
9be53773 | 846 | return true; |
72d0e1cb SG |
847 | } |
848 | ||
12a50cc6 | 849 | static bool lxcapi_set_config_item(struct lxc_container *c, const char *key, const char *v) |
72d0e1cb SG |
850 | { |
851 | int ret; | |
852 | bool b = false; | |
853 | struct lxc_config_t *config; | |
854 | ||
855 | if (!c) | |
856 | return false; | |
857 | ||
858 | if (lxclock(c->privlock, 0)) | |
859 | return false; | |
860 | ||
861 | if (!c->lxc_conf) | |
862 | c->lxc_conf = lxc_conf_init(); | |
863 | if (!c->lxc_conf) | |
864 | goto err; | |
865 | config = lxc_getconfig(key); | |
866 | if (!config) | |
867 | goto err; | |
868 | ret = config->cb(key, v, c->lxc_conf); | |
869 | if (!ret) | |
870 | b = true; | |
871 | ||
872 | err: | |
873 | lxcunlock(c->privlock); | |
874 | return b; | |
875 | } | |
876 | ||
877 | static char *lxcapi_config_file_name(struct lxc_container *c) | |
878 | { | |
879 | if (!c || !c->configfile) | |
880 | return NULL; | |
881 | return strdup(c->configfile); | |
882 | } | |
883 | ||
2a59a681 SH |
884 | static const char *lxcapi_get_config_path(struct lxc_container *c) |
885 | { | |
886 | if (!c || !c->config_path) | |
887 | return NULL; | |
888 | return (const char *)(c->config_path); | |
889 | } | |
890 | ||
afeecbba SH |
891 | /* |
892 | * not for export | |
893 | * Just recalculate the c->configfile based on the | |
894 | * c->config_path, which must be set. | |
895 | * The lxc_container must be locked or not yet public. | |
896 | */ | |
897 | static bool set_config_filename(struct lxc_container *c) | |
898 | { | |
899 | char *newpath; | |
900 | int len, ret; | |
901 | ||
902 | if (!c->config_path) | |
903 | return false; | |
904 | ||
905 | /* $lxc_path + "/" + c->name + "/" + "config" + '\0' */ | |
906 | len = strlen(c->config_path) + strlen(c->name) + strlen("config") + 3; | |
907 | newpath = malloc(len); | |
908 | if (!newpath) | |
909 | return false; | |
910 | ||
911 | ret = snprintf(newpath, len, "%s/%s/config", c->config_path, c->name); | |
912 | if (ret < 0 || ret >= len) { | |
913 | fprintf(stderr, "Error printing out config file name\n"); | |
914 | free(newpath); | |
915 | return false; | |
916 | } | |
917 | ||
918 | if (c->configfile) | |
919 | free(c->configfile); | |
920 | c->configfile = newpath; | |
921 | ||
922 | return true; | |
923 | } | |
924 | ||
2a59a681 SH |
925 | static bool lxcapi_set_config_path(struct lxc_container *c, const char *path) |
926 | { | |
927 | char *p; | |
928 | bool b = false; | |
afeecbba | 929 | char *oldpath = NULL; |
2a59a681 SH |
930 | |
931 | if (!c) | |
932 | return b; | |
933 | ||
934 | if (lxclock(c->privlock, 0)) | |
935 | return b; | |
936 | ||
937 | p = strdup(path); | |
afeecbba SH |
938 | if (!p) { |
939 | ERROR("Out of memory setting new lxc path"); | |
2a59a681 | 940 | goto err; |
afeecbba SH |
941 | } |
942 | ||
2a59a681 SH |
943 | b = true; |
944 | if (c->config_path) | |
afeecbba | 945 | oldpath = c->config_path; |
2a59a681 | 946 | c->config_path = p; |
afeecbba SH |
947 | |
948 | /* Since we've changed the config path, we have to change the | |
949 | * config file name too */ | |
950 | if (!set_config_filename(c)) { | |
951 | ERROR("Out of memory setting new config filename"); | |
952 | b = false; | |
953 | free(c->config_path); | |
954 | c->config_path = oldpath; | |
955 | oldpath = NULL; | |
956 | } | |
2a59a681 | 957 | err: |
afeecbba SH |
958 | if (oldpath) |
959 | free(oldpath); | |
2a59a681 SH |
960 | lxcunlock(c->privlock); |
961 | return b; | |
962 | } | |
963 | ||
964 | ||
794dd120 SH |
965 | static bool lxcapi_set_cgroup_item(struct lxc_container *c, const char *subsys, const char *value) |
966 | { | |
967 | int ret; | |
968 | bool b = false; | |
969 | ||
970 | if (!c) | |
971 | return false; | |
972 | ||
973 | if (lxclock(c->privlock, 0)) | |
974 | return false; | |
975 | ||
976 | if (is_stopped_nolock(c)) | |
977 | goto err; | |
978 | ||
ae5c8b8e | 979 | ret = lxc_cgroup_set(c->name, subsys, value, c->config_path); |
794dd120 SH |
980 | if (!ret) |
981 | b = true; | |
982 | err: | |
983 | lxcunlock(c->privlock); | |
984 | return b; | |
985 | } | |
986 | ||
987 | static int lxcapi_get_cgroup_item(struct lxc_container *c, const char *subsys, char *retv, int inlen) | |
988 | { | |
989 | int ret = -1; | |
990 | ||
991 | if (!c || !c->lxc_conf) | |
992 | return -1; | |
993 | ||
994 | if (lxclock(c->privlock, 0)) | |
995 | return -1; | |
996 | ||
997 | if (is_stopped_nolock(c)) | |
998 | goto out; | |
999 | ||
ae5c8b8e | 1000 | ret = lxc_cgroup_get(c->name, subsys, retv, inlen, c->config_path); |
794dd120 SH |
1001 | |
1002 | out: | |
1003 | lxcunlock(c->privlock); | |
1004 | return ret; | |
1005 | } | |
1006 | ||
67e571de | 1007 | const char *lxc_get_default_config_path(void) |
83c98d82 DE |
1008 | { |
1009 | return default_lxc_path(); | |
1010 | } | |
794dd120 | 1011 | |
a8428dfa SH |
1012 | const char *lxc_get_default_lvm_vg(void) |
1013 | { | |
1014 | return default_lvm_vg(); | |
1015 | } | |
1016 | ||
1017 | const char *lxc_get_default_zfs_root(void) | |
1018 | { | |
1019 | return default_zfs_root(); | |
1020 | } | |
1021 | ||
b6b918a1 SG |
1022 | const char *lxc_get_version(void) |
1023 | { | |
1024 | return lxc_version(); | |
1025 | } | |
1026 | ||
9be53773 SH |
1027 | static int copy_file(char *old, char *new) |
1028 | { | |
1029 | int in, out; | |
1030 | ssize_t len, ret; | |
1031 | char buf[8096]; | |
1032 | struct stat sbuf; | |
1033 | ||
1034 | if (file_exists(new)) { | |
1035 | ERROR("copy destination %s exists", new); | |
1036 | return -1; | |
1037 | } | |
1038 | ret = stat(old, &sbuf); | |
1039 | if (ret < 0) { | |
1040 | SYSERROR("stat'ing %s", old); | |
1041 | return -1; | |
1042 | } | |
1043 | ||
1044 | in = open(old, O_RDONLY); | |
1045 | if (in < 0) { | |
1046 | SYSERROR("opening original file %s", old); | |
1047 | return -1; | |
1048 | } | |
1049 | out = open(new, O_CREAT | O_EXCL | O_WRONLY, 0644); | |
1050 | if (out < 0) { | |
1051 | SYSERROR("opening new file %s", new); | |
1052 | close(in); | |
1053 | return -1; | |
1054 | } | |
1055 | ||
1056 | while (1) { | |
1057 | len = read(in, buf, 8096); | |
1058 | if (len < 0) { | |
1059 | SYSERROR("reading old file %s", old); | |
1060 | goto err; | |
1061 | } | |
1062 | if (len == 0) | |
1063 | break; | |
1064 | ret = write(out, buf, len); | |
1065 | if (ret < len) { // should we retry? | |
1066 | SYSERROR("write to new file %s was interrupted", new); | |
1067 | goto err; | |
1068 | } | |
1069 | } | |
1070 | close(in); | |
1071 | close(out); | |
1072 | ||
1073 | // we set mode, but not owner/group | |
1074 | ret = chmod(new, sbuf.st_mode); | |
1075 | if (ret) { | |
1076 | SYSERROR("setting mode on %s", new); | |
1077 | return -1; | |
1078 | } | |
1079 | ||
1080 | return 0; | |
1081 | ||
1082 | err: | |
1083 | close(in); | |
1084 | close(out); | |
1085 | return -1; | |
1086 | } | |
1087 | ||
1088 | /* | |
1089 | * we're being passed result of two strstrs(x, y). We want to write | |
1090 | * all data up to the first found string, or to end of the string if | |
1091 | * neither string was found. | |
1092 | * This function will return the earliest found string if any, or else | |
1093 | * NULL | |
1094 | */ | |
1095 | static const char *lowest_nonnull(const char *p1, const char *p2) | |
1096 | { | |
1097 | if (!p1) | |
1098 | return p2; | |
1099 | if (!p2) | |
1100 | return p1; | |
1101 | return p1 < p2 ? p1 : p2; | |
1102 | } | |
1103 | ||
1104 | static int is_word_sep(char c) | |
1105 | { | |
1106 | switch(c) { | |
1107 | case '\0': | |
1108 | case '\n': | |
1109 | case '\r': | |
1110 | case '\t': | |
1111 | case ' ': | |
1112 | case '=': | |
1113 | case '/': | |
1114 | return 1; | |
1115 | default: return 0; | |
1116 | } | |
1117 | } | |
1118 | ||
1119 | static const char *find_first_wholeword(const char *p, const char *word) | |
1120 | { | |
1121 | if (!p) | |
1122 | return NULL; | |
1123 | ||
1124 | while ((p = strstr(p, word)) != NULL) { | |
1125 | if (is_word_sep(*(p-1)) && is_word_sep(p[strlen(word)])) | |
1126 | return p; | |
1127 | p++; | |
1128 | } | |
1129 | return NULL; | |
1130 | } | |
1131 | ||
1132 | static int update_name_and_paths(const char *path, struct lxc_container *oldc, | |
1133 | const char *newname, const char *newpath) | |
1134 | { | |
1135 | FILE *f; | |
1136 | size_t flen; | |
1137 | char *contents; | |
1138 | const char *p0, *p1, *p2, *end; | |
1139 | const char *oldpath = oldc->get_config_path(oldc); | |
1140 | const char *oldname = oldc->name; | |
1141 | ||
1142 | f = fopen(path, "r"); | |
1143 | if (!f) { | |
1144 | SYSERROR("opening old config"); | |
1145 | return -1; | |
1146 | } | |
1147 | if (fseek(f, 0, SEEK_END) < 0) { | |
1148 | SYSERROR("seeking to end of old config"); | |
1149 | fclose(f); | |
1150 | return -1; | |
1151 | } | |
1152 | flen = ftell(f); | |
1153 | if (flen < 0) { | |
1154 | fclose(f); | |
1155 | SYSERROR("telling size of old config"); | |
1156 | return -1; | |
1157 | } | |
1158 | if (fseek(f, 0, SEEK_SET) < 0) { | |
1159 | fclose(f); | |
1160 | SYSERROR("rewinding old config"); | |
1161 | return -1; | |
1162 | } | |
1163 | contents = malloc(flen); | |
1164 | if (!contents) { | |
1165 | SYSERROR("out of memory"); | |
1166 | fclose(f); | |
1167 | } | |
1168 | if (fread(contents, 1, flen, f) != flen) { | |
1169 | free(contents); | |
1170 | fclose(f); | |
1171 | SYSERROR("reading old config"); | |
1172 | return -1; | |
1173 | } | |
1174 | if (fclose(f) < 0) { | |
1175 | free(contents); | |
1176 | SYSERROR("closing old config"); | |
1177 | return -1; | |
1178 | } | |
1179 | ||
1180 | f = fopen(path, "w"); | |
1181 | if (!f) { | |
1182 | SYSERROR("reopening config"); | |
1183 | free(contents); | |
1184 | return -1; | |
1185 | } | |
1186 | ||
1187 | p0 = contents; | |
1188 | end = contents + flen; | |
1189 | while (1) { | |
1190 | p1 = find_first_wholeword(p0, oldpath); | |
1191 | p2 = find_first_wholeword(p0, oldname); | |
1192 | if (!p1 && !p2) { | |
1193 | // write the rest and be done | |
1194 | if (fwrite(p0, 1, (end-p0), f) != (end-p0)) { | |
1195 | SYSERROR("writing new config"); | |
1196 | free(contents); | |
1197 | fclose(f); | |
1198 | return -1; | |
1199 | } | |
1200 | free(contents); | |
1201 | fclose(f); | |
1202 | // success | |
1203 | return 0; | |
1204 | } else { | |
1205 | const char *p = lowest_nonnull(p1, p2); | |
1206 | const char *new = (p == p2) ? newname : newpath; | |
1207 | if (fwrite(p0, 1, (p-p0), f) != (p-p0)) { | |
1208 | SYSERROR("writing new config"); | |
1209 | free(contents); | |
1210 | fclose(f); | |
1211 | return -1; | |
1212 | } | |
1213 | p0 = p; | |
1214 | // now write the newpath or newname | |
1215 | if (fwrite(new, 1, strlen(new), f) != strlen(new)) { | |
1216 | SYSERROR("writing new name or path in new config"); | |
1217 | free(contents); | |
1218 | fclose(f); | |
1219 | return -1; | |
1220 | } | |
1221 | p0 += (p == p2) ? strlen(oldname) : strlen(oldpath); | |
1222 | } | |
1223 | } | |
1224 | } | |
1225 | ||
1226 | static int copyhooks(struct lxc_container *oldc, struct lxc_container *c) | |
1227 | { | |
1228 | int i; | |
1229 | int ret; | |
1230 | struct lxc_list *it; | |
1231 | ||
1232 | for (i=0; i<NUM_LXC_HOOKS; i++) { | |
1233 | lxc_list_for_each(it, &c->lxc_conf->hooks[i]) { | |
1234 | char *hookname = it->elem; | |
1235 | char *fname = rindex(hookname, '/'); | |
1236 | char tmppath[MAXPATHLEN]; | |
1237 | if (!fname) // relative path - we don't support, but maybe we should | |
1238 | return 0; | |
1239 | // copy the script, and change the entry in confile | |
1240 | ret = snprintf(tmppath, MAXPATHLEN, "%s/%s/%s", | |
1241 | c->config_path, c->name, fname+1); | |
1242 | if (ret < 0 || ret >= MAXPATHLEN) | |
1243 | return -1; | |
1244 | ret = copy_file(it->elem, tmppath); | |
1245 | if (ret < 0) | |
1246 | return -1; | |
1247 | free(it->elem); | |
1248 | it->elem = strdup(tmppath); | |
1249 | if (!it->elem) { | |
1250 | ERROR("out of memory copying hook path"); | |
1251 | return -1; | |
1252 | } | |
1253 | update_name_and_paths(it->elem, oldc, c->name, c->get_config_path(c)); | |
1254 | } | |
1255 | } | |
1256 | ||
1257 | c->save_config(c, NULL); | |
1258 | return 0; | |
1259 | } | |
1260 | ||
1261 | static void new_hwaddr(char *hwaddr) | |
1262 | { | |
1263 | FILE *f = fopen("/dev/urandom", "r"); | |
1264 | if (f) { | |
1265 | unsigned int seed; | |
1266 | int ret = fread(&seed, sizeof(seed), 1, f); | |
1267 | if (ret != 1) | |
1268 | seed = time(NULL); | |
1269 | fclose(f); | |
1270 | srand(seed); | |
1271 | } else | |
1272 | srand(time(NULL)); | |
1273 | snprintf(hwaddr, 18, "00:16:3e:%02x:%02x:%02x", | |
1274 | rand() % 255, rand() % 255, rand() % 255); | |
1275 | } | |
1276 | ||
1277 | static void network_new_hwaddrs(struct lxc_container *c) | |
1278 | { | |
1279 | struct lxc_list *it; | |
1280 | ||
1281 | lxc_list_for_each(it, &c->lxc_conf->network) { | |
1282 | struct lxc_netdev *n = it->elem; | |
1283 | if (n->hwaddr) | |
1284 | new_hwaddr(n->hwaddr); | |
1285 | } | |
1286 | } | |
1287 | ||
1288 | static int copy_fstab(struct lxc_container *oldc, struct lxc_container *c) | |
1289 | { | |
1290 | char newpath[MAXPATHLEN]; | |
1291 | char *oldpath = oldc->lxc_conf->fstab; | |
1292 | int ret; | |
1293 | ||
1294 | if (!oldpath) | |
1295 | return 0; | |
1296 | ||
1297 | char *p = rindex(oldpath, '/'); | |
1298 | if (!p) | |
1299 | return -1; | |
1300 | ret = snprintf(newpath, MAXPATHLEN, "%s/%s%s", | |
1301 | c->config_path, c->name, p); | |
1302 | if (ret < 0 || ret >= MAXPATHLEN) { | |
1303 | ERROR("error printing new path for %s", oldpath); | |
1304 | return -1; | |
1305 | } | |
1306 | if (file_exists(newpath)) { | |
1307 | ERROR("error: fstab file %s exists", newpath); | |
1308 | return -1; | |
1309 | } | |
1310 | ||
1311 | if (copy_file(oldpath, newpath) < 0) { | |
1312 | ERROR("error: copying %s to %s", oldpath, newpath); | |
1313 | return -1; | |
1314 | } | |
1315 | free(c->lxc_conf->fstab); | |
1316 | c->lxc_conf->fstab = strdup(newpath); | |
1317 | if (!c->lxc_conf->fstab) { | |
1318 | ERROR("error: allocating pathname"); | |
1319 | return -1; | |
1320 | } | |
1321 | ||
1322 | return 0; | |
1323 | } | |
1324 | ||
1325 | static int copy_storage(struct lxc_container *c0, struct lxc_container *c, | |
1326 | const char *newtype, int flags, const char *bdevdata, unsigned long newsize) | |
1327 | { | |
1328 | struct bdev *bdev; | |
1329 | ||
1330 | bdev = bdev_copy(c0->lxc_conf->rootfs.path, c0->name, c->name, | |
1331 | c0->config_path, c->config_path, newtype, !!(flags & LXC_CLONE_SNAPSHOT), | |
1332 | bdevdata, newsize); | |
1333 | if (!bdev) { | |
1334 | ERROR("error copying storage"); | |
1335 | return -1; | |
1336 | } | |
1337 | free(c->lxc_conf->rootfs.path); | |
1338 | c->lxc_conf->rootfs.path = strdup(bdev->src); | |
1339 | bdev_put(bdev); | |
1340 | if (!c->lxc_conf->rootfs.path) | |
1341 | return -1; | |
1342 | // here we could also update all lxc.mount.entries or even | |
1343 | // items in the lxc.mount fstab list. As discussed on m-l, | |
1344 | // we could do either any source paths starting with the | |
1345 | // lxcpath/oldname, or simply anythign which is not a virtual | |
1346 | // fs or a bind mount. | |
1347 | return 0; | |
1348 | } | |
1349 | ||
1350 | static int clone_update_rootfs(struct lxc_container *c, int flags) | |
1351 | { | |
1352 | int ret = -1; | |
1353 | char path[MAXPATHLEN]; | |
1354 | struct bdev *bdev; | |
1355 | FILE *fout; | |
1356 | pid_t pid; | |
1357 | ||
1358 | if (flags & LXC_CLONE_KEEPNAME) | |
1359 | return 0; | |
1360 | ||
1361 | /* update hostname in rootfs */ | |
1362 | /* we're going to mount, so run in a clean namespace to simplify cleanup */ | |
1363 | ||
1364 | pid = fork(); | |
1365 | if (pid < 0) | |
1366 | return -1; | |
1367 | if (pid > 0) | |
1368 | return wait_for_pid(pid); | |
1369 | ||
1370 | if (unshare(CLONE_NEWNS) < 0) { | |
1371 | ERROR("error unsharing mounts"); | |
1372 | exit(1); | |
1373 | } | |
1374 | bdev = bdev_init(c->lxc_conf->rootfs.path, c->lxc_conf->rootfs.mount, NULL); | |
1375 | if (!bdev) | |
1376 | exit(1); | |
1377 | if (bdev->ops->mount(bdev) < 0) | |
1378 | exit(1); | |
1379 | ret = snprintf(path, MAXPATHLEN, "%s/etc/hostname", bdev->dest); | |
1380 | if (ret < 0 || ret >= MAXPATHLEN) | |
1381 | exit(1); | |
1382 | if (!(fout = fopen(path, "w"))) { | |
1383 | SYSERROR("unable to open %s: ignoring\n", path); | |
1384 | exit(0); | |
1385 | } | |
1386 | if (fprintf(fout, "%s", c->name) < 0) | |
1387 | exit(1); | |
1388 | if (fclose(fout) < 0) | |
1389 | exit(1); | |
1390 | exit(0); | |
1391 | } | |
1392 | ||
1393 | /* | |
1394 | * We want to support: | |
1395 | sudo lxc-clone -o o1 -n n1 -s -L|-fssize fssize -v|--vgname vgname \ | |
1396 | -p|--lvprefix lvprefix -t|--fstype fstype -B backingstore | |
1397 | ||
1398 | -s [ implies overlayfs] | |
1399 | -s -B overlayfs | |
1400 | -s -B aufs | |
1401 | ||
1402 | only rootfs gets converted (copied/snapshotted) on clone. | |
1403 | */ | |
1404 | ||
1405 | static int create_file_dirname(char *path) | |
1406 | { | |
1407 | char *p = rindex(path, '/'); | |
1408 | int ret; | |
1409 | ||
1410 | if (!p) | |
1411 | return -1; | |
1412 | *p = '\0'; | |
1413 | ret = mkdir(path, 0755); | |
1414 | if (ret && errno != EEXIST) | |
1415 | SYSERROR("creating container path %s\n", path); | |
1416 | *p = '/'; | |
1417 | return ret; | |
1418 | } | |
1419 | ||
1420 | struct lxc_container *lxcapi_clone(struct lxc_container *c, const char *newname, | |
1421 | const char *lxcpath, int flags, | |
1422 | const char *bdevtype, const char *bdevdata, unsigned long newsize) | |
1423 | { | |
1424 | struct lxc_container *c2 = NULL; | |
1425 | char newpath[MAXPATHLEN]; | |
1426 | int ret; | |
1427 | const char *n, *l; | |
1428 | FILE *fout; | |
1429 | ||
1430 | if (!c || !c->is_defined(c)) | |
1431 | return NULL; | |
1432 | ||
1433 | if (lxclock(c->privlock, 0)) | |
1434 | return NULL; | |
1435 | ||
1436 | if (c->is_running(c)) { | |
1437 | ERROR("error: Original container (%s) is running", c->name); | |
1438 | goto out; | |
1439 | } | |
1440 | ||
1441 | // Make sure the container doesn't yet exist. | |
1442 | n = newname ? newname : c->name; | |
1443 | l = lxcpath ? lxcpath : c->get_config_path(c); | |
1444 | ret = snprintf(newpath, MAXPATHLEN, "%s/%s/config", l, n); | |
1445 | if (ret < 0 || ret >= MAXPATHLEN) { | |
1446 | SYSERROR("clone: failed making config pathname"); | |
1447 | goto out; | |
1448 | } | |
1449 | if (file_exists(newpath)) { | |
1450 | ERROR("error: clone: %s exists", newpath); | |
1451 | goto out; | |
1452 | } | |
1453 | ||
1454 | if (create_file_dirname(newpath) < 0) { | |
1455 | ERROR("Error creating container dir for %s", newpath); | |
1456 | goto out; | |
1457 | } | |
1458 | ||
1459 | // copy the configuration, tweak it as needed, | |
1460 | fout = fopen(newpath, "w"); | |
1461 | if (!fout) { | |
1462 | SYSERROR("open %s", newpath); | |
1463 | goto out; | |
1464 | } | |
1465 | write_config(fout, c->lxc_conf); | |
1466 | fclose(fout); | |
1467 | ||
1468 | if (update_name_and_paths(newpath, c, n, l) < 0) { | |
1469 | ERROR("Error updating name in cloned config"); | |
1470 | goto out; | |
1471 | } | |
1472 | ||
1473 | sprintf(newpath, "%s/%s/rootfs", l, n); | |
1474 | if (mkdir(newpath, 0755) < 0) { | |
1475 | SYSERROR("error creating %s", newpath); | |
1476 | goto out; | |
1477 | } | |
1478 | ||
1479 | c2 = lxc_container_new(n, l); | |
1480 | if (!c) { | |
1481 | ERROR("clone: failed to create new container (%s %s)", n, l); | |
1482 | goto out; | |
1483 | } | |
1484 | ||
1485 | // copy hooks if requested | |
1486 | if (flags & LXC_CLONE_COPYHOOKS) { | |
1487 | ret = copyhooks(c, c2); | |
1488 | if (ret < 0) { | |
1489 | ERROR("error copying hooks"); | |
1490 | c2->destroy(c2); | |
1491 | lxc_container_put(c2); | |
1492 | goto out; | |
1493 | } | |
1494 | } | |
1495 | ||
1496 | if (copy_fstab(c, c2) < 0) { | |
1497 | ERROR("error copying fstab"); | |
1498 | c2->destroy(c2); | |
1499 | lxc_container_put(c2); | |
1500 | goto out; | |
1501 | } | |
1502 | ||
1503 | // update macaddrs | |
1504 | if (!(flags & LXC_CLONE_KEEPMACADDR)) | |
1505 | network_new_hwaddrs(c2); | |
1506 | ||
1507 | // copy/snapshot rootfs's | |
1508 | ret = copy_storage(c, c2, bdevtype, flags, bdevdata, newsize); | |
1509 | if (ret < 0) { | |
1510 | c2->destroy(c2); | |
1511 | lxc_container_put(c2); | |
1512 | goto out; | |
1513 | } | |
1514 | ||
1515 | if (!c2->save_config(c2, NULL)) { | |
1516 | c2->destroy(c2); | |
1517 | lxc_container_put(c2); | |
1518 | goto out; | |
1519 | } | |
1520 | ||
1521 | if (clone_update_rootfs(c2, flags) < 0) { | |
1522 | //c2->destroy(c2); | |
1523 | lxc_container_put(c2); | |
1524 | goto out; | |
1525 | } | |
1526 | ||
1527 | // TODO: update c's lxc.snapshot = count | |
1528 | lxcunlock(c->privlock); | |
1529 | return c2; | |
1530 | ||
1531 | out: | |
1532 | lxcunlock(c->privlock); | |
1533 | if (c2) | |
1534 | lxc_container_put(c2); | |
1535 | ||
1536 | return NULL; | |
1537 | } | |
1538 | ||
afeecbba | 1539 | struct lxc_container *lxc_container_new(const char *name, const char *configpath) |
72d0e1cb SG |
1540 | { |
1541 | struct lxc_container *c; | |
72d0e1cb SG |
1542 | |
1543 | c = malloc(sizeof(*c)); | |
1544 | if (!c) { | |
1545 | fprintf(stderr, "failed to malloc lxc_container\n"); | |
1546 | return NULL; | |
1547 | } | |
1548 | memset(c, 0, sizeof(*c)); | |
1549 | ||
afeecbba SH |
1550 | if (configpath) |
1551 | c->config_path = strdup(configpath); | |
1552 | else | |
67e571de | 1553 | c->config_path = strdup(default_lxc_path()); |
afeecbba | 1554 | |
2a59a681 SH |
1555 | if (!c->config_path) { |
1556 | fprintf(stderr, "Out of memory"); | |
1557 | goto err; | |
1558 | } | |
1559 | ||
72d0e1cb SG |
1560 | c->name = malloc(strlen(name)+1); |
1561 | if (!c->name) { | |
1562 | fprintf(stderr, "Error allocating lxc_container name\n"); | |
1563 | goto err; | |
1564 | } | |
1565 | strcpy(c->name, name); | |
1566 | ||
1567 | c->numthreads = 1; | |
1568 | c->slock = lxc_newlock(name); | |
1569 | if (!c->slock) { | |
1570 | fprintf(stderr, "failed to create lock\n"); | |
1571 | goto err; | |
1572 | } | |
1573 | ||
1574 | c->privlock = lxc_newlock(NULL); | |
1575 | if (!c->privlock) { | |
1576 | fprintf(stderr, "failed to alloc privlock\n"); | |
1577 | goto err; | |
1578 | } | |
1579 | ||
afeecbba | 1580 | if (!set_config_filename(c)) { |
72d0e1cb SG |
1581 | fprintf(stderr, "Error allocating config file pathname\n"); |
1582 | goto err; | |
1583 | } | |
72d0e1cb SG |
1584 | |
1585 | if (file_exists(c->configfile)) | |
1586 | lxcapi_load_config(c, NULL); | |
1587 | ||
1588 | // assign the member functions | |
1589 | c->is_defined = lxcapi_is_defined; | |
1590 | c->state = lxcapi_state; | |
1591 | c->is_running = lxcapi_is_running; | |
1592 | c->freeze = lxcapi_freeze; | |
1593 | c->unfreeze = lxcapi_unfreeze; | |
1594 | c->init_pid = lxcapi_init_pid; | |
1595 | c->load_config = lxcapi_load_config; | |
1596 | c->want_daemonize = lxcapi_want_daemonize; | |
1597 | c->start = lxcapi_start; | |
1598 | c->startl = lxcapi_startl; | |
1599 | c->stop = lxcapi_stop; | |
1600 | c->config_file_name = lxcapi_config_file_name; | |
1601 | c->wait = lxcapi_wait; | |
1602 | c->set_config_item = lxcapi_set_config_item; | |
1603 | c->destroy = lxcapi_destroy; | |
1604 | c->save_config = lxcapi_save_config; | |
1605 | c->get_keys = lxcapi_get_keys; | |
1606 | c->create = lxcapi_create; | |
1607 | c->createl = lxcapi_createl; | |
1608 | c->shutdown = lxcapi_shutdown; | |
1609 | c->clear_config_item = lxcapi_clear_config_item; | |
1610 | c->get_config_item = lxcapi_get_config_item; | |
794dd120 SH |
1611 | c->get_cgroup_item = lxcapi_get_cgroup_item; |
1612 | c->set_cgroup_item = lxcapi_set_cgroup_item; | |
2a59a681 SH |
1613 | c->get_config_path = lxcapi_get_config_path; |
1614 | c->set_config_path = lxcapi_set_config_path; | |
9be53773 | 1615 | c->clone = lxcapi_clone; |
72d0e1cb SG |
1616 | |
1617 | /* we'll allow the caller to update these later */ | |
ab1bf971 | 1618 | if (lxc_log_init(NULL, "none", NULL, "lxc_container", 0, c->config_path)) { |
72d0e1cb SG |
1619 | fprintf(stderr, "failed to open log\n"); |
1620 | goto err; | |
1621 | } | |
1622 | ||
72d0e1cb SG |
1623 | return c; |
1624 | ||
1625 | err: | |
1626 | lxc_container_free(c); | |
1627 | return NULL; | |
1628 | } | |
1629 | ||
4a7c7daa | 1630 | int lxc_get_wait_states(const char **states) |
72d0e1cb SG |
1631 | { |
1632 | int i; | |
1633 | ||
1634 | if (states) | |
1635 | for (i=0; i<MAX_STATE; i++) | |
1636 | states[i] = lxc_state2str(i); | |
1637 | return MAX_STATE; | |
1638 | } |