]>
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 | ||
20 | #include "lxc.h" | |
21 | #include "state.h" | |
22 | #include "lxccontainer.h" | |
23 | #include "conf.h" | |
24 | #include "config.h" | |
25 | #include "confile.h" | |
26 | #include "cgroup.h" | |
27 | #include "commands.h" | |
b6b918a1 | 28 | #include "version.h" |
72d0e1cb SG |
29 | #include "log.h" |
30 | #include <unistd.h> | |
31 | #include <sys/types.h> | |
32 | #include <sys/wait.h> | |
33 | #include <errno.h> | |
2a59a681 | 34 | #include <lxc/utils.h> |
e51d4895 | 35 | #include <lxc/monitor.h> |
72d0e1cb SG |
36 | |
37 | lxc_log_define(lxc_container, lxc); | |
38 | ||
39 | /* LOCKING | |
40 | * c->privlock protects the struct lxc_container from multiple threads. | |
41 | * c->slock protects the on-disk container data | |
42 | * NOTHING mutexes two independent programs with their own struct | |
43 | * lxc_container for the same c->name, between API calls. For instance, | |
44 | * c->config_read(); c->start(); Between those calls, data on disk | |
45 | * could change (which shouldn't bother the caller unless for instance | |
46 | * the rootfs get moved). c->config_read(); update; c->config_write(); | |
47 | * Two such updaters could race. The callers should therefore check their | |
48 | * results. Trying to prevent that would necessarily expose us to deadlocks | |
49 | * due to hung callers. So I prefer to keep the locks only within our own | |
50 | * functions, not across functions. | |
51 | * | |
52 | * If you're going to fork while holding a lxccontainer, increment | |
53 | * c->numthreads (under privlock) before forking. When deleting, | |
54 | * decrement numthreads under privlock, then if it hits 0 you can delete. | |
55 | * Do not ever use a lxccontainer whose numthreads you did not bump. | |
56 | */ | |
57 | ||
58 | static void lxc_container_free(struct lxc_container *c) | |
59 | { | |
60 | if (!c) | |
61 | return; | |
62 | ||
63 | if (c->configfile) { | |
64 | free(c->configfile); | |
65 | c->configfile = NULL; | |
66 | } | |
67 | if (c->error_string) { | |
68 | free(c->error_string); | |
69 | c->error_string = NULL; | |
70 | } | |
d95db067 DE |
71 | if (c->slock) { |
72 | sem_close(c->slock); | |
73 | c->slock = NULL; | |
74 | } | |
72d0e1cb | 75 | if (c->privlock) { |
43d1aa34 | 76 | sem_t *l = c->privlock; |
72d0e1cb | 77 | c->privlock = NULL; |
43d1aa34 SH |
78 | sem_destroy(l); |
79 | free(l); | |
72d0e1cb SG |
80 | } |
81 | if (c->name) { | |
82 | free(c->name); | |
83 | c->name = NULL; | |
84 | } | |
d95db067 DE |
85 | if (c->lxc_conf) { |
86 | lxc_conf_free(c->lxc_conf); | |
87 | c->lxc_conf = NULL; | |
88 | } | |
2a59a681 SH |
89 | if (c->config_path) { |
90 | free(c->config_path); | |
91 | c->config_path = NULL; | |
92 | } | |
72d0e1cb SG |
93 | free(c); |
94 | } | |
95 | ||
43d1aa34 SH |
96 | /* |
97 | * Consider the following case: | |
98 | freer | racing get()er | |
99 | ================================================================== | |
100 | lxc_container_put() | lxc_container_get() | |
101 | \ lxclock(c->privlock) | c->numthreads < 1? (no) | |
102 | \ c->numthreads = 0 | \ lxclock(c->privlock) -> waits | |
103 | \ lxcunlock() | \ | |
104 | \ lxc_container_free() | \ lxclock() returns | |
105 | | \ c->numthreads < 1 -> return 0 | |
106 | \ \ (free stuff) | | |
107 | \ \ sem_destroy(privlock) | | |
108 | ||
109 | * When the get()er checks numthreads the first time, one of the following | |
110 | * is true: | |
111 | * 1. freer has set numthreads = 0. get() returns 0 | |
112 | * 2. freer is between lxclock and setting numthreads to 0. get()er will | |
113 | * sem_wait on privlock, get lxclock after freer() drops it, then see | |
114 | * numthreads is 0 and exit without touching lxclock again.. | |
115 | * 3. freer has not yet locked privlock. If get()er runs first, then put()er | |
116 | * will see --numthreads = 1 and not call lxc_container_free(). | |
117 | */ | |
118 | ||
72d0e1cb SG |
119 | int lxc_container_get(struct lxc_container *c) |
120 | { | |
121 | if (!c) | |
122 | return 0; | |
123 | ||
43d1aa34 SH |
124 | // if someone else has already started freeing the container, don't |
125 | // try to take the lock, which may be invalid | |
126 | if (c->numthreads < 1) | |
127 | return 0; | |
128 | ||
72d0e1cb SG |
129 | if (lxclock(c->privlock, 0)) |
130 | return 0; | |
131 | if (c->numthreads < 1) { | |
132 | // bail without trying to unlock, bc the privlock is now probably | |
133 | // in freed memory | |
134 | return 0; | |
135 | } | |
136 | c->numthreads++; | |
137 | lxcunlock(c->privlock); | |
138 | return 1; | |
139 | } | |
140 | ||
141 | int lxc_container_put(struct lxc_container *c) | |
142 | { | |
143 | if (!c) | |
144 | return -1; | |
145 | if (lxclock(c->privlock, 0)) | |
146 | return -1; | |
147 | if (--c->numthreads < 1) { | |
148 | lxcunlock(c->privlock); | |
149 | lxc_container_free(c); | |
150 | return 1; | |
151 | } | |
152 | lxcunlock(c->privlock); | |
153 | return 0; | |
154 | } | |
155 | ||
156 | static bool file_exists(char *f) | |
157 | { | |
158 | struct stat statbuf; | |
159 | ||
160 | return stat(f, &statbuf) == 0; | |
161 | } | |
162 | ||
163 | static bool lxcapi_is_defined(struct lxc_container *c) | |
164 | { | |
165 | struct stat statbuf; | |
166 | bool ret = false; | |
167 | int statret; | |
168 | ||
169 | if (!c) | |
170 | return false; | |
171 | ||
172 | if (lxclock(c->privlock, 0)) | |
173 | return false; | |
174 | if (!c->configfile) | |
175 | goto out; | |
176 | statret = stat(c->configfile, &statbuf); | |
177 | if (statret != 0) | |
178 | goto out; | |
179 | ret = true; | |
180 | ||
181 | out: | |
182 | lxcunlock(c->privlock); | |
183 | return ret; | |
184 | } | |
185 | ||
186 | static const char *lxcapi_state(struct lxc_container *c) | |
187 | { | |
188 | const char *ret; | |
189 | lxc_state_t s; | |
190 | ||
191 | if (!c) | |
192 | return NULL; | |
193 | if (lxclock(c->slock, 0)) | |
194 | return NULL; | |
13f5be62 | 195 | s = lxc_getstate(c->name, c->config_path); |
72d0e1cb SG |
196 | ret = lxc_state2str(s); |
197 | lxcunlock(c->slock); | |
198 | ||
199 | return ret; | |
200 | } | |
201 | ||
794dd120 SH |
202 | static bool is_stopped_nolock(struct lxc_container *c) |
203 | { | |
204 | lxc_state_t s; | |
13f5be62 | 205 | s = lxc_getstate(c->name, c->config_path); |
794dd120 SH |
206 | return (s == STOPPED); |
207 | } | |
208 | ||
72d0e1cb SG |
209 | static bool lxcapi_is_running(struct lxc_container *c) |
210 | { | |
211 | const char *s; | |
212 | ||
213 | if (!c) | |
214 | return false; | |
215 | s = lxcapi_state(c); | |
216 | if (!s || strcmp(s, "STOPPED") == 0) | |
217 | return false; | |
218 | return true; | |
219 | } | |
220 | ||
221 | static bool lxcapi_freeze(struct lxc_container *c) | |
222 | { | |
223 | int ret; | |
224 | if (!c) | |
225 | return false; | |
226 | ||
227 | if (lxclock(c->slock, 0)) | |
228 | return false; | |
9123e471 | 229 | ret = lxc_freeze(c->name, c->config_path); |
72d0e1cb SG |
230 | lxcunlock(c->slock); |
231 | if (ret) | |
232 | return false; | |
233 | return true; | |
234 | } | |
235 | ||
236 | static bool lxcapi_unfreeze(struct lxc_container *c) | |
237 | { | |
238 | int ret; | |
239 | if (!c) | |
240 | return false; | |
241 | ||
242 | if (lxclock(c->slock, 0)) | |
243 | return false; | |
9123e471 | 244 | ret = lxc_unfreeze(c->name, c->config_path); |
72d0e1cb SG |
245 | lxcunlock(c->slock); |
246 | if (ret) | |
247 | return false; | |
248 | return true; | |
249 | } | |
250 | ||
251 | static pid_t lxcapi_init_pid(struct lxc_container *c) | |
252 | { | |
253 | pid_t ret; | |
254 | if (!c) | |
255 | return -1; | |
256 | ||
257 | if (lxclock(c->slock, 0)) | |
258 | return -1; | |
13f5be62 | 259 | ret = get_init_pid(c->name, c->config_path); |
72d0e1cb SG |
260 | lxcunlock(c->slock); |
261 | return ret; | |
262 | } | |
263 | ||
12a50cc6 | 264 | static bool load_config_locked(struct lxc_container *c, const char *fname) |
8eb5694b SH |
265 | { |
266 | if (!c->lxc_conf) | |
267 | c->lxc_conf = lxc_conf_init(); | |
268 | if (c->lxc_conf && !lxc_config_read(fname, c->lxc_conf)) | |
269 | return true; | |
270 | return false; | |
271 | } | |
272 | ||
12a50cc6 | 273 | static bool lxcapi_load_config(struct lxc_container *c, const char *alt_file) |
72d0e1cb SG |
274 | { |
275 | bool ret = false; | |
12a50cc6 | 276 | const char *fname; |
72d0e1cb SG |
277 | if (!c) |
278 | return false; | |
279 | ||
280 | fname = c->configfile; | |
281 | if (alt_file) | |
282 | fname = alt_file; | |
283 | if (!fname) | |
284 | return false; | |
285 | if (lxclock(c->slock, 0)) | |
286 | return false; | |
8eb5694b | 287 | ret = load_config_locked(c, fname); |
72d0e1cb SG |
288 | lxcunlock(c->slock); |
289 | return ret; | |
290 | } | |
291 | ||
292 | static void lxcapi_want_daemonize(struct lxc_container *c) | |
293 | { | |
294 | if (!c) | |
295 | return; | |
296 | c->daemonize = 1; | |
297 | } | |
298 | ||
12a50cc6 | 299 | static bool lxcapi_wait(struct lxc_container *c, const char *state, int timeout) |
7a44c8b4 SG |
300 | { |
301 | int ret; | |
302 | ||
303 | if (!c) | |
304 | return false; | |
305 | ||
67e571de | 306 | ret = lxc_wait(c->name, state, timeout, c->config_path); |
7a44c8b4 SG |
307 | return ret == 0; |
308 | } | |
309 | ||
310 | ||
311 | static bool wait_on_daemonized_start(struct lxc_container *c) | |
312 | { | |
313 | /* we'll probably want to make this timeout configurable? */ | |
697fa639 | 314 | int timeout = 5, ret, status; |
7a44c8b4 | 315 | |
697fa639 SH |
316 | /* |
317 | * our child is going to fork again, then exit. reap the | |
318 | * child | |
319 | */ | |
320 | ret = wait(&status); | |
321 | if (ret == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) | |
322 | DEBUG("failed waiting for first dual-fork child"); | |
7a44c8b4 SG |
323 | return lxcapi_wait(c, "RUNNING", timeout); |
324 | } | |
325 | ||
72d0e1cb SG |
326 | /* |
327 | * I can't decide if it'd be more convenient for callers if we accept '...', | |
328 | * or a null-terminated array (i.e. execl vs execv) | |
329 | */ | |
12a50cc6 | 330 | static bool lxcapi_start(struct lxc_container *c, int useinit, char * const argv[]) |
72d0e1cb SG |
331 | { |
332 | int ret; | |
333 | struct lxc_conf *conf; | |
334 | int daemonize = 0; | |
335 | char *default_args[] = { | |
336 | "/sbin/init", | |
337 | '\0', | |
338 | }; | |
339 | ||
340 | /* container exists */ | |
341 | if (!c) | |
342 | return false; | |
343 | /* container has been setup */ | |
344 | if (!c->lxc_conf) | |
345 | return false; | |
346 | ||
347 | /* is this app meant to be run through lxcinit, as in lxc-execute? */ | |
348 | if (useinit && !argv) | |
349 | return false; | |
350 | ||
351 | if (lxclock(c->privlock, 0)) | |
352 | return false; | |
353 | conf = c->lxc_conf; | |
354 | daemonize = c->daemonize; | |
355 | lxcunlock(c->privlock); | |
356 | ||
357 | if (useinit) { | |
13f5be62 | 358 | ret = lxc_execute(c->name, argv, 1, conf, c->config_path); |
72d0e1cb SG |
359 | return ret == 0 ? true : false; |
360 | } | |
361 | ||
362 | if (!argv) | |
363 | argv = default_args; | |
364 | ||
365 | /* | |
366 | * say, I'm not sure - what locks do we want here? Any? | |
367 | * Is liblxc's locking enough here to protect the on disk | |
368 | * container? We don't want to exclude things like lxc_info | |
369 | * while container is running... | |
370 | */ | |
371 | if (daemonize) { | |
372 | if (!lxc_container_get(c)) | |
373 | return false; | |
e51d4895 | 374 | lxc_monitord_spawn(c->config_path); |
72d0e1cb SG |
375 | pid_t pid = fork(); |
376 | if (pid < 0) { | |
377 | lxc_container_put(c); | |
378 | return false; | |
379 | } | |
380 | if (pid != 0) | |
7a44c8b4 | 381 | return wait_on_daemonized_start(c); |
697fa639 SH |
382 | /* second fork to be reparented by init */ |
383 | pid = fork(); | |
384 | if (pid < 0) { | |
385 | SYSERROR("Error doing dual-fork"); | |
386 | return false; | |
387 | } | |
388 | if (pid != 0) | |
389 | exit(0); | |
72d0e1cb | 390 | /* like daemon(), chdir to / and redirect 0,1,2 to /dev/null */ |
c278cef2 SH |
391 | if (chdir("/")) { |
392 | SYSERROR("Error chdir()ing to /."); | |
393 | return false; | |
394 | } | |
72d0e1cb SG |
395 | close(0); |
396 | close(1); | |
397 | close(2); | |
398 | open("/dev/null", O_RDONLY); | |
399 | open("/dev/null", O_RDWR); | |
400 | open("/dev/null", O_RDWR); | |
401 | setsid(); | |
402 | } | |
403 | ||
72d0e1cb SG |
404 | reboot: |
405 | conf->reboot = 0; | |
13f5be62 | 406 | ret = lxc_start(c->name, argv, conf, c->config_path); |
72d0e1cb SG |
407 | |
408 | if (conf->reboot) { | |
409 | INFO("container requested reboot"); | |
410 | conf->reboot = 0; | |
72d0e1cb SG |
411 | goto reboot; |
412 | } | |
413 | ||
414 | if (daemonize) { | |
415 | lxc_container_put(c); | |
416 | exit (ret == 0 ? true : false); | |
417 | } else { | |
418 | return (ret == 0 ? true : false); | |
419 | } | |
420 | } | |
421 | ||
422 | /* | |
423 | * note there MUST be an ending NULL | |
424 | */ | |
425 | static bool lxcapi_startl(struct lxc_container *c, int useinit, ...) | |
426 | { | |
427 | va_list ap; | |
428 | char **inargs = NULL, **temp; | |
429 | int n_inargs = 0; | |
430 | bool bret = false; | |
431 | ||
432 | /* container exists */ | |
433 | if (!c) | |
434 | return false; | |
435 | ||
436 | /* build array of arguments if any */ | |
437 | va_start(ap, useinit); | |
438 | while (1) { | |
439 | char *arg; | |
440 | arg = va_arg(ap, char *); | |
441 | if (!arg) | |
442 | break; | |
443 | n_inargs++; | |
444 | temp = realloc(inargs, n_inargs * sizeof(*inargs)); | |
586d4e9b SH |
445 | if (!temp) { |
446 | va_end(ap); | |
72d0e1cb | 447 | goto out; |
586d4e9b | 448 | } |
72d0e1cb SG |
449 | inargs = temp; |
450 | inargs[n_inargs - 1] = strdup(arg); // not sure if it's safe not to copy | |
451 | } | |
452 | va_end(ap); | |
453 | ||
454 | /* add trailing NULL */ | |
455 | if (n_inargs) { | |
456 | n_inargs++; | |
457 | temp = realloc(inargs, n_inargs * sizeof(*inargs)); | |
458 | if (!temp) | |
459 | goto out; | |
460 | inargs = temp; | |
461 | inargs[n_inargs - 1] = NULL; | |
462 | } | |
463 | ||
464 | bret = lxcapi_start(c, useinit, inargs); | |
465 | ||
466 | out: | |
467 | if (inargs) { | |
468 | int i; | |
469 | for (i = 0; i < n_inargs; i++) { | |
470 | if (inargs[i]) | |
471 | free(inargs[i]); | |
472 | } | |
473 | free(inargs); | |
474 | } | |
475 | ||
476 | return bret; | |
477 | } | |
478 | ||
479 | static bool lxcapi_stop(struct lxc_container *c) | |
480 | { | |
481 | int ret; | |
482 | ||
483 | if (!c) | |
484 | return false; | |
485 | ||
13f5be62 | 486 | ret = lxc_stop(c->name, c->config_path); |
72d0e1cb SG |
487 | |
488 | return ret == 0; | |
72d0e1cb SG |
489 | } |
490 | ||
491 | static bool valid_template(char *t) | |
492 | { | |
493 | struct stat statbuf; | |
494 | int statret; | |
495 | ||
496 | statret = stat(t, &statbuf); | |
497 | if (statret == 0) | |
498 | return true; | |
499 | return false; | |
500 | } | |
501 | ||
502 | /* | |
503 | * create the standard expected container dir | |
504 | */ | |
505 | static bool create_container_dir(struct lxc_container *c) | |
506 | { | |
507 | char *s; | |
508 | int len, ret; | |
509 | ||
2a59a681 | 510 | len = strlen(c->config_path) + strlen(c->name) + 2; |
72d0e1cb SG |
511 | s = malloc(len); |
512 | if (!s) | |
513 | return false; | |
2a59a681 | 514 | ret = snprintf(s, len, "%s/%s", c->config_path, c->name); |
72d0e1cb SG |
515 | if (ret < 0 || ret >= len) { |
516 | free(s); | |
517 | return false; | |
518 | } | |
519 | ret = mkdir(s, 0755); | |
520 | if (ret) { | |
521 | if (errno == EEXIST) | |
522 | ret = 0; | |
523 | else | |
524 | SYSERROR("failed to create container path for %s\n", c->name); | |
525 | } | |
526 | free(s); | |
527 | return ret == 0; | |
528 | } | |
529 | ||
530 | /* | |
531 | * backing stores not (yet) supported | |
532 | * for ->create, argv contains the arguments to pass to the template, | |
533 | * terminated by NULL. If no arguments, you can just pass NULL. | |
534 | */ | |
12a50cc6 | 535 | static bool lxcapi_create(struct lxc_container *c, char *t, char *const argv[]) |
72d0e1cb SG |
536 | { |
537 | bool bret = false; | |
538 | pid_t pid; | |
539 | int ret, status; | |
540 | char *tpath = NULL; | |
541 | int len, nargs = 0; | |
542 | char **newargv; | |
543 | ||
544 | if (!c) | |
545 | return false; | |
546 | ||
547 | len = strlen(LXCTEMPLATEDIR) + strlen(t) + strlen("/lxc-") + 1; | |
548 | tpath = malloc(len); | |
549 | if (!tpath) | |
550 | return false; | |
551 | ret = snprintf(tpath, len, "%s/lxc-%s", LXCTEMPLATEDIR, t); | |
552 | if (ret < 0 || ret >= len) | |
553 | goto out; | |
554 | if (!valid_template(tpath)) { | |
555 | ERROR("bad template: %s\n", t); | |
556 | goto out; | |
557 | } | |
558 | ||
72d0e1cb SG |
559 | if (!c->save_config(c, NULL)) { |
560 | ERROR("failed to save starting configuration for %s\n", c->name); | |
561 | goto out; | |
562 | } | |
563 | ||
5a3d2e1e | 564 | /* container is already created if we have a config and rootfs.path is accessible */ |
e51d4895 | 565 | if (lxcapi_is_defined(c) && c->lxc_conf && c->lxc_conf->rootfs.path && access(c->lxc_conf->rootfs.path, F_OK) == 0) |
a741a85d | 566 | goto out; |
5a3d2e1e | 567 | |
72d0e1cb SG |
568 | /* we're going to fork. but since we'll wait for our child, we |
569 | don't need to lxc_container_get */ | |
570 | ||
571 | if (lxclock(c->slock, 0)) { | |
572 | ERROR("failed to grab global container lock for %s\n", c->name); | |
573 | goto out; | |
574 | } | |
575 | ||
576 | pid = fork(); | |
577 | if (pid < 0) { | |
578 | SYSERROR("failed to fork task for container creation template\n"); | |
579 | goto out_unlock; | |
580 | } | |
581 | ||
582 | if (pid == 0) { // child | |
583 | char *patharg, *namearg; | |
584 | int i; | |
585 | ||
586 | close(0); | |
587 | close(1); | |
588 | close(2); | |
589 | open("/dev/null", O_RDONLY); | |
590 | open("/dev/null", O_RDWR); | |
591 | open("/dev/null", O_RDWR); | |
592 | ||
593 | /* | |
594 | * create our new array, pre-pend the template name and | |
595 | * base args | |
596 | */ | |
597 | if (argv) | |
598 | for (; argv[nargs]; nargs++) ; | |
599 | nargs += 3; // template, path and name args | |
600 | newargv = malloc(nargs * sizeof(*newargv)); | |
601 | if (!newargv) | |
602 | exit(1); | |
603 | newargv[0] = t; | |
604 | ||
2a59a681 | 605 | len = strlen(c->config_path) + strlen(c->name) + strlen("--path=") + 2; |
72d0e1cb SG |
606 | patharg = malloc(len); |
607 | if (!patharg) | |
608 | exit(1); | |
2a59a681 | 609 | ret = snprintf(patharg, len, "--path=%s/%s", c->config_path, c->name); |
72d0e1cb SG |
610 | if (ret < 0 || ret >= len) |
611 | exit(1); | |
612 | newargv[1] = patharg; | |
613 | len = strlen("--name=") + strlen(c->name) + 1; | |
614 | namearg = malloc(len); | |
615 | if (!namearg) | |
616 | exit(1); | |
617 | ret = snprintf(namearg, len, "--name=%s", c->name); | |
618 | if (ret < 0 || ret >= len) | |
619 | exit(1); | |
620 | newargv[2] = namearg; | |
621 | ||
622 | /* add passed-in args */ | |
623 | if (argv) | |
624 | for (i = 3; i < nargs; i++) | |
625 | newargv[i] = argv[i-3]; | |
626 | ||
627 | /* add trailing NULL */ | |
628 | nargs++; | |
629 | newargv = realloc(newargv, nargs * sizeof(*newargv)); | |
630 | if (!newargv) | |
631 | exit(1); | |
632 | newargv[nargs - 1] = NULL; | |
633 | ||
634 | /* execute */ | |
e6a19d26 | 635 | execv(tpath, newargv); |
72d0e1cb SG |
636 | SYSERROR("failed to execute template %s", tpath); |
637 | exit(1); | |
638 | } | |
639 | ||
640 | again: | |
641 | ret = waitpid(pid, &status, 0); | |
642 | if (ret == -1) { | |
643 | if (errno == -EINTR) | |
644 | goto again; | |
645 | SYSERROR("waitpid failed"); | |
646 | goto out_unlock; | |
647 | } | |
648 | if (ret != pid) | |
649 | goto again; | |
650 | if (!WIFEXITED(status)) { // did not exit normally | |
651 | // we could set an error code and string inside the | |
652 | // container_struct here if we like | |
653 | ERROR("container creation template exited abnormally\n"); | |
654 | goto out_unlock; | |
655 | } | |
656 | ||
8eb5694b | 657 | if (WEXITSTATUS(status) != 0) { |
72d0e1cb SG |
658 | ERROR("container creation template for %s exited with %d\n", |
659 | c->name, WEXITSTATUS(status)); | |
8eb5694b SH |
660 | goto out_unlock; |
661 | } | |
662 | ||
663 | // now clear out the lxc_conf we have, reload from the created | |
664 | // container | |
665 | if (c->lxc_conf) | |
666 | lxc_conf_free(c->lxc_conf); | |
667 | c->lxc_conf = NULL; | |
668 | bret = load_config_locked(c, c->configfile); | |
72d0e1cb SG |
669 | |
670 | out_unlock: | |
671 | lxcunlock(c->slock); | |
672 | out: | |
673 | if (tpath) | |
674 | free(tpath); | |
675 | return bret; | |
676 | } | |
677 | ||
678 | static bool lxcapi_shutdown(struct lxc_container *c, int timeout) | |
679 | { | |
680 | bool retv; | |
681 | pid_t pid; | |
682 | ||
683 | if (!c) | |
684 | return false; | |
685 | ||
686 | if (!timeout) | |
687 | timeout = -1; | |
688 | if (!c->is_running(c)) | |
689 | return true; | |
690 | pid = c->init_pid(c); | |
691 | if (pid <= 0) | |
692 | return true; | |
693 | kill(pid, SIGPWR); | |
694 | retv = c->wait(c, "STOPPED", timeout); | |
f6144ed4 | 695 | if (!retv && timeout > 0) { |
72d0e1cb SG |
696 | c->stop(c); |
697 | retv = c->wait(c, "STOPPED", 0); // 0 means don't wait | |
698 | } | |
699 | return retv; | |
700 | } | |
701 | ||
702 | static bool lxcapi_createl(struct lxc_container *c, char *t, ...) | |
703 | { | |
704 | bool bret = false; | |
705 | char **args = NULL, **temp; | |
706 | va_list ap; | |
707 | int nargs = 0; | |
708 | ||
709 | if (!c) | |
710 | return false; | |
711 | ||
712 | /* | |
713 | * since we're going to wait for create to finish, I don't think we | |
714 | * need to get a copy of the arguments. | |
715 | */ | |
716 | va_start(ap, t); | |
717 | while (1) { | |
718 | char *arg; | |
719 | arg = va_arg(ap, char *); | |
720 | if (!arg) | |
721 | break; | |
722 | nargs++; | |
83cab6e0 | 723 | temp = realloc(args, (nargs+1) * sizeof(*args)); |
41670788 SH |
724 | if (!temp) { |
725 | va_end(ap); | |
72d0e1cb | 726 | goto out; |
41670788 | 727 | } |
72d0e1cb SG |
728 | args = temp; |
729 | args[nargs - 1] = arg; | |
730 | } | |
731 | va_end(ap); | |
63e414f8 SH |
732 | if (args) |
733 | args[nargs] = NULL; | |
72d0e1cb SG |
734 | |
735 | bret = c->create(c, t, args); | |
736 | ||
737 | out: | |
738 | if (args) | |
739 | free(args); | |
740 | return bret; | |
741 | } | |
742 | ||
12a50cc6 | 743 | static bool lxcapi_clear_config_item(struct lxc_container *c, const char *key) |
72d0e1cb SG |
744 | { |
745 | int ret; | |
746 | ||
747 | if (!c || !c->lxc_conf) | |
748 | return false; | |
749 | if (lxclock(c->privlock, 0)) { | |
750 | return false; | |
751 | } | |
752 | ret = lxc_clear_config_item(c->lxc_conf, key); | |
753 | lxcunlock(c->privlock); | |
754 | return ret == 0; | |
755 | } | |
756 | ||
12a50cc6 | 757 | static int lxcapi_get_config_item(struct lxc_container *c, const char *key, char *retv, int inlen) |
72d0e1cb SG |
758 | { |
759 | int ret; | |
760 | ||
761 | if (!c || !c->lxc_conf) | |
762 | return -1; | |
763 | if (lxclock(c->privlock, 0)) { | |
764 | return -1; | |
765 | } | |
766 | ret = lxc_get_config_item(c->lxc_conf, key, retv, inlen); | |
767 | lxcunlock(c->privlock); | |
768 | return ret; | |
769 | } | |
770 | ||
12a50cc6 | 771 | static int lxcapi_get_keys(struct lxc_container *c, const char *key, char *retv, int inlen) |
72d0e1cb SG |
772 | { |
773 | if (!key) | |
774 | return lxc_listconfigs(retv, inlen); | |
775 | /* | |
776 | * Support 'lxc.network.<idx>', i.e. 'lxc.network.0' | |
777 | * This is an intelligent result to show which keys are valid given | |
778 | * the type of nic it is | |
779 | */ | |
780 | if (!c || !c->lxc_conf) | |
781 | return -1; | |
782 | if (lxclock(c->privlock, 0)) | |
783 | return -1; | |
784 | int ret = -1; | |
785 | if (strncmp(key, "lxc.network.", 12) == 0) | |
786 | ret = lxc_list_nicconfigs(c->lxc_conf, key, retv, inlen); | |
787 | lxcunlock(c->privlock); | |
788 | return ret; | |
789 | } | |
790 | ||
791 | ||
792 | /* default config file - should probably come through autoconf */ | |
bb9702b5 | 793 | #define LXC_DEFAULT_CONFIG "/etc/lxc/default.conf" |
12a50cc6 | 794 | static bool lxcapi_save_config(struct lxc_container *c, const char *alt_file) |
72d0e1cb SG |
795 | { |
796 | if (!alt_file) | |
797 | alt_file = c->configfile; | |
798 | if (!alt_file) | |
799 | return false; // should we write to stdout if no file is specified? | |
800 | if (!c->lxc_conf) | |
801 | if (!c->load_config(c, LXC_DEFAULT_CONFIG)) { | |
802 | ERROR("Error loading default configuration file %s while saving %s\n", LXC_DEFAULT_CONFIG, c->name); | |
803 | return false; | |
804 | } | |
805 | ||
5a3d2e1e SG |
806 | if (!create_container_dir(c)) |
807 | return false; | |
808 | ||
72d0e1cb SG |
809 | FILE *fout = fopen(alt_file, "w"); |
810 | if (!fout) | |
811 | return false; | |
812 | if (lxclock(c->privlock, 0)) { | |
813 | fclose(fout); | |
814 | return false; | |
815 | } | |
816 | write_config(fout, c->lxc_conf); | |
817 | fclose(fout); | |
818 | lxcunlock(c->privlock); | |
819 | return true; | |
820 | } | |
821 | ||
822 | static bool lxcapi_destroy(struct lxc_container *c) | |
823 | { | |
824 | pid_t pid; | |
825 | int ret, status; | |
826 | ||
827 | if (!c) | |
828 | return false; | |
829 | ||
5a3d2e1e | 830 | /* container is already destroyed if we don't have a config and rootfs.path is not accessible */ |
e51d4895 | 831 | if (!lxcapi_is_defined(c) && (!c->lxc_conf || !c->lxc_conf->rootfs.path || access(c->lxc_conf->rootfs.path, F_OK) != 0)) |
5a3d2e1e SG |
832 | return false; |
833 | ||
72d0e1cb SG |
834 | pid = fork(); |
835 | if (pid < 0) | |
836 | return false; | |
837 | if (pid == 0) { // child | |
e6a19d26 | 838 | execlp("lxc-destroy", "lxc-destroy", "-n", c->name, "-P", c->config_path, NULL); |
72d0e1cb SG |
839 | perror("execl"); |
840 | exit(1); | |
841 | } | |
842 | ||
843 | again: | |
844 | ret = waitpid(pid, &status, 0); | |
845 | if (ret == -1) { | |
846 | if (errno == -EINTR) | |
847 | goto again; | |
848 | perror("waitpid"); | |
849 | return false; | |
850 | } | |
851 | if (ret != pid) | |
852 | goto again; | |
853 | if (!WIFEXITED(status)) { // did not exit normally | |
854 | // we could set an error code and string inside the | |
855 | // container_struct here if we like | |
856 | return false; | |
857 | } | |
858 | ||
859 | return WEXITSTATUS(status) == 0; | |
860 | } | |
861 | ||
12a50cc6 | 862 | static bool lxcapi_set_config_item(struct lxc_container *c, const char *key, const char *v) |
72d0e1cb SG |
863 | { |
864 | int ret; | |
865 | bool b = false; | |
866 | struct lxc_config_t *config; | |
867 | ||
868 | if (!c) | |
869 | return false; | |
870 | ||
871 | if (lxclock(c->privlock, 0)) | |
872 | return false; | |
873 | ||
874 | if (!c->lxc_conf) | |
875 | c->lxc_conf = lxc_conf_init(); | |
876 | if (!c->lxc_conf) | |
877 | goto err; | |
878 | config = lxc_getconfig(key); | |
879 | if (!config) | |
880 | goto err; | |
881 | ret = config->cb(key, v, c->lxc_conf); | |
882 | if (!ret) | |
883 | b = true; | |
884 | ||
885 | err: | |
886 | lxcunlock(c->privlock); | |
887 | return b; | |
888 | } | |
889 | ||
890 | static char *lxcapi_config_file_name(struct lxc_container *c) | |
891 | { | |
892 | if (!c || !c->configfile) | |
893 | return NULL; | |
894 | return strdup(c->configfile); | |
895 | } | |
896 | ||
2a59a681 SH |
897 | static const char *lxcapi_get_config_path(struct lxc_container *c) |
898 | { | |
899 | if (!c || !c->config_path) | |
900 | return NULL; | |
901 | return (const char *)(c->config_path); | |
902 | } | |
903 | ||
afeecbba SH |
904 | /* |
905 | * not for export | |
906 | * Just recalculate the c->configfile based on the | |
907 | * c->config_path, which must be set. | |
908 | * The lxc_container must be locked or not yet public. | |
909 | */ | |
910 | static bool set_config_filename(struct lxc_container *c) | |
911 | { | |
912 | char *newpath; | |
913 | int len, ret; | |
914 | ||
915 | if (!c->config_path) | |
916 | return false; | |
917 | ||
918 | /* $lxc_path + "/" + c->name + "/" + "config" + '\0' */ | |
919 | len = strlen(c->config_path) + strlen(c->name) + strlen("config") + 3; | |
920 | newpath = malloc(len); | |
921 | if (!newpath) | |
922 | return false; | |
923 | ||
924 | ret = snprintf(newpath, len, "%s/%s/config", c->config_path, c->name); | |
925 | if (ret < 0 || ret >= len) { | |
926 | fprintf(stderr, "Error printing out config file name\n"); | |
927 | free(newpath); | |
928 | return false; | |
929 | } | |
930 | ||
931 | if (c->configfile) | |
932 | free(c->configfile); | |
933 | c->configfile = newpath; | |
934 | ||
935 | return true; | |
936 | } | |
937 | ||
2a59a681 SH |
938 | static bool lxcapi_set_config_path(struct lxc_container *c, const char *path) |
939 | { | |
940 | char *p; | |
941 | bool b = false; | |
afeecbba | 942 | char *oldpath = NULL; |
2a59a681 SH |
943 | |
944 | if (!c) | |
945 | return b; | |
946 | ||
947 | if (lxclock(c->privlock, 0)) | |
948 | return b; | |
949 | ||
950 | p = strdup(path); | |
afeecbba SH |
951 | if (!p) { |
952 | ERROR("Out of memory setting new lxc path"); | |
2a59a681 | 953 | goto err; |
afeecbba SH |
954 | } |
955 | ||
2a59a681 SH |
956 | b = true; |
957 | if (c->config_path) | |
afeecbba | 958 | oldpath = c->config_path; |
2a59a681 | 959 | c->config_path = p; |
afeecbba SH |
960 | |
961 | /* Since we've changed the config path, we have to change the | |
962 | * config file name too */ | |
963 | if (!set_config_filename(c)) { | |
964 | ERROR("Out of memory setting new config filename"); | |
965 | b = false; | |
966 | free(c->config_path); | |
967 | c->config_path = oldpath; | |
968 | oldpath = NULL; | |
969 | } | |
2a59a681 | 970 | err: |
afeecbba SH |
971 | if (oldpath) |
972 | free(oldpath); | |
2a59a681 SH |
973 | lxcunlock(c->privlock); |
974 | return b; | |
975 | } | |
976 | ||
977 | ||
794dd120 SH |
978 | static bool lxcapi_set_cgroup_item(struct lxc_container *c, const char *subsys, const char *value) |
979 | { | |
980 | int ret; | |
981 | bool b = false; | |
982 | ||
983 | if (!c) | |
984 | return false; | |
985 | ||
986 | if (lxclock(c->privlock, 0)) | |
987 | return false; | |
988 | ||
989 | if (is_stopped_nolock(c)) | |
990 | goto err; | |
991 | ||
ae5c8b8e | 992 | ret = lxc_cgroup_set(c->name, subsys, value, c->config_path); |
794dd120 SH |
993 | if (!ret) |
994 | b = true; | |
995 | err: | |
996 | lxcunlock(c->privlock); | |
997 | return b; | |
998 | } | |
999 | ||
1000 | static int lxcapi_get_cgroup_item(struct lxc_container *c, const char *subsys, char *retv, int inlen) | |
1001 | { | |
1002 | int ret = -1; | |
1003 | ||
1004 | if (!c || !c->lxc_conf) | |
1005 | return -1; | |
1006 | ||
1007 | if (lxclock(c->privlock, 0)) | |
1008 | return -1; | |
1009 | ||
1010 | if (is_stopped_nolock(c)) | |
1011 | goto out; | |
1012 | ||
ae5c8b8e | 1013 | ret = lxc_cgroup_get(c->name, subsys, retv, inlen, c->config_path); |
794dd120 SH |
1014 | |
1015 | out: | |
1016 | lxcunlock(c->privlock); | |
1017 | return ret; | |
1018 | } | |
1019 | ||
67e571de | 1020 | const char *lxc_get_default_config_path(void) |
83c98d82 DE |
1021 | { |
1022 | return default_lxc_path(); | |
1023 | } | |
794dd120 | 1024 | |
b6b918a1 SG |
1025 | const char *lxc_get_version(void) |
1026 | { | |
1027 | return lxc_version(); | |
1028 | } | |
1029 | ||
afeecbba | 1030 | struct lxc_container *lxc_container_new(const char *name, const char *configpath) |
72d0e1cb SG |
1031 | { |
1032 | struct lxc_container *c; | |
72d0e1cb SG |
1033 | |
1034 | c = malloc(sizeof(*c)); | |
1035 | if (!c) { | |
1036 | fprintf(stderr, "failed to malloc lxc_container\n"); | |
1037 | return NULL; | |
1038 | } | |
1039 | memset(c, 0, sizeof(*c)); | |
1040 | ||
afeecbba SH |
1041 | if (configpath) |
1042 | c->config_path = strdup(configpath); | |
1043 | else | |
67e571de | 1044 | c->config_path = strdup(default_lxc_path()); |
afeecbba | 1045 | |
2a59a681 SH |
1046 | if (!c->config_path) { |
1047 | fprintf(stderr, "Out of memory"); | |
1048 | goto err; | |
1049 | } | |
1050 | ||
72d0e1cb SG |
1051 | c->name = malloc(strlen(name)+1); |
1052 | if (!c->name) { | |
1053 | fprintf(stderr, "Error allocating lxc_container name\n"); | |
1054 | goto err; | |
1055 | } | |
1056 | strcpy(c->name, name); | |
1057 | ||
1058 | c->numthreads = 1; | |
1059 | c->slock = lxc_newlock(name); | |
1060 | if (!c->slock) { | |
1061 | fprintf(stderr, "failed to create lock\n"); | |
1062 | goto err; | |
1063 | } | |
1064 | ||
1065 | c->privlock = lxc_newlock(NULL); | |
1066 | if (!c->privlock) { | |
1067 | fprintf(stderr, "failed to alloc privlock\n"); | |
1068 | goto err; | |
1069 | } | |
1070 | ||
afeecbba | 1071 | if (!set_config_filename(c)) { |
72d0e1cb SG |
1072 | fprintf(stderr, "Error allocating config file pathname\n"); |
1073 | goto err; | |
1074 | } | |
72d0e1cb SG |
1075 | |
1076 | if (file_exists(c->configfile)) | |
1077 | lxcapi_load_config(c, NULL); | |
1078 | ||
1079 | // assign the member functions | |
1080 | c->is_defined = lxcapi_is_defined; | |
1081 | c->state = lxcapi_state; | |
1082 | c->is_running = lxcapi_is_running; | |
1083 | c->freeze = lxcapi_freeze; | |
1084 | c->unfreeze = lxcapi_unfreeze; | |
1085 | c->init_pid = lxcapi_init_pid; | |
1086 | c->load_config = lxcapi_load_config; | |
1087 | c->want_daemonize = lxcapi_want_daemonize; | |
1088 | c->start = lxcapi_start; | |
1089 | c->startl = lxcapi_startl; | |
1090 | c->stop = lxcapi_stop; | |
1091 | c->config_file_name = lxcapi_config_file_name; | |
1092 | c->wait = lxcapi_wait; | |
1093 | c->set_config_item = lxcapi_set_config_item; | |
1094 | c->destroy = lxcapi_destroy; | |
1095 | c->save_config = lxcapi_save_config; | |
1096 | c->get_keys = lxcapi_get_keys; | |
1097 | c->create = lxcapi_create; | |
1098 | c->createl = lxcapi_createl; | |
1099 | c->shutdown = lxcapi_shutdown; | |
1100 | c->clear_config_item = lxcapi_clear_config_item; | |
1101 | c->get_config_item = lxcapi_get_config_item; | |
794dd120 SH |
1102 | c->get_cgroup_item = lxcapi_get_cgroup_item; |
1103 | c->set_cgroup_item = lxcapi_set_cgroup_item; | |
2a59a681 SH |
1104 | c->get_config_path = lxcapi_get_config_path; |
1105 | c->set_config_path = lxcapi_set_config_path; | |
72d0e1cb SG |
1106 | |
1107 | /* we'll allow the caller to update these later */ | |
ab1bf971 | 1108 | if (lxc_log_init(NULL, "none", NULL, "lxc_container", 0, c->config_path)) { |
72d0e1cb SG |
1109 | fprintf(stderr, "failed to open log\n"); |
1110 | goto err; | |
1111 | } | |
1112 | ||
72d0e1cb SG |
1113 | return c; |
1114 | ||
1115 | err: | |
1116 | lxc_container_free(c); | |
1117 | return NULL; | |
1118 | } | |
1119 | ||
4a7c7daa | 1120 | int lxc_get_wait_states(const char **states) |
72d0e1cb SG |
1121 | { |
1122 | int i; | |
1123 | ||
1124 | if (states) | |
1125 | for (i=0; i<MAX_STATE; i++) | |
1126 | states[i] = lxc_state2str(i); | |
1127 | return MAX_STATE; | |
1128 | } |