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