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