]> git.proxmox.com Git - mirror_lxc.git/blob - src/python-lxc/lxc.c
b69116d798b0370164e2748e36d45c3bd31da086
[mirror_lxc.git] / src / python-lxc / lxc.c
1 /*
2 * python-lxc: Python bindings for LXC
3 *
4 * (C) Copyright Canonical Ltd. 2012-2013
5 *
6 * Authors:
7 * Stéphane Graber <stgraber@ubuntu.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
22 * USA
23 */
24
25 #include <Python.h>
26 #include "structmember.h"
27 #include <lxc/lxccontainer.h>
28 #include <stdio.h>
29 #include <sys/wait.h>
30 #include <sched.h>
31
32 /*
33 * CLONE_* definitions copied from lxc/namespace.h
34 */
35 #ifndef CLONE_FS
36 # define CLONE_FS 0x00000200
37 #endif
38 #ifndef CLONE_NEWNS
39 # define CLONE_NEWNS 0x00020000
40 #endif
41 #ifndef CLONE_NEWCGROUP
42 # define CLONE_NEWCGROUP 0x02000000
43 #endif
44 #ifndef CLONE_NEWUTS
45 # define CLONE_NEWUTS 0x04000000
46 #endif
47 #ifndef CLONE_NEWIPC
48 # define CLONE_NEWIPC 0x08000000
49 #endif
50 #ifndef CLONE_NEWUSER
51 # define CLONE_NEWUSER 0x10000000
52 #endif
53 #ifndef CLONE_NEWPID
54 # define CLONE_NEWPID 0x20000000
55 #endif
56 #ifndef CLONE_NEWNET
57 # define CLONE_NEWNET 0x40000000
58 #endif
59
60 /* From sys/personality.h */
61 #define PER_LINUX 0x0000
62 #define PER_LINUX32 0x0008
63
64 /* Helper functions */
65
66 /* Copied from lxc/utils.c */
67 static int lxc_wait_for_pid_status(pid_t pid)
68 {
69 int status, ret;
70
71 again:
72 ret = waitpid(pid, &status, 0);
73 if (ret == -1) {
74 if (errno == EINTR)
75 goto again;
76 return -1;
77 }
78 if (ret != pid)
79 goto again;
80 return status;
81 }
82
83 /* Copied from lxc/confile.c, with HAVE_SYS_PERSONALITY_H check removed */
84 signed long lxc_config_parse_arch(const char *arch)
85 {
86 struct per_name {
87 char *name;
88 unsigned long per;
89 } pername[] = {
90 { "x86", PER_LINUX32 },
91 { "linux32", PER_LINUX32 },
92 { "i386", PER_LINUX32 },
93 { "i486", PER_LINUX32 },
94 { "i586", PER_LINUX32 },
95 { "i686", PER_LINUX32 },
96 { "athlon", PER_LINUX32 },
97 { "linux64", PER_LINUX },
98 { "x86_64", PER_LINUX },
99 { "amd64", PER_LINUX },
100 };
101 size_t len = sizeof(pername) / sizeof(pername[0]);
102
103 size_t i;
104
105 for (i = 0; i < len; i++) {
106 if (!strcmp(pername[i].name, arch))
107 return pername[i].per;
108 }
109
110 return -1;
111 }
112
113 char**
114 convert_tuple_to_char_pointer_array(PyObject *argv) {
115 int argc;
116 int i, j;
117 char **result;
118
119 /* not a list or tuple */
120 if (!PyList_Check(argv) && !PyTuple_Check(argv)) {
121 PyErr_SetString(PyExc_TypeError, "Expected list or tuple.");
122 return NULL;
123 }
124
125 argc = PySequence_Fast_GET_SIZE(argv);
126
127 result = (char**) calloc(argc + 1, sizeof(char*));
128
129 if (result == NULL) {
130 PyErr_SetNone(PyExc_MemoryError);
131 return NULL;
132 }
133
134 for (i = 0; i < argc; i++) {
135 char *str = NULL;
136 PyObject *pystr = NULL;
137 PyObject *pyobj = PySequence_Fast_GET_ITEM(argv, i);
138 assert(pyobj != NULL);
139
140 if (!PyUnicode_Check(pyobj)) {
141 PyErr_SetString(PyExc_ValueError, "Expected a string");
142 goto error;
143 }
144
145 pystr = PyUnicode_AsUTF8String(pyobj);
146 if (!pystr) {
147 /* Maybe it wasn't UTF-8 encoded. An exception is already set. */
148 goto error;
149 }
150
151 str = PyBytes_AsString(pystr);
152 if (!str) {
153 /* Maybe pystr wasn't a valid object. An exception is already set.
154 */
155 Py_DECREF(pystr);
156 goto error;
157 }
158
159 /* We must make a copy of str, because it points into internal memory
160 * which we do not own. Assume it's NULL terminated, otherwise we'd
161 * have to use PyUnicode_AsUTF8AndSize() and be explicit about copying
162 * the memory.
163 */
164 result[i] = strdup(str);
165
166 /* Do not decref pyobj since we stole a reference by using
167 * PyTuple_GET_ITEM().
168 */
169 Py_DECREF(pystr);
170 if (result[i] == NULL) {
171 PyErr_SetNone(PyExc_MemoryError);
172 goto error;
173 }
174 }
175
176 result[argc] = NULL;
177 return result;
178
179 error:
180 /* We can only iterate up to but not including i because malloc() does not
181 * initialize its memory. Thus if we got here, i points to the index
182 * after the last strdup'd entry in result.
183 */
184 for (j = 0; j < i; j++)
185 free(result[j]);
186 free(result);
187 return NULL;
188 }
189
190 struct lxc_attach_python_payload {
191 PyObject *fn;
192 PyObject *arg;
193 };
194
195 static int lxc_attach_python_exec(void* _payload)
196 {
197 /* This function is the first one to be called after attaching to a
198 * container. As lxc_attach() calls fork() PyOS_AfterFork should be called
199 * in the new process if the Python interpreter will continue to be used.
200 */
201 PyOS_AfterFork();
202
203 struct lxc_attach_python_payload *payload =
204 (struct lxc_attach_python_payload *)_payload;
205 PyObject *result = PyObject_CallFunctionObjArgs(payload->fn,
206 payload->arg, NULL);
207
208 if (!result) {
209 PyErr_Print();
210 return -1;
211 }
212 if (PyLong_Check(result))
213 return (int)PyLong_AsLong(result);
214 else
215 return -1;
216 }
217
218 static void lxc_attach_free_options(lxc_attach_options_t *options);
219
220 static lxc_attach_options_t *lxc_attach_parse_options(PyObject *kwds)
221 {
222 static char *kwlist[] = {"attach_flags", "namespaces", "personality",
223 "initial_cwd", "uid", "gid", "env_policy",
224 "extra_env_vars", "extra_keep_env", "stdin",
225 "stdout", "stderr", NULL};
226 long temp_uid, temp_gid;
227 int temp_env_policy;
228 PyObject *extra_env_vars_obj = NULL;
229 PyObject *extra_keep_env_obj = NULL;
230 PyObject *stdin_obj = NULL;
231 PyObject *stdout_obj = NULL;
232 PyObject *stderr_obj = NULL;
233 PyObject *initial_cwd_obj = NULL;
234 PyObject *dummy = NULL;
235 bool parse_result;
236
237 lxc_attach_options_t default_options = LXC_ATTACH_OPTIONS_DEFAULT;
238 lxc_attach_options_t *options = malloc(sizeof(*options));
239
240 if (!options) {
241 PyErr_SetNone(PyExc_MemoryError);
242 return NULL;
243 }
244 memcpy(options, &default_options, sizeof(*options));
245
246 /* we need some dummy variables because we can't be sure
247 * the data types match completely */
248 temp_uid = -1;
249 temp_gid = -1;
250 temp_env_policy = options->env_policy;
251
252 /* we need a dummy tuple */
253 dummy = PyTuple_New(0);
254
255 parse_result = PyArg_ParseTupleAndKeywords(dummy, kwds, "|iilO&lliOOOOO",
256 kwlist, &options->attach_flags,
257 &options->namespaces,
258 &options->personality,
259 PyUnicode_FSConverter,
260 &initial_cwd_obj, &temp_uid,
261 &temp_gid, &temp_env_policy,
262 &extra_env_vars_obj,
263 &extra_keep_env_obj,
264 &stdin_obj, &stdout_obj,
265 &stderr_obj);
266
267 /* immediately get rid of the dummy tuple */
268 Py_DECREF(dummy);
269
270 if (!parse_result) {
271 lxc_attach_free_options(options);
272 return NULL;
273 }
274
275 /* duplicate the string, so we don't depend on some random Python object */
276 if (initial_cwd_obj != NULL) {
277 options->initial_cwd = strndup(PyBytes_AsString(initial_cwd_obj),
278 PyBytes_Size(initial_cwd_obj));
279 Py_DECREF(initial_cwd_obj);
280 }
281
282 /* do the type conversion from the types that match the parse string */
283 if (temp_uid != -1) options->uid = (uid_t)temp_uid;
284 if (temp_gid != -1) options->gid = (gid_t)temp_gid;
285 options->env_policy = (lxc_attach_env_policy_t)temp_env_policy;
286
287 if (extra_env_vars_obj)
288 options->extra_env_vars =
289 convert_tuple_to_char_pointer_array(extra_env_vars_obj);
290 if (extra_keep_env_obj)
291 options->extra_keep_env =
292 convert_tuple_to_char_pointer_array(extra_keep_env_obj);
293 if (stdin_obj) {
294 options->stdin_fd = PyObject_AsFileDescriptor(stdin_obj);
295 if (options->stdin_fd < 0) {
296 lxc_attach_free_options(options);
297 return NULL;
298 }
299 }
300 if (stdout_obj) {
301 options->stdout_fd = PyObject_AsFileDescriptor(stdout_obj);
302 if (options->stdout_fd < 0) {
303 lxc_attach_free_options(options);
304 return NULL;
305 }
306 }
307 if (stderr_obj) {
308 options->stderr_fd = PyObject_AsFileDescriptor(stderr_obj);
309 if (options->stderr_fd < 0) {
310 lxc_attach_free_options(options);
311 return NULL;
312 }
313 }
314
315 return options;
316 }
317
318 void lxc_attach_free_options(lxc_attach_options_t *options)
319 {
320 int i;
321 if (!options)
322 return;
323 free(options->initial_cwd);
324 if (options->extra_env_vars) {
325 for (i = 0; options->extra_env_vars[i]; i++)
326 free(options->extra_env_vars[i]);
327 free(options->extra_env_vars);
328 }
329 if (options->extra_keep_env) {
330 for (i = 0; options->extra_keep_env[i]; i++)
331 free(options->extra_keep_env[i]);
332 free(options->extra_keep_env);
333 }
334 free(options);
335 }
336
337 /* Module functions */
338 static PyObject *
339 LXC_arch_to_personality(PyObject *self, PyObject *arg)
340 {
341 long rv = -1;
342 PyObject *pystr = NULL;
343 char *str;
344
345 if (!PyUnicode_Check(arg)) {
346 PyErr_SetString(PyExc_ValueError, "Expected a string");
347 return NULL;
348 }
349
350 pystr = PyUnicode_AsUTF8String(arg);
351 if (!pystr)
352 return NULL;
353
354 str = PyBytes_AsString(pystr);
355 if (!str)
356 goto out;
357
358 rv = lxc_config_parse_arch(str);
359 if (rv == -1)
360 PyErr_SetString(PyExc_KeyError, "Failed to lookup architecture.");
361
362 out:
363 Py_DECREF(pystr);
364 return rv == -1 ? NULL : PyLong_FromLong(rv);
365 }
366
367 static PyObject *
368 LXC_attach_run_command(PyObject *self, PyObject *arg)
369 {
370 PyObject *args_obj = NULL;
371 int i, rv;
372 lxc_attach_command_t cmd = {
373 NULL, /* program */
374 NULL /* argv[] */
375 };
376
377 if (!PyArg_ParseTuple(arg, "sO", (const char**)&cmd.program, &args_obj))
378 return NULL;
379 if (args_obj && PyList_Check(args_obj)) {
380 cmd.argv = convert_tuple_to_char_pointer_array(args_obj);
381 } else {
382 PyErr_Format(PyExc_TypeError, "Second part of tuple passed to "
383 "attach_run_command must be a list.");
384 return NULL;
385 }
386
387 if (!cmd.argv)
388 return NULL;
389
390 rv = lxc_attach_run_command(&cmd);
391
392 for (i = 0; cmd.argv[i]; i++)
393 free(cmd.argv[i]);
394 free(cmd.argv);
395
396 return PyLong_FromLong(rv);
397 }
398
399 static PyObject *
400 LXC_attach_run_shell(PyObject *self, PyObject *arg)
401 {
402 int rv;
403
404 rv = lxc_attach_run_shell(NULL);
405
406 return PyLong_FromLong(rv);
407 }
408
409 static PyObject *
410 LXC_get_global_config_item(PyObject *self, PyObject *args, PyObject *kwds)
411 {
412 static char *kwlist[] = {"key", NULL};
413 char* key = NULL;
414 const char* value = NULL;
415
416 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s|", kwlist,
417 &key))
418 return NULL;
419
420 value = lxc_get_global_config_item(key);
421
422 if (!value) {
423 PyErr_SetString(PyExc_KeyError, "Invalid configuration key");
424 return NULL;
425 }
426
427 return PyUnicode_FromString(value);
428 }
429
430 static PyObject *
431 LXC_get_version(PyObject *self, PyObject *args)
432 {
433 return PyUnicode_FromString(lxc_get_version());
434 }
435
436 static PyObject *
437 LXC_list_containers(PyObject *self, PyObject *args, PyObject *kwds)
438 {
439 char **names = NULL;
440 PyObject *list = NULL;
441 int list_count = 0;
442
443 int list_active = 1;
444 int list_defined = 1;
445
446 PyObject *py_list_active = NULL;
447 PyObject *py_list_defined = NULL;
448
449 char* config_path = NULL;
450
451 int i = 0;
452 PyObject *vargs = NULL;
453 static char *kwlist[] = {"active", "defined", "config_path", NULL};
454
455 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOs", kwlist,
456 &py_list_active,
457 &py_list_defined,
458 &config_path, &vargs))
459 return NULL;
460
461 /* We default to listing everything */
462 if (py_list_active && py_list_active != Py_True) {
463 list_active = 0;
464 }
465
466 if (py_list_defined && py_list_defined != Py_True) {
467 list_defined = 0;
468 }
469
470 /* Call the right API function based on filters */
471 if (list_active == 1 && list_defined == 1)
472 list_count = list_all_containers(config_path, &names, NULL);
473 else if (list_active == 1)
474 list_count = list_active_containers(config_path, &names, NULL);
475 else if (list_defined == 1)
476 list_count = list_defined_containers(config_path, &names, NULL);
477
478 /* Handle failure */
479 if (list_count < 0) {
480 PyErr_SetString(PyExc_ValueError, "failure to list containers");
481 return NULL;
482 }
483
484 /* Generate the tuple */
485 list = PyTuple_New(list_count);
486 for (i = 0; i < list_count; i++) {
487 PyTuple_SET_ITEM(list, i, PyUnicode_FromString(names[i]));
488 free(names[i]);
489 }
490 free(names);
491
492 return list;
493 }
494
495 /* Base type and functions for Container */
496 typedef struct {
497 PyObject_HEAD
498 struct lxc_container *container;
499 } Container;
500
501 static void
502 Container_dealloc(Container* self)
503 {
504 lxc_container_put(self->container);
505 Py_TYPE(self)->tp_free((PyObject*)self);
506 }
507
508 static int
509 Container_init(Container *self, PyObject *args, PyObject *kwds)
510 {
511 static char *kwlist[] = {"name", "config_path", NULL};
512 char *name = NULL;
513 PyObject *fs_config_path = NULL;
514 char *config_path = NULL;
515
516 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|O&", kwlist,
517 &name,
518 PyUnicode_FSConverter, &fs_config_path))
519 return -1;
520
521 if (fs_config_path != NULL) {
522 config_path = PyBytes_AS_STRING(fs_config_path);
523 assert(config_path != NULL);
524 }
525
526 self->container = lxc_container_new(name, config_path);
527 if (!self->container) {
528 Py_XDECREF(fs_config_path);
529
530 PyErr_Format(PyExc_RuntimeError, "%s:%s:%d: error during init for container '%s'.",
531 __FUNCTION__, __FILE__, __LINE__, name);
532 return -1;
533 }
534
535 Py_XDECREF(fs_config_path);
536 return 0;
537 }
538
539 static PyObject *
540 Container_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
541 {
542 Container *self;
543
544 self = (Container *)type->tp_alloc(type, 0);
545
546 return (PyObject *)self;
547 }
548
549 /* Container properties */
550 static PyObject *
551 Container_config_file_name(Container *self, void *closure)
552 {
553 return PyUnicode_FromString(
554 self->container->config_file_name(self->container));
555 }
556
557 static PyObject *
558 Container_controllable(Container *self, void *closure)
559 {
560 if (self->container->may_control(self->container)) {
561 Py_RETURN_TRUE;
562 }
563
564 Py_RETURN_FALSE;
565 }
566
567 static PyObject *
568 Container_defined(Container *self, void *closure)
569 {
570 if (self->container->is_defined(self->container)) {
571 Py_RETURN_TRUE;
572 }
573
574 Py_RETURN_FALSE;
575 }
576
577 static PyObject *
578 Container_init_pid(Container *self, void *closure)
579 {
580 return PyLong_FromLong(self->container->init_pid(self->container));
581 }
582
583 static PyObject *
584 Container_name(Container *self, void *closure)
585 {
586 return PyUnicode_FromString(self->container->name);
587 }
588
589 static PyObject *
590 Container_running(Container *self, void *closure)
591 {
592 if (self->container->is_running(self->container)) {
593 Py_RETURN_TRUE;
594 }
595
596 Py_RETURN_FALSE;
597 }
598
599 static PyObject *
600 Container_state(Container *self, void *closure)
601 {
602 return PyUnicode_FromString(self->container->state(self->container));
603 }
604
605 /* Container Functions */
606 static PyObject *
607 Container_attach_interface(Container *self, PyObject *args, PyObject *kwds)
608 {
609 static char *kwlist[] = {"src_ifname", "dst_ifname", NULL};
610 char *src_name = NULL;
611 char *dst_name = NULL;
612 PyObject *py_src_name = NULL;
613 PyObject *py_dst_name = NULL;
614
615 if (! PyArg_ParseTupleAndKeywords(args, kwds, "O&|O&", kwlist,
616 PyUnicode_FSConverter, &py_src_name,
617 PyUnicode_FSConverter, &py_dst_name))
618 return NULL;
619
620 if (py_src_name != NULL) {
621 src_name = PyBytes_AS_STRING(py_src_name);
622 assert(src_name != NULL);
623 }
624
625 if (py_dst_name != NULL) {
626 dst_name = PyBytes_AS_STRING(py_dst_name);
627 assert(dst_name != NULL);
628 }
629
630 if (self->container->attach_interface(self->container, src_name, dst_name)) {
631 Py_XDECREF(py_src_name);
632 Py_XDECREF(py_dst_name);
633 Py_RETURN_TRUE;
634 }
635
636 Py_XDECREF(py_src_name);
637 Py_XDECREF(py_dst_name);
638 Py_RETURN_FALSE;
639 }
640
641 static PyObject *
642 Container_detach_interface(Container *self, PyObject *args, PyObject *kwds)
643 {
644 static char *kwlist[] = {"ifname", NULL};
645 char *ifname = NULL;
646 PyObject *py_ifname = NULL;
647
648 if (! PyArg_ParseTupleAndKeywords(args, kwds, "O&", kwlist,
649 PyUnicode_FSConverter, &py_ifname))
650 return NULL;
651
652 if (py_ifname != NULL) {
653 ifname = PyBytes_AS_STRING(py_ifname);
654 assert(ifname != NULL);
655 }
656
657 if (self->container->detach_interface(self->container, ifname, NULL)) {
658 Py_XDECREF(py_ifname);
659 Py_RETURN_TRUE;
660 }
661
662 Py_XDECREF(py_ifname);
663 Py_RETURN_FALSE;
664 }
665
666 static PyObject *
667 Container_add_device_node(Container *self, PyObject *args, PyObject *kwds)
668 {
669 static char *kwlist[] = {"src_path", "dest_path", NULL};
670 char *src_path = NULL;
671 char *dst_path = NULL;
672 PyObject *py_src_path = NULL;
673 PyObject *py_dst_path = NULL;
674
675 if (! PyArg_ParseTupleAndKeywords(args, kwds, "O&|O&", kwlist,
676 PyUnicode_FSConverter, &py_src_path,
677 PyUnicode_FSConverter, &py_dst_path))
678 return NULL;
679
680 if (py_src_path != NULL) {
681 src_path = PyBytes_AS_STRING(py_src_path);
682 assert(src_path != NULL);
683 }
684
685 if (py_dst_path != NULL) {
686 dst_path = PyBytes_AS_STRING(py_dst_path);
687 assert(dst_path != NULL);
688 }
689
690 if (self->container->add_device_node(self->container, src_path,
691 dst_path)) {
692 Py_XDECREF(py_src_path);
693 Py_XDECREF(py_dst_path);
694 Py_RETURN_TRUE;
695 }
696
697 Py_XDECREF(py_src_path);
698 Py_XDECREF(py_dst_path);
699 Py_RETURN_FALSE;
700 }
701
702 static PyObject *
703 Container_attach_and_possibly_wait(Container *self, PyObject *args,
704 PyObject *kwds, int wait)
705 {
706 struct lxc_attach_python_payload payload = { NULL, NULL };
707 lxc_attach_options_t *options = NULL;
708 long ret;
709 pid_t pid;
710
711 if (!PyArg_ParseTuple(args, "O|O", &payload.fn, &payload.arg))
712 return NULL;
713 if (!PyCallable_Check(payload.fn)) {
714 PyErr_Format(PyExc_TypeError, "attach: object not callable");
715 return NULL;
716 }
717
718 options = lxc_attach_parse_options(kwds);
719 if (!options)
720 return NULL;
721
722 ret = self->container->attach(self->container, lxc_attach_python_exec,
723 &payload, options, &pid);
724 if (ret < 0)
725 goto out;
726
727 if (wait) {
728 Py_BEGIN_ALLOW_THREADS
729 ret = lxc_wait_for_pid_status(pid);
730 Py_END_ALLOW_THREADS
731 /* handle case where attach fails */
732 if (WIFEXITED(ret) && WEXITSTATUS(ret) == 255)
733 ret = -1;
734 } else {
735 ret = (long)pid;
736 }
737
738 out:
739 lxc_attach_free_options(options);
740 return PyLong_FromLong(ret);
741 }
742
743 static PyObject *
744 Container_attach(Container *self, PyObject *args, PyObject *kwds)
745 {
746 return Container_attach_and_possibly_wait(self, args, kwds, 0);
747 }
748
749 static PyObject *
750 Container_attach_wait(Container *self, PyObject *args, PyObject *kwds)
751 {
752 return Container_attach_and_possibly_wait(self, args, kwds, 1);
753 }
754
755 static PyObject *
756 Container_clear_config(Container *self, PyObject *args, PyObject *kwds)
757 {
758 self->container->clear_config(self->container);
759
760 Py_RETURN_NONE;
761 }
762
763 static PyObject *
764 Container_clear_config_item(Container *self, PyObject *args, PyObject *kwds)
765 {
766 static char *kwlist[] = {"key", NULL};
767 char *key = NULL;
768
769 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist,
770 &key))
771 return NULL;
772
773 if (self->container->clear_config_item(self->container, key)) {
774 Py_RETURN_TRUE;
775 }
776
777 Py_RETURN_FALSE;
778 }
779
780 static PyObject *
781 Container_clone(Container *self, PyObject *args, PyObject *kwds)
782 {
783 char *newname = NULL;
784 char *config_path = NULL;
785 int flags = 0;
786 char *bdevtype = NULL;
787 char *bdevdata = NULL;
788 unsigned long newsize = 0;
789 char **hookargs = NULL;
790
791 PyObject *py_hookargs = NULL;
792 PyObject *py_config_path = NULL;
793 struct lxc_container *new_container = NULL;
794 int i = 0;
795
796 static char *kwlist[] = {"newname", "config_path", "flags", "bdevtype",
797 "bdevdata", "newsize", "hookargs", NULL};
798 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s|O&isskO", kwlist,
799 &newname,
800 PyUnicode_FSConverter, &py_config_path,
801 &flags, &bdevtype, &bdevdata, &newsize,
802 &py_hookargs))
803 return NULL;
804
805 if (py_hookargs) {
806 if (PyTuple_Check(py_hookargs)) {
807 hookargs = convert_tuple_to_char_pointer_array(py_hookargs);
808 if (!hookargs) {
809 return NULL;
810 }
811 }
812 else {
813 PyErr_SetString(PyExc_ValueError, "hookargs needs to be a tuple");
814 return NULL;
815 }
816 }
817
818 if (py_config_path != NULL) {
819 config_path = PyBytes_AS_STRING(py_config_path);
820 assert(config_path != NULL);
821 }
822
823 new_container = self->container->clone(self->container, newname,
824 config_path, flags, bdevtype,
825 bdevdata, newsize, hookargs);
826
827 Py_XDECREF(py_config_path);
828
829 if (hookargs) {
830 for (i = 0; i < PyTuple_GET_SIZE(py_hookargs); i++)
831 free(hookargs[i]);
832 free(hookargs);
833 }
834
835 if (new_container == NULL) {
836 Py_RETURN_FALSE;
837 }
838
839 lxc_container_put(new_container);
840
841 Py_RETURN_TRUE;
842 }
843
844 static PyObject *
845 Container_console(Container *self, PyObject *args, PyObject *kwds)
846 {
847 static char *kwlist[] = {"ttynum", "stdinfd", "stdoutfd", "stderrfd",
848 "escape", NULL};
849 int ttynum = -1, stdinfd = 0, stdoutfd = 1, stderrfd = 2, escape = 1;
850
851 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|iiiii", kwlist,
852 &ttynum, &stdinfd, &stdoutfd, &stderrfd,
853 &escape))
854 return NULL;
855
856 if (self->container->console(self->container, ttynum,
857 stdinfd, stdoutfd, stderrfd, escape) == 0) {
858 Py_RETURN_TRUE;
859 }
860 Py_RETURN_FALSE;
861 }
862
863 static PyObject *
864 Container_console_getfd(Container *self, PyObject *args, PyObject *kwds)
865 {
866 static char *kwlist[] = {"ttynum", NULL};
867 int ttynum = -1, masterfd;
868
869 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist, &ttynum))
870 return NULL;
871
872 if (self->container->console_getfd(self->container, &ttynum,
873 &masterfd) < 0) {
874 PyErr_SetString(PyExc_ValueError, "Unable to allocate tty");
875 return NULL;
876 }
877 return PyLong_FromLong(masterfd);
878 }
879
880 static PyObject *
881 Container_create(Container *self, PyObject *args, PyObject *kwds)
882 {
883 char* template_name = NULL;
884 int flags = 0;
885 char** create_args = {NULL};
886 PyObject *retval = NULL;
887 PyObject *vargs = NULL;
888 char *bdevtype = NULL;
889 int i = 0;
890 static char *kwlist[] = {"template", "flags", "bdevtype", "args", NULL};
891 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|sisO", kwlist,
892 &template_name, &flags, &bdevtype, &vargs))
893 return NULL;
894
895 if (vargs) {
896 if (PyTuple_Check(vargs)) {
897 create_args = convert_tuple_to_char_pointer_array(vargs);
898 if (!create_args) {
899 return NULL;
900 }
901 }
902 else {
903 PyErr_SetString(PyExc_ValueError, "args needs to be a tuple");
904 return NULL;
905 }
906 }
907
908 if (self->container->create(self->container, template_name, bdevtype, NULL,
909 flags, create_args))
910 retval = Py_True;
911 else
912 retval = Py_False;
913
914 if (vargs) {
915 /* We cannot have gotten here unless vargs was given and create_args
916 * was successfully allocated.
917 */
918 for (i = 0; i < PyTuple_GET_SIZE(vargs); i++)
919 free(create_args[i]);
920 free(create_args);
921 }
922
923 Py_INCREF(retval);
924 return retval;
925 }
926
927 static PyObject *
928 Container_destroy(Container *self, PyObject *args, PyObject *kwds)
929 {
930 if (self->container->destroy(self->container)) {
931 Py_RETURN_TRUE;
932 }
933
934 Py_RETURN_FALSE;
935 }
936
937 static PyObject *
938 Container_freeze(Container *self, PyObject *args, PyObject *kwds)
939 {
940 if (self->container->freeze(self->container)) {
941 Py_RETURN_TRUE;
942 }
943
944 Py_RETURN_FALSE;
945 }
946
947 static PyObject *
948 Container_get_cgroup_item(Container *self, PyObject *args, PyObject *kwds)
949 {
950 static char *kwlist[] = {"key", NULL};
951 char* key = NULL;
952 int len = 0;
953 char* value;
954 PyObject *ret = NULL;
955
956 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist,
957 &key))
958 return NULL;
959
960 len = self->container->get_cgroup_item(self->container, key, NULL, 0);
961
962 if (len < 0) {
963 PyErr_SetString(PyExc_KeyError, "Invalid cgroup entry");
964 return NULL;
965 }
966
967 value = (char*) malloc(sizeof(char)*len + 1);
968 if (value == NULL)
969 return PyErr_NoMemory();
970
971 if (self->container->get_cgroup_item(self->container,
972 key, value, len + 1) != len) {
973 PyErr_SetString(PyExc_ValueError, "Unable to read config value");
974 free(value);
975 return NULL;
976 }
977
978 ret = PyUnicode_FromString(value);
979 free(value);
980 return ret;
981 }
982
983 static PyObject *
984 Container_get_config_item(Container *self, PyObject *args, PyObject *kwds)
985 {
986 static char *kwlist[] = {"key", NULL};
987 char* key = NULL;
988 int len = 0;
989 char* value;
990 PyObject *ret = NULL;
991
992 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s|", kwlist,
993 &key))
994 return NULL;
995
996 len = self->container->get_config_item(self->container, key, NULL, 0);
997
998 if (len < 0) {
999 PyErr_SetString(PyExc_KeyError, "Invalid configuration key");
1000 return NULL;
1001 }
1002
1003 if (len == 0) {
1004 return PyUnicode_FromString("");
1005 }
1006
1007 value = (char*) malloc(sizeof(char)*len + 1);
1008 if (value == NULL)
1009 return PyErr_NoMemory();
1010
1011 if (self->container->get_config_item(self->container,
1012 key, value, len + 1) != len) {
1013 PyErr_SetString(PyExc_ValueError, "Unable to read config value");
1014 free(value);
1015 return NULL;
1016 }
1017
1018 ret = PyUnicode_FromString(value);
1019 free(value);
1020 return ret;
1021 }
1022
1023 static PyObject *
1024 Container_get_config_path(Container *self, PyObject *args, PyObject *kwds)
1025 {
1026 return PyUnicode_FromString(
1027 self->container->get_config_path(self->container));
1028 }
1029
1030 static PyObject *
1031 Container_get_keys(Container *self, PyObject *args, PyObject *kwds)
1032 {
1033 static char *kwlist[] = {"key", NULL};
1034 char* key = NULL;
1035 int len = 0;
1036 char* value;
1037 PyObject *ret = NULL;
1038
1039 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist,
1040 &key))
1041 return NULL;
1042
1043 len = self->container->get_keys(self->container, key, NULL, 0);
1044
1045 if (len < 0) {
1046 PyErr_SetString(PyExc_KeyError, "Invalid configuration key");
1047 return NULL;
1048 }
1049
1050 value = (char*) malloc(sizeof(char)*len + 1);
1051 if (value == NULL)
1052 return PyErr_NoMemory();
1053
1054 if (self->container->get_keys(self->container,
1055 key, value, len + 1) != len) {
1056 PyErr_SetString(PyExc_ValueError, "Unable to read config keys");
1057 free(value);
1058 return NULL;
1059 }
1060
1061 ret = PyUnicode_FromString(value);
1062 free(value);
1063 return ret;
1064 }
1065
1066 static PyObject *
1067 Container_get_interfaces(Container *self)
1068 {
1069 int i = 0;
1070 char** interfaces = NULL;
1071
1072 PyObject* ret;
1073
1074 /* Get the interfaces */
1075 interfaces = self->container->get_interfaces(self->container);
1076 if (!interfaces)
1077 return PyTuple_New(0);
1078
1079 /* Count the entries */
1080 while (interfaces[i])
1081 i++;
1082
1083 /* Create the new tuple */
1084 ret = PyTuple_New(i);
1085 if (!ret)
1086 return NULL;
1087
1088 /* Add the entries to the tuple and free the memory */
1089 i = 0;
1090 while (interfaces[i]) {
1091 PyObject *unicode = PyUnicode_FromString(interfaces[i]);
1092 if (!unicode) {
1093 Py_DECREF(ret);
1094 ret = NULL;
1095 break;
1096 }
1097 PyTuple_SET_ITEM(ret, i, unicode);
1098 i++;
1099 }
1100
1101 /* Free the list of IPs */
1102 i = 0;
1103 while (interfaces[i]) {
1104 free(interfaces[i]);
1105 i++;
1106 }
1107 free(interfaces);
1108
1109 return ret;
1110 }
1111
1112 static PyObject *
1113 Container_get_ips(Container *self, PyObject *args, PyObject *kwds)
1114 {
1115 static char *kwlist[] = {"interface", "family", "scope", NULL};
1116 char* interface = NULL;
1117 char* family = NULL;
1118 int scope = 0;
1119
1120 int i = 0;
1121 char** ips = NULL;
1122
1123 PyObject* ret;
1124
1125 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|ssi", kwlist,
1126 &interface, &family, &scope))
1127 return NULL;
1128
1129 /* Get the IPs */
1130 ips = self->container->get_ips(self->container, interface, family, scope);
1131 if (!ips)
1132 return PyTuple_New(0);
1133
1134 /* Count the entries */
1135 while (ips[i])
1136 i++;
1137
1138 /* Create the new tuple */
1139 ret = PyTuple_New(i);
1140 if (!ret)
1141 return NULL;
1142
1143 /* Add the entries to the tuple and free the memory */
1144 i = 0;
1145 while (ips[i]) {
1146 PyObject *unicode = PyUnicode_FromString(ips[i]);
1147 if (!unicode) {
1148 Py_DECREF(ret);
1149 ret = NULL;
1150 break;
1151 }
1152 PyTuple_SET_ITEM(ret, i, unicode);
1153 i++;
1154 }
1155
1156 /* Free the list of IPs */
1157 i = 0;
1158 while (ips[i]) {
1159 free(ips[i]);
1160 i++;
1161 }
1162 free(ips);
1163
1164 return ret;
1165 }
1166
1167 static PyObject *
1168 Container_get_running_config_item(Container *self, PyObject *args,
1169 PyObject *kwds)
1170 {
1171 static char *kwlist[] = {"key", NULL};
1172 char* key = NULL;
1173 char* value = NULL;
1174 PyObject *ret = NULL;
1175
1176 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s|", kwlist,
1177 &key))
1178 return NULL;
1179
1180 value = self->container->get_running_config_item(self->container, key);
1181
1182 if (!value)
1183 Py_RETURN_NONE;
1184
1185 ret = PyUnicode_FromString(value);
1186 free(value);
1187 return ret;
1188 }
1189
1190
1191 static PyObject *
1192 Container_load_config(Container *self, PyObject *args, PyObject *kwds)
1193 {
1194 static char *kwlist[] = {"path", NULL};
1195 PyObject *fs_path = NULL;
1196 char* path = NULL;
1197
1198 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|O&", kwlist,
1199 PyUnicode_FSConverter, &fs_path))
1200 return NULL;
1201
1202 if (fs_path != NULL) {
1203 path = PyBytes_AS_STRING(fs_path);
1204 assert(path != NULL);
1205 }
1206
1207 if (self->container->load_config(self->container, path)) {
1208 Py_XDECREF(fs_path);
1209 Py_RETURN_TRUE;
1210 }
1211
1212 Py_XDECREF(fs_path);
1213 Py_RETURN_FALSE;
1214 }
1215
1216 static PyObject *
1217 Container_reboot(Container *self, PyObject *args, PyObject *kwds)
1218 {
1219 if (self->container->reboot(self->container)) {
1220 Py_RETURN_TRUE;
1221 }
1222
1223 Py_RETURN_FALSE;
1224 }
1225
1226 static PyObject *
1227 Container_rename(Container *self, PyObject *args, PyObject *kwds)
1228 {
1229 char *new_name = NULL;
1230 static char *kwlist[] = {"new_name", NULL};
1231
1232 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s|", kwlist,
1233 &new_name))
1234 return NULL;
1235
1236 if (self->container->rename(self->container, new_name)) {
1237 Py_RETURN_TRUE;
1238 }
1239
1240 Py_RETURN_FALSE;
1241 }
1242
1243 static PyObject *
1244 Container_remove_device_node(Container *self, PyObject *args, PyObject *kwds)
1245 {
1246 static char *kwlist[] = {"src_path", "dest_path", NULL};
1247 char *src_path = NULL;
1248 char *dst_path = NULL;
1249 PyObject *py_src_path = NULL;
1250 PyObject *py_dst_path = NULL;
1251
1252 if (! PyArg_ParseTupleAndKeywords(args, kwds, "O&|O&", kwlist,
1253 PyUnicode_FSConverter, &py_src_path,
1254 PyUnicode_FSConverter, &py_dst_path))
1255 return NULL;
1256
1257 if (py_src_path != NULL) {
1258 src_path = PyBytes_AS_STRING(py_src_path);
1259 assert(src_path != NULL);
1260 }
1261
1262 if (py_dst_path != NULL) {
1263 dst_path = PyBytes_AS_STRING(py_dst_path);
1264 assert(dst_path != NULL);
1265 }
1266
1267 if (self->container->remove_device_node(self->container, src_path,
1268 dst_path)) {
1269 Py_XDECREF(py_src_path);
1270 Py_XDECREF(py_dst_path);
1271 Py_RETURN_TRUE;
1272 }
1273
1274 Py_XDECREF(py_src_path);
1275 Py_XDECREF(py_dst_path);
1276 Py_RETURN_FALSE;
1277 }
1278
1279 static PyObject *
1280 Container_save_config(Container *self, PyObject *args, PyObject *kwds)
1281 {
1282 static char *kwlist[] = {"path", NULL};
1283 PyObject *fs_path = NULL;
1284 char* path = NULL;
1285
1286 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|O&", kwlist,
1287 PyUnicode_FSConverter, &fs_path))
1288 return NULL;
1289
1290 if (fs_path != NULL) {
1291 path = PyBytes_AS_STRING(fs_path);
1292 assert(path != NULL);
1293 }
1294
1295 if (self->container->save_config(self->container, path)) {
1296 Py_XDECREF(fs_path);
1297 Py_RETURN_TRUE;
1298 }
1299
1300 Py_XDECREF(fs_path);
1301 Py_RETURN_FALSE;
1302 }
1303
1304 static PyObject *
1305 Container_set_cgroup_item(Container *self, PyObject *args, PyObject *kwds)
1306 {
1307 static char *kwlist[] = {"key", "value", NULL};
1308 char *key = NULL;
1309 char *value = NULL;
1310
1311 if (! PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwlist,
1312 &key, &value))
1313 return NULL;
1314
1315 if (self->container->set_cgroup_item(self->container, key, value)) {
1316 Py_RETURN_TRUE;
1317 }
1318
1319 Py_RETURN_FALSE;
1320 }
1321
1322 static PyObject *
1323 Container_set_config_item(Container *self, PyObject *args, PyObject *kwds)
1324 {
1325 static char *kwlist[] = {"key", "value", NULL};
1326 char *key = NULL;
1327 char *value = NULL;
1328
1329 if (! PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwlist,
1330 &key, &value))
1331 return NULL;
1332
1333 if (self->container->set_config_item(self->container, key, value)) {
1334 Py_RETURN_TRUE;
1335 }
1336
1337 Py_RETURN_FALSE;
1338 }
1339
1340 static PyObject *
1341 Container_set_config_path(Container *self, PyObject *args, PyObject *kwds)
1342 {
1343 static char *kwlist[] = {"path", NULL};
1344 char *path = NULL;
1345
1346 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist,
1347 &path))
1348 return NULL;
1349
1350 if (self->container->set_config_path(self->container, path)) {
1351 Py_RETURN_TRUE;
1352 }
1353
1354 Py_RETURN_FALSE;
1355 }
1356
1357 static PyObject *
1358 Container_shutdown(Container *self, PyObject *args, PyObject *kwds)
1359 {
1360 static char *kwlist[] = {"timeout", NULL};
1361 int timeout = -1;
1362
1363 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
1364 &timeout))
1365 return NULL;
1366
1367 if (self->container->shutdown(self->container, timeout)) {
1368 Py_RETURN_TRUE;
1369 }
1370
1371 Py_RETURN_FALSE;
1372 }
1373
1374 static PyObject *
1375 Container_snapshot(Container *self, PyObject *args, PyObject *kwds)
1376 {
1377 char *comment_path = NULL;
1378 static char *kwlist[] = {"comment_path", NULL};
1379 int retval = 0;
1380 int ret = 0;
1381 char newname[20];
1382 PyObject *py_comment_path = NULL;
1383
1384 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|O&", kwlist,
1385 PyUnicode_FSConverter, &py_comment_path))
1386 return NULL;
1387
1388 if (py_comment_path != NULL) {
1389 comment_path = PyBytes_AS_STRING(py_comment_path);
1390 assert(comment_path != NULL);
1391 }
1392
1393 retval = self->container->snapshot(self->container, comment_path);
1394
1395 Py_XDECREF(py_comment_path);
1396
1397 if (retval < 0) {
1398 Py_RETURN_FALSE;
1399 }
1400
1401 ret = snprintf(newname, 20, "snap%d", retval);
1402 if (ret < 0 || ret >= 20)
1403 return NULL;
1404
1405
1406 return PyUnicode_FromString(newname);
1407 }
1408
1409 static PyObject *
1410 Container_snapshot_destroy(Container *self, PyObject *args, PyObject *kwds)
1411 {
1412 char *name = NULL;
1413 static char *kwlist[] = {"name", NULL};
1414
1415 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s|", kwlist,
1416 &name))
1417 return NULL;
1418
1419 if (self->container->snapshot_destroy(self->container, name)) {
1420 Py_RETURN_TRUE;
1421 }
1422
1423 Py_RETURN_FALSE;
1424 }
1425
1426 static PyObject *
1427 Container_snapshot_list(Container *self, PyObject *args, PyObject *kwds)
1428 {
1429 struct lxc_snapshot *snap;
1430 int snap_count = 0;
1431 PyObject *list = NULL;
1432 int i = 0;
1433
1434 snap_count = self->container->snapshot_list(self->container, &snap);
1435
1436 if (snap_count < 0) {
1437 PyErr_SetString(PyExc_KeyError, "Unable to list snapshots");
1438 return NULL;
1439 }
1440
1441 list = PyTuple_New(snap_count);
1442 for (i = 0; i < snap_count; i++) {
1443 PyObject *list_entry = NULL;
1444
1445 list_entry = PyTuple_New(4);
1446 PyTuple_SET_ITEM(list_entry, 0,
1447 PyUnicode_FromString(snap[i].name));
1448 PyTuple_SET_ITEM(list_entry, 1,
1449 PyUnicode_FromString(snap[i].comment_pathname));
1450 PyTuple_SET_ITEM(list_entry, 2,
1451 PyUnicode_FromString(snap[i].timestamp));
1452 PyTuple_SET_ITEM(list_entry, 3,
1453 PyUnicode_FromString(snap[i].lxcpath));
1454
1455 snap[i].free(&snap[i]);
1456
1457 PyTuple_SET_ITEM(list, i, list_entry);
1458 }
1459
1460 return list;
1461 }
1462
1463
1464 static PyObject *
1465 Container_snapshot_restore(Container *self, PyObject *args, PyObject *kwds)
1466 {
1467 char *name = NULL;
1468 char *newname = NULL;
1469 static char *kwlist[] = {"name", "newname", NULL};
1470
1471 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s|s", kwlist,
1472 &name, &newname))
1473 return NULL;
1474
1475 if (self->container->snapshot_restore(self->container, name, newname)) {
1476 Py_RETURN_TRUE;
1477 }
1478
1479 Py_RETURN_FALSE;
1480 }
1481
1482 static PyObject *
1483 Container_start(Container *self, PyObject *args, PyObject *kwds)
1484 {
1485 PyObject *useinit = NULL;
1486 PyObject *daemonize = NULL;
1487 PyObject *close_fds = NULL;
1488
1489 PyObject *vargs = NULL;
1490 char** init_args = {NULL};
1491
1492 PyObject *retval = NULL;
1493 int init_useinit = 0, i = 0;
1494 static char *kwlist[] = {"useinit", "daemonize", "close_fds",
1495 "cmd", NULL};
1496
1497 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO", kwlist,
1498 &useinit, &daemonize, &close_fds,
1499 &vargs))
1500 return NULL;
1501
1502 if (useinit && useinit == Py_True) {
1503 init_useinit = 1;
1504 }
1505
1506 if (vargs && PyTuple_Check(vargs)) {
1507 init_args = convert_tuple_to_char_pointer_array(vargs);
1508 if (!init_args) {
1509 return NULL;
1510 }
1511 }
1512
1513 if (close_fds && close_fds == Py_True) {
1514 self->container->want_close_all_fds(self->container, true);
1515 }
1516 else {
1517 self->container->want_close_all_fds(self->container, false);
1518 }
1519
1520 if (!daemonize || daemonize == Py_True) {
1521 self->container->want_daemonize(self->container, true);
1522 }
1523 else {
1524 self->container->want_daemonize(self->container, false);
1525 }
1526
1527 if (self->container->start(self->container, init_useinit, init_args))
1528 retval = Py_True;
1529 else
1530 retval = Py_False;
1531
1532 if (vargs) {
1533 /* We cannot have gotten here unless vargs was given and create_args
1534 * was successfully allocated.
1535 */
1536 for (i = 0; i < PyTuple_GET_SIZE(vargs); i++)
1537 free(init_args[i]);
1538 free(init_args);
1539 }
1540
1541 Py_INCREF(retval);
1542 return retval;
1543 }
1544
1545 static PyObject *
1546 Container_stop(Container *self, PyObject *args, PyObject *kwds)
1547 {
1548 if (self->container->stop(self->container)) {
1549 Py_RETURN_TRUE;
1550 }
1551
1552 Py_RETURN_FALSE;
1553 }
1554
1555 static PyObject *
1556 Container_unfreeze(Container *self, PyObject *args, PyObject *kwds)
1557 {
1558 if (self->container->unfreeze(self->container)) {
1559 Py_RETURN_TRUE;
1560 }
1561
1562 Py_RETURN_FALSE;
1563 }
1564
1565 static PyObject *
1566 Container_wait(Container *self, PyObject *args, PyObject *kwds)
1567 {
1568 static char *kwlist[] = {"state", "timeout", NULL};
1569 char *state = NULL;
1570 int timeout = -1;
1571
1572 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s|i", kwlist,
1573 &state, &timeout))
1574 return NULL;
1575
1576 if (self->container->wait(self->container, state, timeout)) {
1577 Py_RETURN_TRUE;
1578 }
1579
1580 Py_RETURN_FALSE;
1581 }
1582
1583 /* Function/Properties list */
1584 static PyGetSetDef Container_getseters[] = {
1585 {"config_file_name",
1586 (getter)Container_config_file_name, NULL,
1587 "Path to the container configuration",
1588 NULL},
1589 {"controllable",
1590 (getter)Container_controllable, NULL,
1591 "Boolean indicating whether the container may be controlled",
1592 NULL},
1593 {"defined",
1594 (getter)Container_defined, NULL,
1595 "Boolean indicating whether the container configuration exists",
1596 NULL},
1597 {"init_pid",
1598 (getter)Container_init_pid, NULL,
1599 "PID of the container's init process in the host's PID namespace",
1600 NULL},
1601 {"name",
1602 (getter)Container_name, NULL,
1603 "Container name",
1604 NULL},
1605 {"running",
1606 (getter)Container_running, NULL,
1607 "Boolean indicating whether the container is running or not",
1608 NULL},
1609 {"state",
1610 (getter)Container_state, NULL,
1611 "Container state",
1612 NULL},
1613 {NULL, NULL, NULL, NULL, NULL}
1614 };
1615
1616 static PyMethodDef Container_methods[] = {
1617 {"attach_interface", (PyCFunction)Container_attach_interface,
1618 METH_VARARGS|METH_KEYWORDS,
1619 "attach_interface(src_ifname, dest_ifname) -> boolean\n"
1620 "\n"
1621 "Pass a new network device to the container."
1622 },
1623 {"detach_interface", (PyCFunction)Container_detach_interface,
1624 METH_VARARGS|METH_KEYWORDS,
1625 "detach_interface(ifname) -> boolean\n"
1626 "\n"
1627 "detach a network device from the container."
1628 },
1629 {"add_device_node", (PyCFunction)Container_add_device_node,
1630 METH_VARARGS|METH_KEYWORDS,
1631 "add_device_node(src_path, dest_path) -> boolean\n"
1632 "\n"
1633 "Pass a new device to the container."
1634 },
1635 {"attach", (PyCFunction)Container_attach,
1636 METH_VARARGS|METH_KEYWORDS,
1637 "attach(run, payload) -> int\n"
1638 "\n"
1639 "Attach to the container. Returns the pid of the attached process."
1640 },
1641 {"attach_wait", (PyCFunction)Container_attach_wait,
1642 METH_VARARGS|METH_KEYWORDS,
1643 "attach(run, payload) -> int\n"
1644 "\n"
1645 "Attach to the container. Returns the exit code of the process."
1646 },
1647 {"clear_config", (PyCFunction)Container_clear_config,
1648 METH_NOARGS,
1649 "clear_config()\n"
1650 "\n"
1651 "Clear any container configuration."
1652 },
1653 {"clear_config_item", (PyCFunction)Container_clear_config_item,
1654 METH_VARARGS|METH_KEYWORDS,
1655 "clear_config_item(key) -> boolean\n"
1656 "\n"
1657 "Clear the current value of a config key."
1658 },
1659 {"console", (PyCFunction)Container_console,
1660 METH_VARARGS|METH_KEYWORDS,
1661 "console(ttynum = -1, stdinfd = 0, stdoutfd = 1, stderrfd = 2, "
1662 "escape = 0) -> boolean\n"
1663 "\n"
1664 "Attach to container's console."
1665 },
1666 {"console_getfd", (PyCFunction)Container_console_getfd,
1667 METH_VARARGS|METH_KEYWORDS,
1668 "console(ttynum = -1) -> boolean\n"
1669 "\n"
1670 "Attach to container's console."
1671 },
1672 {"clone", (PyCFunction)Container_clone,
1673 METH_VARARGS|METH_KEYWORDS,
1674 "clone(newname, config_path, flags, bdevtype, bdevdata, newsize, "
1675 "hookargs) -> boolean\n"
1676 "\n"
1677 "Create a new container based on the current one."
1678 },
1679 {"create", (PyCFunction)Container_create,
1680 METH_VARARGS|METH_KEYWORDS,
1681 "create(template, args = (,)) -> boolean\n"
1682 "\n"
1683 "Create a new rootfs for the container, using the given template "
1684 "and passing some optional arguments to it."
1685 },
1686 {"destroy", (PyCFunction)Container_destroy,
1687 METH_NOARGS,
1688 "destroy() -> boolean\n"
1689 "\n"
1690 "Destroys the container."
1691 },
1692 {"freeze", (PyCFunction)Container_freeze,
1693 METH_NOARGS,
1694 "freeze() -> boolean\n"
1695 "\n"
1696 "Freezes the container and returns its return code."
1697 },
1698 {"get_cgroup_item", (PyCFunction)Container_get_cgroup_item,
1699 METH_VARARGS|METH_KEYWORDS,
1700 "get_cgroup_item(key) -> string\n"
1701 "\n"
1702 "Get the current value of a cgroup entry."
1703 },
1704 {"get_config_item", (PyCFunction)Container_get_config_item,
1705 METH_VARARGS|METH_KEYWORDS,
1706 "get_config_item(key) -> string\n"
1707 "\n"
1708 "Get the current value of a config key."
1709 },
1710 {"get_config_path", (PyCFunction)Container_get_config_path,
1711 METH_NOARGS,
1712 "get_config_path() -> string\n"
1713 "\n"
1714 "Return the LXC config path (where the containers are stored)."
1715 },
1716 {"get_keys", (PyCFunction)Container_get_keys,
1717 METH_VARARGS|METH_KEYWORDS,
1718 "get_keys(key) -> string\n"
1719 "\n"
1720 "Get a list of valid sub-keys for a key."
1721 },
1722 {"get_interfaces", (PyCFunction)Container_get_interfaces,
1723 METH_NOARGS,
1724 "get_interface() -> tuple\n"
1725 "\n"
1726 "Get a tuple of interfaces for the container."
1727 },
1728 {"get_ips", (PyCFunction)Container_get_ips,
1729 METH_VARARGS|METH_KEYWORDS,
1730 "get_ips(interface, family, scope) -> tuple\n"
1731 "\n"
1732 "Get a tuple of IPs for the container."
1733 },
1734 {"get_running_config_item", (PyCFunction)Container_get_running_config_item,
1735 METH_VARARGS|METH_KEYWORDS,
1736 "get_running_config_item(key) -> string\n"
1737 "\n"
1738 "Get the runtime value of a config key."
1739 },
1740 {"load_config", (PyCFunction)Container_load_config,
1741 METH_VARARGS|METH_KEYWORDS,
1742 "load_config(path = DEFAULT) -> boolean\n"
1743 "\n"
1744 "Read the container configuration from its default "
1745 "location or from an alternative location if provided."
1746 },
1747 {"reboot", (PyCFunction)Container_reboot,
1748 METH_NOARGS,
1749 "reboot() -> boolean\n"
1750 "\n"
1751 "Ask the container to reboot."
1752 },
1753 {"rename", (PyCFunction)Container_rename,
1754 METH_VARARGS|METH_KEYWORDS,
1755 "rename(new_name) -> boolean\n"
1756 "\n"
1757 "Rename the container."
1758 },
1759 {"remove_device_node", (PyCFunction)Container_remove_device_node,
1760 METH_VARARGS|METH_KEYWORDS,
1761 "remove_device_node(src_path, dest_path) -> boolean\n"
1762 "\n"
1763 "Remove a device from the container."
1764 },
1765 {"save_config", (PyCFunction)Container_save_config,
1766 METH_VARARGS|METH_KEYWORDS,
1767 "save_config(path = DEFAULT) -> boolean\n"
1768 "\n"
1769 "Save the container configuration to its default "
1770 "location or to an alternative location if provided."
1771 },
1772 {"set_cgroup_item", (PyCFunction)Container_set_cgroup_item,
1773 METH_VARARGS|METH_KEYWORDS,
1774 "set_cgroup_item(key, value) -> boolean\n"
1775 "\n"
1776 "Set a cgroup entry to the provided value."
1777 },
1778 {"set_config_item", (PyCFunction)Container_set_config_item,
1779 METH_VARARGS|METH_KEYWORDS,
1780 "set_config_item(key, value) -> boolean\n"
1781 "\n"
1782 "Set a config key to the provided value."
1783 },
1784 {"set_config_path", (PyCFunction)Container_set_config_path,
1785 METH_VARARGS|METH_KEYWORDS,
1786 "set_config_path(path) -> boolean\n"
1787 "\n"
1788 "Set the LXC config path (where the containers are stored)."
1789 },
1790 {"shutdown", (PyCFunction)Container_shutdown,
1791 METH_VARARGS|METH_KEYWORDS,
1792 "shutdown(timeout = -1) -> boolean\n"
1793 "\n"
1794 "Sends SIGPWR to the container and wait for it to shutdown."
1795 "-1 means wait forever, 0 means skip waiting."
1796 },
1797 {"snapshot", (PyCFunction)Container_snapshot,
1798 METH_VARARGS|METH_KEYWORDS,
1799 "snapshot(comment_path = None) -> string\n"
1800 "\n"
1801 "Snapshot the container and return the snapshot name "
1802 "(or False on error)."
1803 },
1804 {"snapshot_destroy", (PyCFunction)Container_snapshot_destroy,
1805 METH_VARARGS|METH_KEYWORDS,
1806 "snapshot_destroy(name) -> boolean\n"
1807 "\n"
1808 "Destroy a snapshot."
1809 },
1810 {"snapshot_list", (PyCFunction)Container_snapshot_list,
1811 METH_NOARGS,
1812 "snapshot_list() -> tuple of snapshot tuples\n"
1813 "\n"
1814 "List all snapshots for a container."
1815 },
1816 {"snapshot_restore", (PyCFunction)Container_snapshot_restore,
1817 METH_VARARGS|METH_KEYWORDS,
1818 "snapshot_restore(name, newname = None) -> boolean\n"
1819 "\n"
1820 "Restore a container snapshot. If newname is provided a new "
1821 "container will be created from the snapshot, otherwise an in-place "
1822 "restore will be attempted."
1823 },
1824 {"start", (PyCFunction)Container_start,
1825 METH_VARARGS|METH_KEYWORDS,
1826 "start(useinit = False, daemonize=True, close_fds=False, "
1827 "cmd = (,)) -> boolean\n"
1828 "\n"
1829 "Start the container, return True on success.\n"
1830 "When set useinit will make LXC use lxc-init to start the container.\n"
1831 "The container can be started in the foreground with daemonize=False.\n"
1832 "All fds may also be closed by passing close_fds=True."
1833 },
1834 {"stop", (PyCFunction)Container_stop,
1835 METH_NOARGS,
1836 "stop() -> boolean\n"
1837 "\n"
1838 "Stop the container and returns its return code."
1839 },
1840 {"unfreeze", (PyCFunction)Container_unfreeze,
1841 METH_NOARGS,
1842 "unfreeze() -> boolean\n"
1843 "\n"
1844 "Unfreezes the container and returns its return code."
1845 },
1846 {"wait", (PyCFunction)Container_wait,
1847 METH_VARARGS|METH_KEYWORDS,
1848 "wait(state, timeout = -1) -> boolean\n"
1849 "\n"
1850 "Wait for the container to reach a given state or timeout."
1851 },
1852 {NULL, NULL, 0, NULL}
1853 };
1854
1855 static PyTypeObject _lxc_ContainerType = {
1856 PyVarObject_HEAD_INIT(NULL, 0)
1857 "lxc.Container", /* tp_name */
1858 sizeof(Container), /* tp_basicsize */
1859 0, /* tp_itemsize */
1860 (destructor)Container_dealloc, /* tp_dealloc */
1861 0, /* tp_print */
1862 0, /* tp_getattr */
1863 0, /* tp_setattr */
1864 0, /* tp_reserved */
1865 0, /* tp_repr */
1866 0, /* tp_as_number */
1867 0, /* tp_as_sequence */
1868 0, /* tp_as_mapping */
1869 0, /* tp_hash */
1870 0, /* tp_call */
1871 0, /* tp_str */
1872 0, /* tp_getattro */
1873 0, /* tp_setattro */
1874 0, /* tp_as_buffer */
1875 Py_TPFLAGS_DEFAULT |
1876 Py_TPFLAGS_BASETYPE, /* tp_flags */
1877 "Container objects", /* tp_doc */
1878 0, /* tp_traverse */
1879 0, /* tp_clear */
1880 0, /* tp_richcompare */
1881 0, /* tp_weaklistoffset */
1882 0, /* tp_iter */
1883 0, /* tp_iternext */
1884 Container_methods, /* tp_methods */
1885 0, /* tp_members */
1886 Container_getseters, /* tp_getset */
1887 0, /* tp_base */
1888 0, /* tp_dict */
1889 0, /* tp_descr_get */
1890 0, /* tp_descr_set */
1891 0, /* tp_dictoffset */
1892 (initproc)Container_init, /* tp_init */
1893 0, /* tp_alloc */
1894 Container_new, /* tp_new */
1895 };
1896
1897 static PyMethodDef LXC_methods[] = {
1898 {"arch_to_personality", (PyCFunction)LXC_arch_to_personality, METH_O,
1899 "Returns the process personality of the corresponding architecture"},
1900 {"attach_run_command", (PyCFunction)LXC_attach_run_command, METH_O,
1901 "Runs a command when attaching, to use as the run parameter for attach "
1902 "or attach_wait"},
1903 {"attach_run_shell", (PyCFunction)LXC_attach_run_shell, METH_O,
1904 "Starts up a shell when attaching, to use as the run parameter for "
1905 "attach or attach_wait"},
1906 {"get_global_config_item", (PyCFunction)LXC_get_global_config_item,
1907 METH_VARARGS|METH_KEYWORDS,
1908 "Returns the current LXC config path"},
1909 {"get_version", (PyCFunction)LXC_get_version, METH_NOARGS,
1910 "Returns the current LXC library version"},
1911 {"list_containers", (PyCFunction)LXC_list_containers,
1912 METH_VARARGS|METH_KEYWORDS,
1913 "Returns a list of container names or objects"},
1914 {NULL, NULL, 0, NULL}
1915 };
1916
1917 static PyModuleDef _lxcmodule = {
1918 PyModuleDef_HEAD_INIT,
1919 "_lxc",
1920 "Binding for liblxc in python",
1921 -1,
1922 LXC_methods
1923 };
1924
1925 PyMODINIT_FUNC
1926 PyInit__lxc(void)
1927 {
1928 PyObject* m;
1929 PyObject* d;
1930
1931 if (PyType_Ready(&_lxc_ContainerType) < 0)
1932 return NULL;
1933
1934 m = PyModule_Create(&_lxcmodule);
1935 if (m == NULL)
1936 return NULL;
1937
1938 Py_INCREF(&_lxc_ContainerType);
1939 PyModule_AddObject(m, "Container", (PyObject *)&_lxc_ContainerType);
1940
1941 /* add constants */
1942 d = PyModule_GetDict(m);
1943
1944 #define PYLXC_EXPORT_CONST(c) \
1945 PyDict_SetItemString(d, #c, PyLong_FromLong(c))
1946
1947 /* namespace flags (no other python lib exports this) */
1948 PYLXC_EXPORT_CONST(CLONE_NEWUTS);
1949 PYLXC_EXPORT_CONST(CLONE_NEWIPC);
1950 PYLXC_EXPORT_CONST(CLONE_NEWUSER);
1951 PYLXC_EXPORT_CONST(CLONE_NEWPID);
1952 PYLXC_EXPORT_CONST(CLONE_NEWNET);
1953 PYLXC_EXPORT_CONST(CLONE_NEWNS);
1954
1955 /* attach: environment variable handling */
1956 PYLXC_EXPORT_CONST(LXC_ATTACH_CLEAR_ENV);
1957 PYLXC_EXPORT_CONST(LXC_ATTACH_KEEP_ENV);
1958
1959 /* attach: attach options */
1960 PYLXC_EXPORT_CONST(LXC_ATTACH_DEFAULT);
1961 PYLXC_EXPORT_CONST(LXC_ATTACH_DROP_CAPABILITIES);
1962 PYLXC_EXPORT_CONST(LXC_ATTACH_LSM_EXEC);
1963 PYLXC_EXPORT_CONST(LXC_ATTACH_LSM_NOW);
1964 PYLXC_EXPORT_CONST(LXC_ATTACH_MOVE_TO_CGROUP);
1965 PYLXC_EXPORT_CONST(LXC_ATTACH_REMOUNT_PROC_SYS);
1966 PYLXC_EXPORT_CONST(LXC_ATTACH_SET_PERSONALITY);
1967
1968 /* clone: clone flags */
1969 PYLXC_EXPORT_CONST(LXC_CLONE_KEEPBDEVTYPE);
1970 PYLXC_EXPORT_CONST(LXC_CLONE_KEEPMACADDR);
1971 PYLXC_EXPORT_CONST(LXC_CLONE_KEEPNAME);
1972 PYLXC_EXPORT_CONST(LXC_CLONE_MAYBE_SNAPSHOT);
1973 PYLXC_EXPORT_CONST(LXC_CLONE_SNAPSHOT);
1974
1975 /* create: create flags */
1976 PYLXC_EXPORT_CONST(LXC_CREATE_QUIET);
1977
1978 #undef PYLXC_EXPORT_CONST
1979
1980 return m;
1981 }
1982
1983 /*
1984 * kate: space-indent on; indent-width 4; mixedindent off; indent-mode cstyle;
1985 */