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