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