4c6bb4240268d93b67f4e75eec5c5edf6f6ad35d
[util-vserver-pl.git] / python / vserverimpl.c
1 /* Copyright 2005 Princeton University
2
3 Redistribution and use in source and binary forms, with or without
4 modification, are permitted provided that the following conditions
5 are met: 
6
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9       
10 * Redistributions in binary form must reproduce the above
11 copyright notice, this list of conditions and the following
12 disclaimer in the documentation and/or other materials provided
13 with the distribution.
14       
15 * Neither the name of the copyright holder nor the names of its
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
18       
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PRINCETON
23 UNIVERSITY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26 OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
29 WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 POSSIBILITY OF SUCH DAMAGE. 
31
32 */
33
34 #include <Python.h>
35
36 #include <errno.h>
37 #include <stdint.h>
38 #include <sys/resource.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <unistd.h>
42 #include <sys/socket.h>
43 #include <arpa/inet.h>
44 #include <ifaddrs.h>
45 #include <stddef.h>
46 #include <fcntl.h>
47 #include <sys/mount.h>
48 #include <utmp.h>
49
50 #include "config.h"
51 #include "vserver.h"
52 #include "planetlab.h"
53
54 static inline PyObject *inc_and_ret_none(void)
55 {
56   Py_INCREF(Py_None);
57   return Py_None;
58 }
59
60 #define NONE  inc_and_ret_none()
61
62 #define PL_INSECURE_BCAPS       (vc_get_insecurebcaps() | (1 << VC_CAP_NET_BIND_SERVICE))
63 #define PL_INSECURE_CCAPS       vc_get_insecureccaps()
64
65
66 static PyObject *
67 __vserver_get_rlimit(xid_t xid, int resource) {
68   struct vc_rlimit limits;
69   PyObject *ret;
70
71   errno = 0;
72   if (vc_get_rlimit(xid, resource, &limits)==-1)
73     ret = PyErr_SetFromErrno(PyExc_OSError);
74   else
75     ret = Py_BuildValue("LLL",limits.hard, limits.soft, limits.min);
76
77   return ret;
78 }
79
80 static PyObject *
81 vserver_get_rlimit(PyObject *self, PyObject *args) {
82   xid_t xid;
83   int resource;
84   PyObject *ret;
85
86   if (!PyArg_ParseTuple(args, "Ii", &xid, &resource))
87     ret = NULL;
88   else
89     ret = __vserver_get_rlimit(xid, resource);
90
91   return ret;
92 }
93
94 static PyObject *
95 vserver_set_rlimit(PyObject *self, PyObject *args) {
96   struct vc_rlimit limits;
97   struct vc_rlimit_mask mask;
98   uint32_t bitmask;
99   xid_t xid;
100   int resource;
101   PyObject *ret = NULL;
102
103   limits.min = VC_LIM_KEEP;
104   limits.soft = VC_LIM_KEEP;
105   limits.hard = VC_LIM_KEEP;
106
107   if (!PyArg_ParseTuple(args, "IiLLL", &xid, &resource, &limits.hard, &limits.soft, &limits.min))
108     return NULL;
109
110   errno = 0;
111
112   if (vc_get_rlimit_mask(xid, &mask)==-1) {
113     ret = PyErr_SetFromErrno(PyExc_OSError);
114   } else {
115     bitmask = (1<<resource);
116     if ((mask.min|mask.soft|mask.hard) & bitmask) 
117       if (vc_set_rlimit(xid, resource, &limits)==-1) 
118         ret = PyErr_SetFromErrno(PyExc_OSError);
119       else
120         ret = __vserver_get_rlimit(xid, resource);
121   }
122
123   return ret;
124 }
125
126
127 static PyObject *
128 vserver_get_dlimit(PyObject *self, PyObject *args)
129 {
130   PyObject *res;
131   char* path;
132   unsigned xid;
133   struct vc_ctx_dlimit data;
134   int r;
135
136   if (!PyArg_ParseTuple(args, "si", &path,&xid))
137     return NULL;
138
139   memset(&data, 0, sizeof(data));
140   r = vc_get_dlimit(path, xid, 0, &data);
141   if (r>=0) {
142     res = Py_BuildValue("(i,i,i,i,i)",
143                         data.space_used,
144                         data.space_total,
145                         data.inodes_used,
146                         data.inodes_total,
147                         data.reserved);
148   } else {
149     res = PyErr_SetFromErrno(PyExc_OSError);
150   }
151
152   return res;
153 }
154
155
156 static PyObject *
157 vserver_set_dlimit(PyObject *self, PyObject *args)
158 {
159   char* path;
160   unsigned xid;
161   struct vc_ctx_dlimit data;
162
163   memset(&data,0,sizeof(data));
164   if (!PyArg_ParseTuple(args, "siiiiii", &path,
165                         &xid,
166                         &data.space_used,
167                         &data.space_total,
168                         &data.inodes_used,
169                         &data.inodes_total,
170                         &data.reserved))
171     return NULL;
172
173   if ((vc_add_dlimit(path, xid, 0) && errno != EEXIST) ||
174       vc_set_dlimit(path, xid, 0, &data))
175     return PyErr_SetFromErrno(PyExc_OSError);
176
177   return NONE;  
178 }
179
180 static PyObject *
181 vserver_unset_dlimit(PyObject *self, PyObject *args)
182 {
183   char  *path;
184   unsigned  xid;
185
186   if (!PyArg_ParseTuple(args, "si", &path, &xid))
187     return NULL;
188
189   if (vc_rem_dlimit(path, xid, 0) && errno != ESRCH)
190     return PyErr_SetFromErrno(PyExc_OSError);
191
192   return NONE;  
193 }
194
195
196 static PyObject *
197 vserver_set_bcaps(PyObject *self, PyObject *args)
198 {
199   xid_t ctx;
200   struct vc_ctx_caps caps;
201
202   if (!PyArg_ParseTuple(args, "IK", &ctx, &caps.bcaps))
203     return NULL;
204
205   caps.bmask = PL_INSECURE_BCAPS;
206   caps.cmask = caps.ccaps = 0;
207   if (vc_set_ccaps(ctx, &caps) == -1 && errno != ESRCH)
208     return PyErr_SetFromErrno(PyExc_OSError);
209
210   return NONE;
211 }
212
213 static PyObject *
214 vserver_text2bcaps(PyObject *self, PyObject *args)
215 {
216   struct vc_ctx_caps caps = { .bcaps = 0 };
217   const char *list;
218   int len;
219   struct vc_err_listparser err;
220
221   if (!PyArg_ParseTuple(args, "s#", &list, &len))
222     return NULL;
223
224   vc_list2bcap(list, len, &err, &caps);
225
226   return Py_BuildValue("K", caps.bcaps);
227 }
228
229 static PyObject *
230 vserver_get_bcaps(PyObject *self, PyObject *args)
231 {
232   xid_t ctx;
233   struct vc_ctx_caps caps;
234
235   if (!PyArg_ParseTuple(args, "I", &ctx))
236     return NULL;
237
238   if (vc_get_ccaps(ctx, &caps) == -1) {
239     if (errno != ESRCH)
240       return PyErr_SetFromErrno(PyExc_OSError);
241     else
242       caps.bcaps = 0;
243   }
244
245   return Py_BuildValue("K", caps.bcaps & PL_INSECURE_BCAPS);
246 }
247
248 static PyObject *
249 vserver_bcaps2text(PyObject *self, PyObject *args)
250 {
251   struct vc_ctx_caps caps = { .bcaps = 0 };
252   PyObject *list;
253   const char *cap;
254
255   if (!PyArg_ParseTuple(args, "K", &caps.bcaps))
256     return NULL;
257
258   list = PyString_FromString("");
259
260   while ((cap = vc_lobcap2text(&caps.bcaps)) != NULL) {
261     if (list == NULL)
262       break;
263     PyString_ConcatAndDel(&list, PyString_FromFormat(
264                           (PyString_Size(list) > 0 ? ",CAP_%s" : "CAP_%s" ),
265                           cap));
266   }
267
268   return list;
269 }
270
271 static PyObject *
272 vserver_set_ccaps(PyObject *self, PyObject *args)
273 {
274   xid_t ctx;
275   struct vc_ctx_caps caps;
276
277   if (!PyArg_ParseTuple(args, "IK", &ctx, &caps.ccaps))
278     return NULL;
279
280   caps.cmask = PL_INSECURE_CCAPS;
281   caps.bmask = caps.bcaps = 0;
282   if (vc_set_ccaps(ctx, &caps) == -1 && errno != ESRCH)
283     return PyErr_SetFromErrno(PyExc_OSError);
284
285   return NONE;
286 }
287
288 static PyObject *
289 vserver_text2ccaps(PyObject *self, PyObject *args)
290 {
291   struct vc_ctx_caps caps = { .ccaps = 0 };
292   const char *list;
293   int len;
294   struct vc_err_listparser err;
295
296   if (!PyArg_ParseTuple(args, "s#", &list, &len))
297     return NULL;
298
299   vc_list2ccap(list, len, &err, &caps);
300
301   return Py_BuildValue("K", caps.ccaps);
302 }
303
304 static PyObject *
305 vserver_get_ccaps(PyObject *self, PyObject *args)
306 {
307   xid_t ctx;
308   struct vc_ctx_caps caps;
309
310   if (!PyArg_ParseTuple(args, "I", &ctx))
311     return NULL;
312
313   if (vc_get_ccaps(ctx, &caps) == -1) {
314     if (errno != ESRCH)
315       return PyErr_SetFromErrno(PyExc_OSError);
316     else
317       caps.ccaps = 0;
318   }
319
320   return Py_BuildValue("K", caps.ccaps & PL_INSECURE_CCAPS);
321 }
322
323 static PyObject *
324 vserver_ccaps2text(PyObject *self, PyObject *args)
325 {
326   struct vc_ctx_caps caps = { .ccaps = 0 };
327   PyObject *list;
328   const char *cap;
329
330   if (!PyArg_ParseTuple(args, "K", &caps.ccaps))
331     return NULL;
332
333   list = PyString_FromString("");
334
335   while ((cap = vc_loccap2text(&caps.ccaps)) != NULL) {
336     if (list == NULL)
337       break;
338     PyString_ConcatAndDel(&list, PyString_FromFormat(
339                           (PyString_Size(list) > 0 ? ",%s" : "%s" ),
340                           cap));
341   }
342
343   return list;
344 }
345
346 static inline int
347 convert_address(const char *str, struct vc_net_addr *addr)
348 {
349   void *dst;
350   if (inet_pton(AF_INET6, str, addr->vna_v6_ip.s6_addr) > 0) {
351     addr->vna_type = VC_NXA_TYPE_IPV6;
352     return 0;
353   }
354   else if (inet_pton(AF_INET, str, &addr->vna_v4_ip.s_addr) > 0) {
355     addr->vna_type = VC_NXA_TYPE_IPV4;
356     return 0;
357   }
358   return -1;
359 }
360
361 static int
362 mask_to_prefix(void *data, int limit)
363 {
364   uint8_t *mask = data;
365   int prefix;
366   for (prefix = 0; prefix < limit && mask[prefix >> 3] & (1 << (prefix & 0x07)); prefix++)
367     ;
368   return prefix;
369 }
370
371 static int
372 get_mask(struct vc_net_addr *addr)
373 {
374   struct ifaddrs *head, *ifa;
375   int ret = 0;
376   int family, offset, len;
377   void *ip;
378
379   switch (addr->vna_type) {
380   case VC_NXA_TYPE_IPV4:
381     family = AF_INET;
382     offset = offsetof(struct sockaddr_in,  sin_addr.s_addr);
383     ip = &addr->vna_v4_ip.s_addr;
384     len = 4;
385     addr->vna_v4_mask.s_addr = htonl(0xffffff00);
386     addr->vna_prefix = 24;
387     break;
388   case VC_NXA_TYPE_IPV6:
389     family = AF_INET6;
390     offset = offsetof(struct sockaddr_in6, sin6_addr.s6_addr);
391     ip = addr->vna_v6_ip.s6_addr;
392     len = 16;
393     addr->vna_v6_mask.s6_addr32[9] = addr->vna_v6_mask.s6_addr32[1] = 0xffffffff;
394     addr->vna_v6_mask.s6_addr32[2] = addr->vna_v6_mask.s6_addr32[3] = 0x00000000;
395     addr->vna_prefix = 64;
396     break;
397   default:
398     errno = EINVAL;
399     return -1;
400   }
401
402   if (getifaddrs(&head) == -1)
403     return -1;
404   for (ifa = head; ifa; ifa = ifa->ifa_next) {
405     if (ifa->ifa_addr->sa_family == family &&
406         memcmp((char *) ifa->ifa_addr + offset, ip, len) == 0) {
407       switch (addr->vna_type) {
408       case VC_NXA_TYPE_IPV4:
409         memcpy(&addr->vna_v4_mask.s_addr, ifa->ifa_netmask + offset, len);
410         addr->vna_prefix = mask_to_prefix(&addr->vna_v4_mask.s_addr, 32);
411         break;
412       case VC_NXA_TYPE_IPV6:
413         memcpy(addr->vna_v6_mask.s6_addr, ifa->ifa_netmask + offset, len);
414         addr->vna_prefix = mask_to_prefix(addr->vna_v6_mask.s6_addr, 128);
415         break;
416       }
417       ret = 1;
418       break;
419     }
420   }
421   freeifaddrs(head);
422   return ret;
423 }
424
425 /* XXX These two functions are really similar */
426 static PyObject *
427 vserver_net_add(PyObject *self, PyObject *args)
428 {
429   struct vc_net_addr addr = { .vna_type = 0 };
430   nid_t nid;
431   const char *ip;
432
433   if (!PyArg_ParseTuple(args, "Is", &nid, &ip))
434     return NULL;
435
436   /* Optimize standard case, which also needs to be handled differently */
437   if (strcmp(ip, "0.0.0.0") == 0) {
438     addr.vna_type = VC_NXA_TYPE_MASK | VC_NXA_TYPE_IPV4;
439     addr.vna_flags = 0;
440     addr.vna_prefix = 0;
441     addr.vna_parent = 0;
442     addr.vna_v4_mask.s_addr = 0;
443     addr.vna_v4_ip.s_addr = 0;
444   }
445   else {
446     if (convert_address(ip, &addr) == -1)
447       return PyErr_Format(PyExc_ValueError, "%s is not a valid IP address", ip);
448
449     switch (get_mask(&addr)) {
450     case -1:
451       return PyErr_SetFromErrno(PyExc_OSError);
452     case 0:
453       /* XXX error here? */
454       break;
455     }
456     addr.vna_type |= VC_NXA_TYPE_ADDR;
457   }
458
459   if (vc_net_add(nid, &addr) == -1 && errno != ESRCH)
460     return PyErr_SetFromErrno(PyExc_OSError);
461
462   return NONE;
463 }
464
465 static PyObject *
466 vserver_net_remove(PyObject *self, PyObject *args)
467 {
468   struct vc_net_addr addr;
469   nid_t nid;
470   const char *ip;
471
472   if (!PyArg_ParseTuple(args, "Is", &nid, &ip))
473     return NULL;
474
475   if (strcmp(ip, "all") == 0)
476     addr.vna_type = VC_NXA_TYPE_ANY;
477   else if (strcmp(ip, "all4") == 0)
478     addr.vna_type = VC_NXA_TYPE_IPV4 | VC_NXA_TYPE_ANY;
479   else if (strcmp(ip, "all6") == 0)
480     addr.vna_type = VC_NXA_TYPE_IPV6 | VC_NXA_TYPE_ANY;
481   else {
482     if (convert_address(ip, &addr) == -1)
483       return PyErr_Format(PyExc_ValueError, "%s is not a valid IP address", ip);
484
485     switch (get_mask(&addr)) {
486     case -1:
487       return PyErr_SetFromErrno(PyExc_OSError);
488     }
489
490     addr.vna_type |= VC_NXA_TYPE_ADDR;
491   }
492
493   if (vc_net_remove(nid, &addr) == -1 && errno != ESRCH)
494     return PyErr_SetFromErrno(PyExc_OSError);
495
496   return NONE;
497 }
498
499 struct secure_dirs {
500   int host_fd;
501   int cwd_fd;
502   int guest_fd;
503   int target_fd;
504 };
505
506 static inline int
507 fchroot(int fd)
508 {
509   if (fchdir(fd) == -1 || chroot(".") == -1)
510     return -1;
511   return 0;
512 }
513
514 static inline int
515 restore_dirs(struct secure_dirs *dirs)
516 {
517   if (dirs->host_fd != -1) {
518     if (fchroot(dirs->host_fd) == -1)
519       return -1;
520     if (close(dirs->host_fd) == -1)
521       return -1;
522   }
523   if (dirs->guest_fd != -1) {
524     if (close(dirs->guest_fd) == -1)
525       return -1;
526   }
527   if (dirs->target_fd != -1) {
528     if (close(dirs->target_fd) == -1)
529       return -1;
530   }
531   if (dirs->cwd_fd != -1) {
532     if (fchdir(dirs->cwd_fd) == -1)
533       return -1;
534     if (close(dirs->cwd_fd) == -1)
535       return -1;
536   }
537   return 0;
538 }
539
540 static inline int
541 secure_chdir(struct secure_dirs *dirs, const char *guest, const char *target)
542 {
543   dirs->host_fd = dirs->cwd_fd = dirs->guest_fd = dirs->target_fd = -1;
544
545   dirs->host_fd = open("/", O_RDONLY|O_DIRECTORY);
546   if (dirs->host_fd == -1)
547     return -1;
548
549   dirs->cwd_fd = open(".", O_RDONLY|O_DIRECTORY);
550   if (dirs->cwd_fd == -1)
551     return -1;
552
553   dirs->guest_fd = open(guest, O_RDONLY|O_DIRECTORY);
554   if (dirs->guest_fd == -1)
555     return -1;
556   if (fchroot(dirs->guest_fd) == -1)
557     return -1;
558
559   dirs->target_fd = open(target, O_RDONLY|O_DIRECTORY);
560   if (dirs->target_fd == -1)
561     return -1;
562
563   if (fchroot(dirs->host_fd) == -1 || close(dirs->host_fd) == -1)
564     return -1;
565   dirs->host_fd = -1;
566   if (close(dirs->guest_fd) == -1)
567     return -1;
568   dirs->guest_fd = -1;
569
570   if (fchdir(dirs->target_fd) == -1 || close(dirs->target_fd) == -1)
571     return -1;
572
573   return 0;
574 }
575
576 static PyObject *
577 vserver_mount(PyObject *self, PyObject *args)
578 {
579   const char *guest, *target, *source, *type, *data = NULL;
580   unsigned long flags = 0;
581   struct secure_dirs dirs;
582
583   if (!PyArg_ParseTuple(args, "ssss|ks", &source, &guest, &target, &type,
584                         &flags, &data))
585     return NULL;
586
587   if (secure_chdir(&dirs, guest, target) == -1)
588     goto out;
589   if (mount(source, ".", type, flags, data) == -1 && errno != EBUSY)
590     goto out;
591   restore_dirs(&dirs);
592
593   return NONE;
594
595 out:
596   restore_dirs(&dirs);
597   return PyErr_SetFromErrno(PyExc_OSError);
598 }
599
600 static PyObject *
601 vserver_umount(PyObject *self, PyObject *args)
602 {
603   const char *guest, *target;
604   int flags = 0;
605   char *path;
606   PyObject *ret;
607
608   if (!PyArg_ParseTuple(args, "ss|i", &guest, &target, &flags))
609     return NULL;
610
611   path = calloc(strlen(guest) + strlen(target) + 2, sizeof(char));
612   sprintf(path, "%s/%s", guest, target);
613   if (umount2(path, flags) == -1)
614     ret = PyErr_SetFromErrno(PyExc_OSError);
615   else
616     ret = NONE;
617   free(path);
618
619   return ret;
620 }
621
622 static PyObject *
623 vserver_set_runlevel(PyObject *self, PyObject *args)
624 {
625   const char *file;
626   int runlevel;
627   struct utmp ut;
628
629   if (!PyArg_ParseTuple(args, "si", &file, &runlevel))
630     return NULL;
631
632   utmpname(file);
633   setutent();
634   memset(&ut, 0, sizeof(ut));
635   ut.ut_type = RUN_LVL;
636   ut.ut_pid = ('#' << 8) + runlevel + '0';
637   pututline(&ut);
638   endutent();
639
640   return NONE;
641 }
642
643 static PyObject *
644 vserver_set_name(PyObject *self, PyObject *args)
645 {
646   xid_t       ctx, slice_id;
647   PyObject    *ret;
648
649   if (!PyArg_ParseTuple(args, "II", &ctx, &slice_id))
650     return NULL;
651
652   if (vc_set_vhi_name(ctx, vcVHI_CONTEXT, (char *)&slice_id, sizeof(slice_id)) != 0 && errno != ESRCH) {
653     return PyErr_SetFromErrno(PyExc_OSError);
654   } else {
655     return NONE;
656   }
657 }
658
659 static PyObject *
660 vserver_get_name(PyObject *self, PyObject *args)
661 {
662   xid_t       ctx, slice_id;
663   PyObject    *ret;
664
665   if (!PyArg_ParseTuple(args, "I", &ctx))
666     return NULL;
667
668   if (vc_get_vhi_name(ctx, vcVHI_CONTEXT, (char *)&slice_id, sizeof(slice_id)) != 0) {
669     ret = PyErr_SetFromErrno(PyExc_OSError);
670   } else {
671     ret = Py_BuildValue("i", slice_id);
672   }
673   return ret;
674 }
675
676
677 static PyMethodDef  methods[] = {
678   { "setdlimit", vserver_set_dlimit, METH_VARARGS,
679     "Set disk limits for given vserver context" },
680   { "unsetdlimit", vserver_unset_dlimit, METH_VARARGS,
681     "Remove disk limits for given vserver context" },
682   { "getdlimit", vserver_get_dlimit, METH_VARARGS,
683     "Get disk limits for given vserver context" },
684   { "setrlimit", vserver_set_rlimit, METH_VARARGS,
685     "Set resource limits for given resource of a vserver context" },
686   { "getrlimit", vserver_get_rlimit, METH_VARARGS,
687     "Get resource limits for given resource of a vserver context" },
688   { "setbcaps", vserver_set_bcaps, METH_VARARGS,
689     "Set POSIX capabilities of a vserver context" },
690   { "getbcaps", vserver_get_bcaps, METH_VARARGS,
691     "Get POSIX capabilities of a vserver context" },
692   { "text2bcaps", vserver_text2bcaps, METH_VARARGS,
693     "Translate a string of capabilities to a bitmap" },
694   { "bcaps2text", vserver_bcaps2text, METH_VARARGS,
695     "Translate a capability-bitmap into a string" },
696   { "setccaps", vserver_set_ccaps, METH_VARARGS,
697     "Set context capabilities of a vserver context" },
698   { "getccaps", vserver_get_ccaps, METH_VARARGS,
699     "Get context capabilities of a vserver context" },
700   { "text2ccaps", vserver_text2ccaps, METH_VARARGS,
701     "Translate a string of context capabilities to a bitmap" },
702   { "ccaps2text", vserver_ccaps2text, METH_VARARGS,
703     "Translate a context-capability-bitmap into a string" },
704   { "netadd", vserver_net_add, METH_VARARGS,
705     "Assign an IP address to a context" },
706   { "netremove", vserver_net_remove, METH_VARARGS,
707     "Remove IP address(es) from a context" },
708   { "mount", vserver_mount, METH_VARARGS,
709     "Perform the mount() system call" },
710   { "umount", vserver_umount, METH_VARARGS,
711     "Perform the umount2() system call" },
712   { "setrunlevel", vserver_set_runlevel, METH_VARARGS,
713     "Set the runlevel in utmp" },
714   { "setname", vserver_set_name, METH_VARARGS,
715     "Set the vcVHI_CONTEXT for a xid." },
716   { "getname", vserver_get_name, METH_VARARGS,
717     "Get the vcVHI_CONTEXT for a xid." },
718   { NULL, NULL, 0, NULL }
719 };
720
721 PyMODINIT_FUNC
722 initvserverimpl(void)
723 {
724   PyObject  *mod;
725
726   mod = Py_InitModule("vserverimpl", methods);
727
728   /* export the set of 'safe' capabilities */
729   PyModule_AddIntConstant(mod, "CAP_SAFE", ~vc_get_insecurebcaps());
730
731   /* export the default vserver directory */
732   PyModule_AddStringConstant(mod, "VSERVER_BASEDIR", DEFAULT_VSERVERDIR);
733
734   /* export limit-related constants */
735   PyModule_AddIntConstant(mod, "DLIMIT_KEEP", (int)VC_CDLIM_KEEP);
736   PyModule_AddIntConstant(mod, "DLIMIT_INF", (int)VC_CDLIM_INFINITY);
737   PyModule_AddIntConstant(mod, "VC_LIM_INFINITY", (int)VC_LIM_INFINITY);
738   PyModule_AddIntConstant(mod, "VC_LIM_KEEP", (int)VC_LIM_KEEP);
739
740   PyModule_AddIntConstant(mod, "RLIMIT_CPU", (int)RLIMIT_CPU);
741   PyModule_AddIntConstant(mod, "RLIMIT_RSS", (int)RLIMIT_RSS);
742   PyModule_AddIntConstant(mod, "RLIMIT_NPROC", (int)RLIMIT_NPROC);
743   PyModule_AddIntConstant(mod, "RLIMIT_NOFILE", (int)RLIMIT_NOFILE);
744   PyModule_AddIntConstant(mod, "RLIMIT_MEMLOCK", (int)RLIMIT_MEMLOCK);
745   PyModule_AddIntConstant(mod, "RLIMIT_AS", (int)RLIMIT_AS);
746   PyModule_AddIntConstant(mod, "RLIMIT_LOCKS", (int)RLIMIT_LOCKS);
747
748   PyModule_AddIntConstant(mod, "RLIMIT_SIGPENDING", (int)RLIMIT_SIGPENDING);
749   PyModule_AddIntConstant(mod, "RLIMIT_MSGQUEUE", (int)RLIMIT_MSGQUEUE);
750
751   PyModule_AddIntConstant(mod, "VLIMIT_NSOCK", (int)VC_VLIMIT_NSOCK);
752   PyModule_AddIntConstant(mod, "VLIMIT_OPENFD", (int)VC_VLIMIT_OPENFD);
753   PyModule_AddIntConstant(mod, "VLIMIT_ANON", (int)VC_VLIMIT_ANON);
754   PyModule_AddIntConstant(mod, "VLIMIT_SHMEM", (int)VC_VLIMIT_SHMEM);
755
756 }