]> git.proxmox.com Git - mirror_lxc.git/blob - src/python-lxc/lxc.c
licensing: Add missing headers and FSF address
[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 USA
22 */
23
24 #include <Python.h>
25 #include "structmember.h"
26 #include <lxc/lxccontainer.h>
27 #include <lxc/utils.h>
28 #include <lxc/namespace.h>
29 #include <lxc/confile.h>
30 #include <stdio.h>
31 #include <sys/wait.h>
32
33 typedef struct {
34 PyObject_HEAD
35 struct lxc_container *container;
36 } Container;
37
38 char**
39 convert_tuple_to_char_pointer_array(PyObject *argv) {
40 int argc;
41 int i, j;
42
43 /* not a list or tuple */
44 if (!PyList_Check(argv) && !PyTuple_Check(argv)) {
45 PyErr_SetString(PyExc_TypeError, "Expected list or tuple.");
46 return NULL;
47 }
48
49 argc = PySequence_Fast_GET_SIZE(argv);
50
51 char **result = (char**) calloc(argc + 1, sizeof(char*));
52
53 if (result == NULL) {
54 PyErr_SetNone(PyExc_MemoryError);
55 return NULL;
56 }
57
58 for (i = 0; i < argc; i++) {
59 PyObject *pyobj = PySequence_Fast_GET_ITEM(argv, i);
60 assert(pyobj != NULL);
61
62 char *str = NULL;
63 PyObject *pystr = NULL;
64
65 if (!PyUnicode_Check(pyobj)) {
66 PyErr_SetString(PyExc_ValueError, "Expected a string");
67 goto error;
68 }
69
70 pystr = PyUnicode_AsUTF8String(pyobj);
71 if (!pystr) {
72 /* Maybe it wasn't UTF-8 encoded. An exception is already set. */
73 goto error;
74 }
75
76 str = PyBytes_AsString(pystr);
77 if (!str) {
78 /* Maybe pystr wasn't a valid object. An exception is already set.
79 */
80 Py_DECREF(pystr);
81 goto error;
82 }
83
84 /* We must make a copy of str, because it points into internal memory
85 * which we do not own. Assume it's NULL terminated, otherwise we'd
86 * have to use PyUnicode_AsUTF8AndSize() and be explicit about copying
87 * the memory.
88 */
89 result[i] = strdup(str);
90
91 /* Do not decref pyobj since we stole a reference by using
92 * PyTuple_GET_ITEM().
93 */
94 Py_DECREF(pystr);
95 if (result[i] == NULL) {
96 PyErr_SetNone(PyExc_MemoryError);
97 goto error;
98 }
99 }
100
101 result[argc] = NULL;
102 return result;
103
104 error:
105 /* We can only iterate up to but not including i because malloc() does not
106 * initialize its memory. Thus if we got here, i points to the index
107 * after the last strdup'd entry in result.
108 */
109 for (j = 0; j < i; j++)
110 free(result[j]);
111 free(result);
112 return NULL;
113 }
114
115 static void
116 Container_dealloc(Container* self)
117 {
118 lxc_container_put(self->container);
119 Py_TYPE(self)->tp_free((PyObject*)self);
120 }
121
122 static PyObject *
123 Container_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
124 {
125 Container *self;
126
127 self = (Container *)type->tp_alloc(type, 0);
128
129 return (PyObject *)self;
130 }
131
132 static int
133 Container_init(Container *self, PyObject *args, PyObject *kwds)
134 {
135 static char *kwlist[] = {"name", "config_path", NULL};
136 char *name = NULL;
137 PyObject *fs_config_path = NULL;
138 char *config_path = NULL;
139
140 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|O&", kwlist,
141 &name,
142 PyUnicode_FSConverter, &fs_config_path))
143 return -1;
144
145 if (fs_config_path != NULL) {
146 config_path = PyBytes_AS_STRING(fs_config_path);
147 assert(config_path != NULL);
148 }
149
150 self->container = lxc_container_new(name, config_path);
151 if (!self->container) {
152 Py_XDECREF(fs_config_path);
153 fprintf(stderr, "%d: error creating container %s\n", __LINE__, name);
154 return -1;
155 }
156
157 Py_XDECREF(fs_config_path);
158 return 0;
159 }
160
161 static PyObject *
162 LXC_get_default_config_path(PyObject *self, PyObject *args)
163 {
164 return PyUnicode_FromString(lxc_get_default_config_path());
165 }
166
167 static PyObject *
168 LXC_get_version(PyObject *self, PyObject *args)
169 {
170 return PyUnicode_FromString(lxc_get_version());
171 }
172
173 // Container properties
174 static PyObject *
175 Container_config_file_name(Container *self, void *closure)
176 {
177 return PyUnicode_FromString(
178 self->container->config_file_name(self->container));
179 }
180
181 static PyObject *
182 Container_defined(Container *self, void *closure)
183 {
184 if (self->container->is_defined(self->container)) {
185 Py_RETURN_TRUE;
186 }
187
188 Py_RETURN_FALSE;
189 }
190
191 static PyObject *
192 Container_init_pid(Container *self, void *closure)
193 {
194 return PyLong_FromLong(self->container->init_pid(self->container));
195 }
196
197 static PyObject *
198 Container_name(Container *self, void *closure)
199 {
200 return PyUnicode_FromString(self->container->name);
201 }
202
203 static PyObject *
204 Container_running(Container *self, void *closure)
205 {
206 if (self->container->is_running(self->container)) {
207 Py_RETURN_TRUE;
208 }
209
210 Py_RETURN_FALSE;
211 }
212
213 static PyObject *
214 Container_state(Container *self, void *closure)
215 {
216 return PyUnicode_FromString(self->container->state(self->container));
217 }
218
219 // Container Functions
220 static PyObject *
221 Container_clear_config_item(Container *self, PyObject *args, PyObject *kwds)
222 {
223 static char *kwlist[] = {"key", NULL};
224 char *key = NULL;
225
226 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist,
227 &key))
228 return NULL;
229
230 if (self->container->clear_config_item(self->container, key)) {
231 Py_RETURN_TRUE;
232 }
233
234 Py_RETURN_FALSE;
235 }
236
237 static PyObject *
238 Container_create(Container *self, PyObject *args, PyObject *kwds)
239 {
240 char* template_name = NULL;
241 char** create_args = {NULL};
242 PyObject *retval = NULL, *vargs = NULL;
243 int i = 0;
244 static char *kwlist[] = {"template", "args", NULL};
245
246 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s|O", kwlist,
247 &template_name, &vargs))
248 return NULL;
249
250 if (vargs) {
251 if (PyTuple_Check(vargs)) {
252 create_args = convert_tuple_to_char_pointer_array(vargs);
253 if (!create_args) {
254 return NULL;
255 }
256 }
257 else {
258 PyErr_SetString(PyExc_ValueError, "args needs to be a tuple");
259 return NULL;
260 }
261 }
262
263 if (self->container->create(self->container, template_name, NULL, NULL, 0, create_args))
264 retval = Py_True;
265 else
266 retval = Py_False;
267
268 if (vargs) {
269 /* We cannot have gotten here unless vargs was given and create_args
270 * was successfully allocated.
271 */
272 for (i = 0; i < PyTuple_GET_SIZE(vargs); i++)
273 free(create_args[i]);
274 free(create_args);
275 }
276
277 Py_INCREF(retval);
278 return retval;
279 }
280
281 static PyObject *
282 Container_destroy(Container *self, PyObject *args, PyObject *kwds)
283 {
284 if (self->container->destroy(self->container)) {
285 Py_RETURN_TRUE;
286 }
287
288 Py_RETURN_FALSE;
289 }
290
291 static PyObject *
292 Container_freeze(Container *self, PyObject *args, PyObject *kwds)
293 {
294 if (self->container->freeze(self->container)) {
295 Py_RETURN_TRUE;
296 }
297
298 Py_RETURN_FALSE;
299 }
300
301 static PyObject *
302 Container_get_cgroup_item(Container *self, PyObject *args, PyObject *kwds)
303 {
304 static char *kwlist[] = {"key", NULL};
305 char* key = NULL;
306 int len = 0;
307 PyObject *ret = NULL;
308
309 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist,
310 &key))
311 return NULL;
312
313 len = self->container->get_cgroup_item(self->container, key, NULL, 0);
314
315 if (len < 0) {
316 PyErr_SetString(PyExc_KeyError, "Invalid cgroup entry");
317 return NULL;
318 }
319
320 char* value = (char*) malloc(sizeof(char)*len + 1);
321 if (value == NULL)
322 return PyErr_NoMemory();
323
324 if (self->container->get_cgroup_item(self->container,
325 key, value, len + 1) != len) {
326 PyErr_SetString(PyExc_ValueError, "Unable to read config value");
327 free(value);
328 return NULL;
329 }
330
331 ret = PyUnicode_FromString(value);
332 free(value);
333 return ret;
334 }
335
336 static PyObject *
337 Container_get_config_item(Container *self, PyObject *args, PyObject *kwds)
338 {
339 static char *kwlist[] = {"key", NULL};
340 char* key = NULL;
341 int len = 0;
342 PyObject *ret = NULL;
343
344 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s|", kwlist,
345 &key))
346 return NULL;
347
348 len = self->container->get_config_item(self->container, key, NULL, 0);
349
350 if (len < 0) {
351 PyErr_SetString(PyExc_KeyError, "Invalid configuration key");
352 return NULL;
353 }
354
355 char* value = (char*) malloc(sizeof(char)*len + 1);
356 if (value == NULL)
357 return PyErr_NoMemory();
358
359 if (self->container->get_config_item(self->container,
360 key, value, len + 1) != len) {
361 PyErr_SetString(PyExc_ValueError, "Unable to read config value");
362 free(value);
363 return NULL;
364 }
365
366 ret = PyUnicode_FromString(value);
367 free(value);
368 return ret;
369 }
370
371 static PyObject *
372 Container_get_config_path(Container *self, PyObject *args, PyObject *kwds)
373 {
374 return PyUnicode_FromString(
375 self->container->get_config_path(self->container));
376 }
377
378 static PyObject *
379 Container_get_keys(Container *self, PyObject *args, PyObject *kwds)
380 {
381 static char *kwlist[] = {"key", NULL};
382 char* key = NULL;
383 int len = 0;
384 PyObject *ret = NULL;
385
386 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist,
387 &key))
388 return NULL;
389
390 len = self->container->get_keys(self->container, key, NULL, 0);
391
392 if (len < 0) {
393 PyErr_SetString(PyExc_KeyError, "Invalid configuration key");
394 return NULL;
395 }
396
397 char* value = (char*) malloc(sizeof(char)*len + 1);
398 if (value == NULL)
399 return PyErr_NoMemory();
400
401 if (self->container->get_keys(self->container,
402 key, value, len + 1) != len) {
403 PyErr_SetString(PyExc_ValueError, "Unable to read config keys");
404 free(value);
405 return NULL;
406 }
407
408 ret = PyUnicode_FromString(value);
409 free(value);
410 return ret;
411 }
412
413 static PyObject *
414 Container_get_ips(Container *self, PyObject *args, PyObject *kwds)
415 {
416 static char *kwlist[] = {"interface", "family", "scope", NULL};
417 char* interface = NULL;
418 char* family = NULL;
419 int scope = 0;
420
421 int i = 0;
422 char** ips = NULL;
423
424 PyObject* ret;
425
426 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|ssi", kwlist,
427 &interface, &family, &scope))
428 return NULL;
429
430 /* Get the IPs */
431 ips = self->container->get_ips(self->container, interface, family, scope);
432 if (!ips)
433 return PyTuple_New(0);
434
435 /* Count the entries */
436 while (ips[i])
437 i++;
438
439 /* Create the new tuple */
440 ret = PyTuple_New(i);
441 if (!ret)
442 return NULL;
443
444 /* Add the entries to the tuple and free the memory */
445 i = 0;
446 while (ips[i]) {
447 PyObject *unicode = PyUnicode_FromString(ips[i]);
448 if (!unicode) {
449 Py_DECREF(ret);
450 ret = NULL;
451 break;
452 }
453 PyTuple_SET_ITEM(ret, i, unicode);
454 i++;
455 }
456
457 /* Free the list of IPs */
458 i = 0;
459 while (ips[i]) {
460 free(ips[i]);
461 i++;
462 }
463 free(ips);
464
465 return ret;
466 }
467
468 static PyObject *
469 Container_load_config(Container *self, PyObject *args, PyObject *kwds)
470 {
471 static char *kwlist[] = {"path", NULL};
472 PyObject *fs_path = NULL;
473 char* path = NULL;
474
475 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|O&", kwlist,
476 PyUnicode_FSConverter, &fs_path))
477 return NULL;
478
479 if (fs_path != NULL) {
480 path = PyBytes_AS_STRING(fs_path);
481 assert(path != NULL);
482 }
483
484 if (self->container->load_config(self->container, path)) {
485 Py_XDECREF(fs_path);
486 Py_RETURN_TRUE;
487 }
488
489 Py_XDECREF(fs_path);
490 Py_RETURN_FALSE;
491 }
492
493 static PyObject *
494 Container_save_config(Container *self, PyObject *args, PyObject *kwds)
495 {
496 static char *kwlist[] = {"path", NULL};
497 PyObject *fs_path = NULL;
498 char* path = NULL;
499
500 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|O&", kwlist,
501 PyUnicode_FSConverter, &fs_path))
502 return NULL;
503
504 if (fs_path != NULL) {
505 path = PyBytes_AS_STRING(fs_path);
506 assert(path != NULL);
507 }
508
509 if (self->container->save_config(self->container, path)) {
510 Py_XDECREF(fs_path);
511 Py_RETURN_TRUE;
512 }
513
514 Py_XDECREF(fs_path);
515 Py_RETURN_FALSE;
516 }
517
518 static PyObject *
519 Container_set_cgroup_item(Container *self, PyObject *args, PyObject *kwds)
520 {
521 static char *kwlist[] = {"key", "value", NULL};
522 char *key = NULL;
523 char *value = NULL;
524
525 if (! PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwlist,
526 &key, &value))
527 return NULL;
528
529 if (self->container->set_cgroup_item(self->container, key, value)) {
530 Py_RETURN_TRUE;
531 }
532
533 Py_RETURN_FALSE;
534 }
535
536 static PyObject *
537 Container_set_config_item(Container *self, PyObject *args, PyObject *kwds)
538 {
539 static char *kwlist[] = {"key", "value", NULL};
540 char *key = NULL;
541 char *value = NULL;
542
543 if (! PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwlist,
544 &key, &value))
545 return NULL;
546
547 if (self->container->set_config_item(self->container, key, value)) {
548 Py_RETURN_TRUE;
549 }
550
551 Py_RETURN_FALSE;
552 }
553
554 static PyObject *
555 Container_set_config_path(Container *self, PyObject *args, PyObject *kwds)
556 {
557 static char *kwlist[] = {"path", NULL};
558 char *path = NULL;
559
560 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist,
561 &path))
562 return NULL;
563
564 if (self->container->set_config_path(self->container, path)) {
565 Py_RETURN_TRUE;
566 }
567
568 Py_RETURN_FALSE;
569 }
570
571 static PyObject *
572 Container_shutdown(Container *self, PyObject *args, PyObject *kwds)
573 {
574 static char *kwlist[] = {"timeout", NULL};
575 int timeout = -1;
576
577 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
578 &timeout))
579 return NULL;
580
581 if (self->container->shutdown(self->container, timeout)) {
582 Py_RETURN_TRUE;
583 }
584
585 Py_RETURN_FALSE;
586 }
587
588 static PyObject *
589 Container_start(Container *self, PyObject *args, PyObject *kwds)
590 {
591 char** init_args = {NULL};
592 PyObject *useinit = NULL, *retval = NULL, *vargs = NULL;
593 int init_useinit = 0, i = 0;
594 static char *kwlist[] = {"useinit", "cmd", NULL};
595
596 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist,
597 &useinit, &vargs))
598 return NULL;
599
600 if (useinit && useinit == Py_True) {
601 init_useinit = 1;
602 }
603
604 if (vargs && PyTuple_Check(vargs)) {
605 init_args = convert_tuple_to_char_pointer_array(vargs);
606 if (!init_args) {
607 return NULL;
608 }
609 }
610
611 self->container->want_daemonize(self->container);
612
613 if (self->container->start(self->container, init_useinit, init_args))
614 retval = Py_True;
615 else
616 retval = Py_False;
617
618 if (vargs) {
619 /* We cannot have gotten here unless vargs was given and create_args
620 * was successfully allocated.
621 */
622 for (i = 0; i < PyTuple_GET_SIZE(vargs); i++)
623 free(init_args[i]);
624 free(init_args);
625 }
626
627 Py_INCREF(retval);
628 return retval;
629 }
630
631 static PyObject *
632 Container_stop(Container *self, PyObject *args, PyObject *kwds)
633 {
634 if (self->container->stop(self->container)) {
635 Py_RETURN_TRUE;
636 }
637
638 Py_RETURN_FALSE;
639 }
640
641 static PyObject *
642 Container_unfreeze(Container *self, PyObject *args, PyObject *kwds)
643 {
644 if (self->container->unfreeze(self->container)) {
645 Py_RETURN_TRUE;
646 }
647
648 Py_RETURN_FALSE;
649 }
650
651 static PyObject *
652 Container_console(Container *self, PyObject *args, PyObject *kwds)
653 {
654 static char *kwlist[] = {"ttynum", "stdinfd", "stdoutfd", "stderrfd", "escape", NULL};
655 int ttynum = -1, stdinfd = 0, stdoutfd = 1, stderrfd = 2, escape = 1;
656
657 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|iiiii", kwlist,
658 &ttynum, &stdinfd, &stdoutfd, &stderrfd,
659 &escape))
660 return NULL;
661
662 if (self->container->console(self->container, ttynum,
663 stdinfd, stdoutfd, stderrfd, escape) == 0) {
664 Py_RETURN_TRUE;
665 }
666 Py_RETURN_FALSE;
667 }
668
669 static PyObject *
670 Container_console_getfd(Container *self, PyObject *args, PyObject *kwds)
671 {
672 static char *kwlist[] = {"ttynum", NULL};
673 int ttynum = -1, masterfd;
674
675 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist, &ttynum))
676 return NULL;
677
678 if (self->container->console_getfd(self->container, &ttynum, &masterfd) < 0) {
679 PyErr_SetString(PyExc_ValueError, "Unable to allocate tty");
680 return NULL;
681 }
682 return PyLong_FromLong(masterfd);
683 }
684
685 static PyObject *
686 Container_wait(Container *self, PyObject *args, PyObject *kwds)
687 {
688 static char *kwlist[] = {"state", "timeout", NULL};
689 char *state = NULL;
690 int timeout = -1;
691
692 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s|i", kwlist,
693 &state, &timeout))
694 return NULL;
695
696 if (self->container->wait(self->container, state, timeout)) {
697 Py_RETURN_TRUE;
698 }
699
700 Py_RETURN_FALSE;
701 }
702
703 struct lxc_attach_python_payload {
704 PyObject *fn;
705 PyObject *arg;
706 };
707
708 static int lxc_attach_python_exec(void* _payload)
709 {
710 struct lxc_attach_python_payload *payload = (struct lxc_attach_python_payload *)_payload;
711 PyObject *result = PyObject_CallFunctionObjArgs(payload->fn, payload->arg, NULL);
712
713 if (!result) {
714 PyErr_Print();
715 return -1;
716 }
717 if (PyLong_Check(result))
718 return (int)PyLong_AsLong(result);
719 else
720 return -1;
721 }
722
723 static void lxc_attach_free_options(lxc_attach_options_t *options);
724
725 static lxc_attach_options_t *lxc_attach_parse_options(PyObject *kwds)
726 {
727 static char *kwlist[] = {"attach_flags", "namespaces", "personality", "initial_cwd", "uid", "gid", "env_policy", "extra_env_vars", "extra_keep_env", "stdin", "stdout", "stderr", NULL};
728 long temp_uid, temp_gid;
729 int temp_env_policy;
730 PyObject *extra_env_vars_obj = NULL;
731 PyObject *extra_keep_env_obj = NULL;
732 PyObject *stdin_obj = NULL;
733 PyObject *stdout_obj = NULL;
734 PyObject *stderr_obj = NULL;
735 PyObject *initial_cwd_obj = NULL;
736 PyObject *dummy;
737 bool parse_result;
738
739 lxc_attach_options_t default_options = LXC_ATTACH_OPTIONS_DEFAULT;
740 lxc_attach_options_t *options = malloc(sizeof(*options));
741
742 if (!options) {
743 PyErr_SetNone(PyExc_MemoryError);
744 return NULL;
745 }
746 memcpy(options, &default_options, sizeof(*options));
747
748 /* we need some dummy variables because we can't be sure
749 * the data types match completely */
750 temp_uid = -1;
751 temp_gid = -1;
752 temp_env_policy = options->env_policy;
753
754 /* we need a dummy tuple */
755 dummy = PyTuple_New(0);
756
757 parse_result = PyArg_ParseTupleAndKeywords(dummy, kwds, "|iilO&lliOOOOO", kwlist,
758 &options->attach_flags, &options->namespaces, &options->personality,
759 PyUnicode_FSConverter, &initial_cwd_obj, &temp_uid, &temp_gid,
760 &temp_env_policy, &extra_env_vars_obj, &extra_keep_env_obj,
761 &stdin_obj, &stdout_obj, &stderr_obj);
762
763 /* immediately get rid of the dummy tuple */
764 Py_DECREF(dummy);
765
766 if (!parse_result) {
767 lxc_attach_free_options(options);
768 return NULL;
769 }
770
771 /* duplicate the string, so we don't depend on some random Python object */
772 if (initial_cwd_obj != NULL) {
773 options->initial_cwd = strndup(PyBytes_AsString(initial_cwd_obj), PyBytes_Size(initial_cwd_obj));
774 Py_DECREF(initial_cwd_obj);
775 }
776
777 /* do the type conversion from the types that match the parse string */
778 if (temp_uid != -1) options->uid = (uid_t)temp_uid;
779 if (temp_gid != -1) options->gid = (gid_t)temp_gid;
780 options->env_policy = (lxc_attach_env_policy_t)temp_env_policy;
781
782 if (extra_env_vars_obj)
783 options->extra_env_vars = convert_tuple_to_char_pointer_array(extra_env_vars_obj);
784 if (extra_keep_env_obj)
785 options->extra_keep_env = convert_tuple_to_char_pointer_array(extra_keep_env_obj);
786 if (stdin_obj) {
787 options->stdin_fd = PyObject_AsFileDescriptor(stdin_obj);
788 if (options->stdin_fd < 0) {
789 lxc_attach_free_options(options);
790 return NULL;
791 }
792 }
793 if (stdout_obj) {
794 options->stdout_fd = PyObject_AsFileDescriptor(stdout_obj);
795 if (options->stdout_fd < 0) {
796 lxc_attach_free_options(options);
797 return NULL;
798 }
799 }
800 if (stderr_obj) {
801 options->stderr_fd = PyObject_AsFileDescriptor(stderr_obj);
802 if (options->stderr_fd < 0) {
803 lxc_attach_free_options(options);
804 return NULL;
805 }
806 }
807
808 return options;
809 }
810
811 void lxc_attach_free_options(lxc_attach_options_t *options)
812 {
813 int i;
814 if (!options)
815 return;
816 if (options->initial_cwd)
817 free(options->initial_cwd);
818 if (options->extra_env_vars) {
819 for (i = 0; options->extra_env_vars[i]; i++)
820 free(options->extra_env_vars[i]);
821 free(options->extra_env_vars);
822 }
823 if (options->extra_keep_env) {
824 for (i = 0; options->extra_keep_env[i]; i++)
825 free(options->extra_keep_env[i]);
826 free(options->extra_keep_env);
827 }
828 free(options);
829 }
830
831 static PyObject *
832 Container_attach_and_possibly_wait(Container *self, PyObject *args, PyObject *kwds, int wait)
833 {
834 struct lxc_attach_python_payload payload = { NULL, NULL };
835 lxc_attach_options_t *options = NULL;
836 long ret;
837 pid_t pid;
838
839 if (!PyArg_ParseTuple(args, "O|O", &payload.fn, &payload.arg))
840 return NULL;
841 if (!PyCallable_Check(payload.fn)) {
842 PyErr_Format(PyExc_TypeError, "attach: object not callable");
843 return NULL;
844 }
845
846 options = lxc_attach_parse_options(kwds);
847 if (!options)
848 return NULL;
849
850 ret = self->container->attach(self->container, lxc_attach_python_exec, &payload, options, &pid);
851 if (ret < 0)
852 goto out;
853
854 if (wait) {
855 ret = lxc_wait_for_pid_status(pid);
856 /* handle case where attach fails */
857 if (WIFEXITED(ret) && WEXITSTATUS(ret) == 255)
858 ret = -1;
859 } else {
860 ret = (long)pid;
861 }
862
863 out:
864 lxc_attach_free_options(options);
865 return PyLong_FromLong(ret);
866 }
867
868 static PyObject *
869 Container_attach(Container *self, PyObject *args, PyObject *kwds)
870 {
871 return Container_attach_and_possibly_wait(self, args, kwds, 0);
872 }
873
874 static PyObject *
875 Container_attach_wait(Container *self, PyObject *args, PyObject *kwds)
876 {
877 return Container_attach_and_possibly_wait(self, args, kwds, 1);
878 }
879
880 static PyObject *
881 LXC_attach_run_shell(PyObject *self, PyObject *arg)
882 {
883 int rv;
884
885 rv = lxc_attach_run_shell(NULL);
886
887 return PyLong_FromLong(rv);
888 }
889
890 static PyObject *
891 LXC_arch_to_personality(PyObject *self, PyObject *arg)
892 {
893 long rv = -1;
894 PyObject *pystr;
895 char *str;
896
897 if (!PyUnicode_Check(arg)) {
898 PyErr_SetString(PyExc_ValueError, "Expected a string");
899 return NULL;
900 }
901
902 pystr = PyUnicode_AsUTF8String(arg);
903 if (!pystr)
904 return NULL;
905
906 str = PyBytes_AsString(pystr);
907 if (!str)
908 goto out;
909
910 rv = lxc_config_parse_arch(str);
911 if (rv == -1)
912 PyErr_SetString(PyExc_KeyError, "Failed to lookup architecture.");
913
914 out:
915 Py_DECREF(pystr);
916 return rv == -1 ? NULL : PyLong_FromLong(rv);
917 }
918
919 static PyObject *
920 LXC_attach_run_command(PyObject *self, PyObject *arg)
921 {
922 PyObject *args_obj = NULL;
923 int i, rv;
924 lxc_attach_command_t cmd = {
925 NULL, /* program */
926 NULL /* argv[] */
927 };
928
929 if (!PyArg_ParseTuple(arg, "sO", (const char**)&cmd.program, &args_obj))
930 return NULL;
931 if (args_obj && PyList_Check(args_obj)) {
932 cmd.argv = convert_tuple_to_char_pointer_array(args_obj);
933 } else {
934 PyErr_Format(PyExc_TypeError, "Second part of tuple passed to attach_run_command must be a list.");
935 return NULL;
936 }
937
938 if (!cmd.argv)
939 return NULL;
940
941 rv = lxc_attach_run_command(&cmd);
942
943 for (i = 0; cmd.argv[i]; i++)
944 free(cmd.argv[i]);
945 free(cmd.argv);
946
947 return PyLong_FromLong(rv);
948 }
949
950 static PyGetSetDef Container_getseters[] = {
951 {"config_file_name",
952 (getter)Container_config_file_name, NULL,
953 "Path to the container configuration",
954 NULL},
955 {"defined",
956 (getter)Container_defined, NULL,
957 "Boolean indicating whether the container configuration exists",
958 NULL},
959 {"init_pid",
960 (getter)Container_init_pid, NULL,
961 "PID of the container's init process in the host's PID namespace",
962 NULL},
963 {"name",
964 (getter)Container_name, NULL,
965 "Container name",
966 NULL},
967 {"running",
968 (getter)Container_running, NULL,
969 "Boolean indicating whether the container is running or not",
970 NULL},
971 {"state",
972 (getter)Container_state, NULL,
973 "Container state",
974 NULL},
975 {NULL, NULL, NULL, NULL, NULL}
976 };
977
978 static PyMethodDef Container_methods[] = {
979 {"clear_config_item", (PyCFunction)Container_clear_config_item,
980 METH_VARARGS|METH_KEYWORDS,
981 "clear_config_item(key) -> boolean\n"
982 "\n"
983 "Clear the current value of a config key."
984 },
985 {"create", (PyCFunction)Container_create,
986 METH_VARARGS|METH_KEYWORDS,
987 "create(template, args = (,)) -> boolean\n"
988 "\n"
989 "Create a new rootfs for the container, using the given template "
990 "and passing some optional arguments to it."
991 },
992 {"destroy", (PyCFunction)Container_destroy,
993 METH_NOARGS,
994 "destroy() -> boolean\n"
995 "\n"
996 "Destroys the container."
997 },
998 {"freeze", (PyCFunction)Container_freeze,
999 METH_NOARGS,
1000 "freeze() -> boolean\n"
1001 "\n"
1002 "Freezes the container and returns its return code."
1003 },
1004 {"get_cgroup_item", (PyCFunction)Container_get_cgroup_item,
1005 METH_VARARGS|METH_KEYWORDS,
1006 "get_cgroup_item(key) -> string\n"
1007 "\n"
1008 "Get the current value of a cgroup entry."
1009 },
1010 {"get_config_item", (PyCFunction)Container_get_config_item,
1011 METH_VARARGS|METH_KEYWORDS,
1012 "get_config_item(key) -> string\n"
1013 "\n"
1014 "Get the current value of a config key."
1015 },
1016 {"get_config_path", (PyCFunction)Container_get_config_path,
1017 METH_NOARGS,
1018 "get_config_path() -> string\n"
1019 "\n"
1020 "Return the LXC config path (where the containers are stored)."
1021 },
1022 {"get_keys", (PyCFunction)Container_get_keys,
1023 METH_VARARGS|METH_KEYWORDS,
1024 "get_keys(key) -> string\n"
1025 "\n"
1026 "Get a list of valid sub-keys for a key."
1027 },
1028 {"get_ips", (PyCFunction)Container_get_ips,
1029 METH_VARARGS|METH_KEYWORDS,
1030 "get_ips(interface, family, scope) -> tuple\n"
1031 "\n"
1032 "Get a tuple of IPs for the container."
1033 },
1034 {"load_config", (PyCFunction)Container_load_config,
1035 METH_VARARGS|METH_KEYWORDS,
1036 "load_config(path = DEFAULT) -> boolean\n"
1037 "\n"
1038 "Read the container configuration from its default "
1039 "location or from an alternative location if provided."
1040 },
1041 {"save_config", (PyCFunction)Container_save_config,
1042 METH_VARARGS|METH_KEYWORDS,
1043 "save_config(path = DEFAULT) -> boolean\n"
1044 "\n"
1045 "Save the container configuration to its default "
1046 "location or to an alternative location if provided."
1047 },
1048 {"set_cgroup_item", (PyCFunction)Container_set_cgroup_item,
1049 METH_VARARGS|METH_KEYWORDS,
1050 "set_cgroup_item(key, value) -> boolean\n"
1051 "\n"
1052 "Set a cgroup entry to the provided value."
1053 },
1054 {"set_config_item", (PyCFunction)Container_set_config_item,
1055 METH_VARARGS|METH_KEYWORDS,
1056 "set_config_item(key, value) -> boolean\n"
1057 "\n"
1058 "Set a config key to the provided value."
1059 },
1060 {"set_config_path", (PyCFunction)Container_set_config_path,
1061 METH_VARARGS|METH_KEYWORDS,
1062 "set_config_path(path) -> boolean\n"
1063 "\n"
1064 "Set the LXC config path (where the containers are stored)."
1065 },
1066 {"shutdown", (PyCFunction)Container_shutdown,
1067 METH_VARARGS|METH_KEYWORDS,
1068 "shutdown(timeout = -1) -> boolean\n"
1069 "\n"
1070 "Sends SIGPWR to the container and wait for it to shutdown "
1071 "unless timeout is set to a positive value, in which case "
1072 "the container will be killed when the timeout is reached."
1073 },
1074 {"start", (PyCFunction)Container_start,
1075 METH_VARARGS|METH_KEYWORDS,
1076 "start(useinit = False, cmd = (,)) -> boolean\n"
1077 "\n"
1078 "Start the container, optionally using lxc-init and "
1079 "an alternate init command, then returns its return code."
1080 },
1081 {"stop", (PyCFunction)Container_stop,
1082 METH_NOARGS,
1083 "stop() -> boolean\n"
1084 "\n"
1085 "Stop the container and returns its return code."
1086 },
1087 {"unfreeze", (PyCFunction)Container_unfreeze,
1088 METH_NOARGS,
1089 "unfreeze() -> boolean\n"
1090 "\n"
1091 "Unfreezes the container and returns its return code."
1092 },
1093 {"wait", (PyCFunction)Container_wait,
1094 METH_VARARGS|METH_KEYWORDS,
1095 "wait(state, timeout = -1) -> boolean\n"
1096 "\n"
1097 "Wait for the container to reach a given state or timeout."
1098 },
1099 {"console", (PyCFunction)Container_console,
1100 METH_VARARGS|METH_KEYWORDS,
1101 "console(ttynum = -1, stdinfd = 0, stdoutfd = 1, stderrfd = 2, escape = 0) -> boolean\n"
1102 "\n"
1103 "Attach to container's console."
1104 },
1105 {"console_getfd", (PyCFunction)Container_console_getfd,
1106 METH_VARARGS|METH_KEYWORDS,
1107 "console(ttynum = -1) -> boolean\n"
1108 "\n"
1109 "Attach to container's console."
1110 },
1111 {"attach", (PyCFunction)Container_attach,
1112 METH_VARARGS|METH_KEYWORDS,
1113 "attach(run, payload) -> int\n"
1114 "\n"
1115 "Attach to the container. Returns the pid of the attached process."
1116 },
1117 {"attach_wait", (PyCFunction)Container_attach_wait,
1118 METH_VARARGS|METH_KEYWORDS,
1119 "attach(run, payload) -> int\n"
1120 "\n"
1121 "Attach to the container. Returns the exit code of the process."
1122 },
1123 {NULL, NULL, 0, NULL}
1124 };
1125
1126 static PyTypeObject _lxc_ContainerType = {
1127 PyVarObject_HEAD_INIT(NULL, 0)
1128 "lxc.Container", /* tp_name */
1129 sizeof(Container), /* tp_basicsize */
1130 0, /* tp_itemsize */
1131 (destructor)Container_dealloc, /* tp_dealloc */
1132 0, /* tp_print */
1133 0, /* tp_getattr */
1134 0, /* tp_setattr */
1135 0, /* tp_reserved */
1136 0, /* tp_repr */
1137 0, /* tp_as_number */
1138 0, /* tp_as_sequence */
1139 0, /* tp_as_mapping */
1140 0, /* tp_hash */
1141 0, /* tp_call */
1142 0, /* tp_str */
1143 0, /* tp_getattro */
1144 0, /* tp_setattro */
1145 0, /* tp_as_buffer */
1146 Py_TPFLAGS_DEFAULT |
1147 Py_TPFLAGS_BASETYPE, /* tp_flags */
1148 "Container objects", /* tp_doc */
1149 0, /* tp_traverse */
1150 0, /* tp_clear */
1151 0, /* tp_richcompare */
1152 0, /* tp_weaklistoffset */
1153 0, /* tp_iter */
1154 0, /* tp_iternext */
1155 Container_methods, /* tp_methods */
1156 0, /* tp_members */
1157 Container_getseters, /* tp_getset */
1158 0, /* tp_base */
1159 0, /* tp_dict */
1160 0, /* tp_descr_get */
1161 0, /* tp_descr_set */
1162 0, /* tp_dictoffset */
1163 (initproc)Container_init, /* tp_init */
1164 0, /* tp_alloc */
1165 Container_new, /* tp_new */
1166 };
1167
1168 static PyMethodDef LXC_methods[] = {
1169 {"attach_run_shell", (PyCFunction)LXC_attach_run_shell, METH_O,
1170 "Starts up a shell when attaching, to use as the run parameter for attach or attach_wait"},
1171 {"attach_run_command", (PyCFunction)LXC_attach_run_command, METH_O,
1172 "Runs a command when attaching, to use as the run parameter for attach or attach_wait"},
1173 {"arch_to_personality", (PyCFunction)LXC_arch_to_personality, METH_O,
1174 "Returns the process personality of the corresponding architecture"},
1175 {"get_default_config_path", (PyCFunction)LXC_get_default_config_path, METH_NOARGS,
1176 "Returns the current LXC config path"},
1177 {"get_version", (PyCFunction)LXC_get_version, METH_NOARGS,
1178 "Returns the current LXC library version"},
1179 {NULL, NULL, 0, NULL}
1180 };
1181
1182 static PyModuleDef _lxcmodule = {
1183 PyModuleDef_HEAD_INIT,
1184 "_lxc",
1185 "Binding for liblxc in python",
1186 -1,
1187 LXC_methods
1188 };
1189
1190 PyMODINIT_FUNC
1191 PyInit__lxc(void)
1192 {
1193 PyObject* m;
1194 PyObject* d;
1195
1196 if (PyType_Ready(&_lxc_ContainerType) < 0)
1197 return NULL;
1198
1199 m = PyModule_Create(&_lxcmodule);
1200 if (m == NULL)
1201 return NULL;
1202
1203 Py_INCREF(&_lxc_ContainerType);
1204 PyModule_AddObject(m, "Container", (PyObject *)&_lxc_ContainerType);
1205
1206 /* add constants */
1207 d = PyModule_GetDict(m);
1208
1209 #define PYLXC_EXPORT_CONST(c) PyDict_SetItemString(d, #c, PyLong_FromLong(c))
1210
1211 /* environment variable handling */
1212 PYLXC_EXPORT_CONST(LXC_ATTACH_KEEP_ENV);
1213 PYLXC_EXPORT_CONST(LXC_ATTACH_CLEAR_ENV);
1214
1215 /* attach options */
1216 PYLXC_EXPORT_CONST(LXC_ATTACH_MOVE_TO_CGROUP);
1217 PYLXC_EXPORT_CONST(LXC_ATTACH_DROP_CAPABILITIES);
1218 PYLXC_EXPORT_CONST(LXC_ATTACH_SET_PERSONALITY);
1219 PYLXC_EXPORT_CONST(LXC_ATTACH_APPARMOR);
1220 PYLXC_EXPORT_CONST(LXC_ATTACH_REMOUNT_PROC_SYS);
1221 PYLXC_EXPORT_CONST(LXC_ATTACH_DEFAULT);
1222
1223 /* namespace flags (no other python lib exports this) */
1224 PYLXC_EXPORT_CONST(CLONE_NEWUTS);
1225 PYLXC_EXPORT_CONST(CLONE_NEWIPC);
1226 PYLXC_EXPORT_CONST(CLONE_NEWUSER);
1227 PYLXC_EXPORT_CONST(CLONE_NEWPID);
1228 PYLXC_EXPORT_CONST(CLONE_NEWNET);
1229 PYLXC_EXPORT_CONST(CLONE_NEWNS);
1230
1231 #undef PYLXC_EXPORT_CONST
1232
1233 return m;
1234 }
1235
1236 /*
1237 * kate: space-indent on; indent-width 4; mixedindent off; indent-mode cstyle;
1238 */