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