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