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