Merge 0.30.214.
[util-vserver.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 "pathconfig.h"
52 #include "virtual.h"
53 #include "vserver.h"
54 #include "planetlab.h"
55 #include "vserver-internal.h"
56
57 static inline PyObject *inc_and_ret_none(void)
58 {
59   Py_INCREF(Py_None);
60   return Py_None;
61 }
62
63 #define NONE  inc_and_ret_none()
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 |= ~vc_get_insecurebcaps();
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 rlimit lim;
152   xid_t xid;
153   int resource, lresource;
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   lresource = resource;
164   switch (resource) {
165   case VC_VLIMIT_NSOCK:
166   case VC_VLIMIT_ANON:
167   case VC_VLIMIT_SHMEM:
168     goto do_vc_set_rlimit;
169   case VC_VLIMIT_OPENFD:
170     lresource = RLIMIT_NOFILE;
171     break;
172   default:
173     break;
174   }
175
176   getrlimit(lresource,&lim);
177   if (adjust_lim(&limits,&lim)) {
178     setrlimit(lresource, &lim);
179   }
180
181  do_vc_set_rlimit:
182   errno = 0;
183   if (vc_set_rlimit(xid, resource, &limits)==-1) 
184     ret = PyErr_SetFromErrno(PyExc_OSError);
185   else
186     ret = __vserver_get_rlimit(xid, resource);
187
188   return ret;
189 }
190
191 /*
192  * setsched
193  */
194 static PyObject *
195 vserver_setsched(PyObject *self, PyObject *args)
196 {
197   xid_t  ctx;
198   uint32_t  cpu_share;
199   uint32_t  cpu_sched_flags = VC_VXF_SCHED_FLAGS;
200
201   if (!PyArg_ParseTuple(args, "II|I", &ctx, &cpu_share, &cpu_sched_flags))
202     return NULL;
203
204   /* ESRCH indicates that there are no processes in the context */
205   if (pl_setsched(ctx, cpu_share, cpu_sched_flags) &&
206       errno != ESRCH)
207     return PyErr_SetFromErrno(PyExc_OSError);
208
209   return NONE;
210 }
211
212 static PyObject *
213 vserver_get_dlimit(PyObject *self, PyObject *args)
214 {
215   PyObject *res;
216   char* path;
217   unsigned xid;
218   struct vc_ctx_dlimit data;
219   int r;
220
221   if (!PyArg_ParseTuple(args, "si", &path,&xid))
222     return NULL;
223
224   memset(&data, 0, sizeof(data));
225   r = vc_get_dlimit(path, xid, 0, &data);
226   if (r>=0) {
227     res = Py_BuildValue("(i,i,i,i,i)",
228                         data.space_used,
229                         data.space_total,
230                         data.inodes_used,
231                         data.inodes_total,
232                         data.reserved);
233   } else {
234     res = PyErr_SetFromErrno(PyExc_OSError);
235   }
236
237   return res;
238 }
239
240
241 static PyObject *
242 vserver_set_dlimit(PyObject *self, PyObject *args)
243 {
244   char* path;
245   unsigned xid;
246   struct vc_ctx_dlimit data;
247
248   memset(&data,0,sizeof(data));
249   if (!PyArg_ParseTuple(args, "siiiiii", &path,
250                         &xid,
251                         &data.space_used,
252                         &data.space_total,
253                         &data.inodes_used,
254                         &data.inodes_total,
255                         &data.reserved))
256     return NULL;
257
258   if ((vc_add_dlimit(path, xid, 0) && errno != EEXIST) ||
259       vc_set_dlimit(path, xid, 0, &data))
260     return PyErr_SetFromErrno(PyExc_OSError);
261
262   return NONE;  
263 }
264
265 static PyObject *
266 vserver_unset_dlimit(PyObject *self, PyObject *args)
267 {
268   char  *path;
269   unsigned  xid;
270
271   if (!PyArg_ParseTuple(args, "si", &path, &xid))
272     return NULL;
273
274   if (vc_rem_dlimit(path, xid, 0) && errno != ESRCH)
275     return PyErr_SetFromErrno(PyExc_OSError);
276
277   return NONE;  
278 }
279
280 static PyObject *
281 vserver_killall(PyObject *self, PyObject *args)
282 {
283   xid_t ctx;
284   int   sig;
285   struct vc_ctx_flags cflags = {
286     .flagword = 0,
287     .mask = VC_VXF_PERSISTENT
288   };
289   struct vc_net_flags nflags = {
290     .flagword = 0,
291     .mask = VC_NXF_PERSISTENT
292   };
293
294   if (!PyArg_ParseTuple(args, "Ii", &ctx, &sig))
295     return NULL;
296
297   if (vc_ctx_kill(ctx, 0, sig) && errno != ESRCH)
298     return PyErr_SetFromErrno(PyExc_OSError);
299
300   if (vc_set_cflags(ctx, &cflags) && errno != ESRCH)
301     return PyErr_SetFromErrno(PyExc_OSError);
302
303   if (vc_set_nflags(ctx, &nflags) && errno != ESRCH)
304     return PyErr_SetFromErrno(PyExc_OSError);
305
306   return NONE;
307 }
308
309 static PyObject *
310 vserver_set_bcaps(PyObject *self, PyObject *args)
311 {
312   xid_t ctx;
313   struct vc_ctx_caps caps;
314
315   if (!PyArg_ParseTuple(args, "IK", &ctx, &caps.bcaps))
316     return NULL;
317
318   caps.bmask = vc_get_insecurebcaps();
319   caps.cmask = caps.ccaps = 0;
320   if (vc_set_ccaps(ctx, &caps) == -1 && errno != ESRCH)
321     return PyErr_SetFromErrno(PyExc_OSError);
322
323   return NONE;
324 }
325
326 static PyObject *
327 vserver_text2bcaps(PyObject *self, PyObject *args)
328 {
329   struct vc_ctx_caps caps = { .bcaps = 0 };
330   const char *list;
331   int len;
332   struct vc_err_listparser err;
333
334   if (!PyArg_ParseTuple(args, "s#", &list, &len))
335     return NULL;
336
337   vc_list2bcap(list, len, &err, &caps);
338
339   return Py_BuildValue("K", caps.bcaps);
340 }
341
342 static PyObject *
343 vserver_get_bcaps(PyObject *self, PyObject *args)
344 {
345   xid_t ctx;
346   struct vc_ctx_caps caps;
347
348   if (!PyArg_ParseTuple(args, "I", &ctx))
349     return NULL;
350
351   if (vc_get_ccaps(ctx, &caps) == -1) {
352     if (errno != -ESRCH)
353       return PyErr_SetFromErrno(PyExc_OSError);
354     else
355       caps.bcaps = 0;
356   }
357
358   return Py_BuildValue("K", caps.bcaps & vc_get_insecurebcaps());
359 }
360
361 static PyObject *
362 vserver_bcaps2text(PyObject *self, PyObject *args)
363 {
364   struct vc_ctx_caps caps = { .bcaps = 0 };
365   PyObject *list;
366   const char *cap;
367
368   if (!PyArg_ParseTuple(args, "K", &caps.bcaps))
369     return NULL;
370
371   list = PyString_FromString("");
372
373   while ((cap = vc_lobcap2text(&caps.bcaps)) != NULL) {
374     if (list == NULL)
375       break;
376     PyString_ConcatAndDel(&list, PyString_FromFormat(
377                           (PyString_Size(list) > 0 ? ",CAP_%s" : "CAP_%s" ),
378                           cap));
379   }
380
381   return list;
382 }
383
384 static inline int
385 convert_address(const char *str, struct vc_net_addr *addr)
386 {
387   void *dst;
388   if (inet_pton(AF_INET6, str, addr->vna_v6_ip.s6_addr) > 0) {
389     addr->vna_type = VC_NXA_TYPE_IPV6;
390     return 0;
391   }
392   else if (inet_pton(AF_INET, str, &addr->vna_v4_ip.s_addr) > 0) {
393     addr->vna_type = VC_NXA_TYPE_IPV4;
394     return 0;
395   }
396   return -1;
397 }
398
399 static int
400 mask_to_prefix(void *data, int limit)
401 {
402   uint8_t *mask = data;
403   int prefix;
404   for (prefix = 0; prefix < limit && mask[prefix >> 3] & (1 << (prefix & 0x07)); prefix++)
405     ;
406   return prefix;
407 }
408
409 static int
410 get_mask(struct vc_net_addr *addr)
411 {
412   struct ifaddrs *head, *ifa;
413   int ret = 0;
414   int family, offset, len;
415   void *ip;
416
417   switch (addr->vna_type) {
418   case VC_NXA_TYPE_IPV4:
419     family = AF_INET;
420     offset = offsetof(struct sockaddr_in,  sin_addr.s_addr);
421     ip = &addr->vna_v4_ip.s_addr;
422     len = 4;
423     addr->vna_v4_mask.s_addr = htonl(0xffffff00);
424     addr->vna_prefix = 24;
425     break;
426   case VC_NXA_TYPE_IPV6:
427     family = AF_INET6;
428     offset = offsetof(struct sockaddr_in6, sin6_addr.s6_addr);
429     ip = addr->vna_v6_ip.s6_addr;
430     len = 16;
431     addr->vna_v6_mask.s6_addr32[9] = addr->vna_v6_mask.s6_addr32[1] = 0xffffffff;
432     addr->vna_v6_mask.s6_addr32[2] = addr->vna_v6_mask.s6_addr32[3] = 0x00000000;
433     addr->vna_prefix = 64;
434     break;
435   default:
436     errno = -EINVAL;
437     return -1;
438   }
439
440   if (getifaddrs(&head) == -1)
441     return -1;
442   for (ifa = head; ifa; ifa = ifa->ifa_next) {
443     if (ifa->ifa_addr->sa_family == family &&
444         memcmp((char *) ifa->ifa_addr + offset, ip, len) == 0) {
445       switch (addr->vna_type) {
446       case VC_NXA_TYPE_IPV4:
447         memcpy(&addr->vna_v4_mask.s_addr, ifa->ifa_netmask + offset, len);
448         addr->vna_prefix = mask_to_prefix(&addr->vna_v4_mask.s_addr, 32);
449         break;
450       case VC_NXA_TYPE_IPV6:
451         memcpy(addr->vna_v6_mask.s6_addr, ifa->ifa_netmask + offset, len);
452         addr->vna_prefix = mask_to_prefix(addr->vna_v6_mask.s6_addr, 128);
453         break;
454       }
455       ret = 1;
456       break;
457     }
458   }
459   freeifaddrs(head);
460   return ret;
461 }
462
463 /* XXX These two functions are really similar */
464 static PyObject *
465 vserver_net_add(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 (convert_address(ip, &addr) == -1)
475     return PyErr_Format(PyExc_ValueError, "%s is not a valid IP address", ip);
476
477   switch (get_mask(&addr)) {
478   case -1:
479     return PyErr_SetFromErrno(PyExc_OSError);
480   case 0:
481     /* XXX error here? */
482     break;
483   }
484   addr.vna_type |= VC_NXA_TYPE_ADDR;
485
486   if (vc_net_add(nid, &addr) == -1 && errno != ESRCH)
487     return PyErr_SetFromErrno(PyExc_OSError);
488
489   return NONE;
490 }
491
492 static PyObject *
493 vserver_net_remove(PyObject *self, PyObject *args)
494 {
495   struct vc_net_addr addr;
496   nid_t nid;
497   const char *ip;
498
499   if (!PyArg_ParseTuple(args, "Is", &nid, &ip))
500     return NULL;
501
502   if (strcmp(ip, "all") == 0)
503     addr.vna_type = VC_NXA_TYPE_ANY;
504   else if (strcmp(ip, "all4") == 0)
505     addr.vna_type = VC_NXA_TYPE_IPV6 | VC_NXA_TYPE_ANY;
506   else if (strcmp(ip, "all6") == 0)
507     addr.vna_type = VC_NXA_TYPE_IPV6 | VC_NXA_TYPE_ANY;
508   else {
509     if (convert_address(ip, &addr) == -1)
510       return PyErr_Format(PyExc_ValueError, "%s is not a valid IP address", ip);
511     addr.vna_type |= VC_NXA_TYPE_ADDR;
512   }
513
514   switch (get_mask(&addr)) {
515   case -1:
516     return PyErr_SetFromErrno(PyExc_OSError);
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)
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 PyMethodDef  methods[] = {
670   { "chcontext", vserver_chcontext, METH_VARARGS,
671     "chcontext to vserver with provided flags" },
672   { "setup_done", vserver_setup_done, METH_VARARGS,
673     "Release vserver setup lock" },
674   { "setsched", vserver_setsched, METH_VARARGS,
675     "Change vserver scheduling attributes for given vserver context" },
676   { "setdlimit", vserver_set_dlimit, METH_VARARGS,
677     "Set disk limits for given vserver context" },
678   { "unsetdlimit", vserver_unset_dlimit, METH_VARARGS,
679     "Remove disk limits for given vserver context" },
680   { "getdlimit", vserver_get_dlimit, METH_VARARGS,
681     "Get disk limits for given vserver context" },
682   { "setrlimit", vserver_set_rlimit, METH_VARARGS,
683     "Set resource limits for given resource of a vserver context" },
684   { "getrlimit", vserver_get_rlimit, METH_VARARGS,
685     "Get resource limits for given resource of a vserver context" },
686   { "killall", vserver_killall, METH_VARARGS,
687     "Send signal to all processes in vserver context" },
688   { "isrunning", vserver_isrunning, METH_VARARGS,
689     "Check if vserver is running"},
690   { "setbcaps", vserver_set_bcaps, METH_VARARGS,
691     "Set POSIX capabilities of a vserver context" },
692   { "getbcaps", vserver_get_bcaps, METH_VARARGS,
693     "Get POSIX capabilities of a vserver context" },
694   { "text2bcaps", vserver_text2bcaps, METH_VARARGS,
695     "Translate a string of capabilities to a bitmap" },
696   { "bcaps2text", vserver_bcaps2text, METH_VARARGS,
697     "Translate a capability-bitmap into a string" },
698   { "netadd", vserver_net_add, METH_VARARGS,
699     "Assign an IP address to a context" },
700   { "netremove", vserver_net_remove, METH_VARARGS,
701     "Remove IP address(es) from a context" },
702   { "mount", vserver_mount, METH_VARARGS,
703     "Perform the mount() system call" },
704   { "umount", vserver_umount, METH_VARARGS,
705     "Perform the umount2() system call" },
706   { "setrunlevel", vserver_set_runlevel, METH_VARARGS,
707     "Set the runlevel in utmp" },
708   { NULL, NULL, 0, NULL }
709 };
710
711 PyMODINIT_FUNC
712 initvserverimpl(void)
713 {
714   PyObject  *mod;
715
716   mod = Py_InitModule("vserverimpl", methods);
717
718   /* export the set of 'safe' capabilities */
719   PyModule_AddIntConstant(mod, "CAP_SAFE", ~vc_get_insecurebcaps());
720
721   /* export the default vserver directory */
722   PyModule_AddStringConstant(mod, "VSERVER_BASEDIR", DEFAULT_VSERVERDIR);
723
724   /* export limit-related constants */
725   PyModule_AddIntConstant(mod, "DLIMIT_KEEP", (int)VC_CDLIM_KEEP);
726   PyModule_AddIntConstant(mod, "DLIMIT_INF", (int)VC_CDLIM_INFINITY);
727   PyModule_AddIntConstant(mod, "VC_LIM_KEEP", (int)VC_LIM_KEEP);
728
729   PyModule_AddIntConstant(mod, "RLIMIT_CPU", (int)RLIMIT_CPU);
730   PyModule_AddIntConstant(mod, "RLIMIT_RSS", (int)RLIMIT_RSS);
731   PyModule_AddIntConstant(mod, "RLIMIT_NPROC", (int)RLIMIT_NPROC);
732   PyModule_AddIntConstant(mod, "RLIMIT_NOFILE", (int)RLIMIT_NOFILE);
733   PyModule_AddIntConstant(mod, "RLIMIT_MEMLOCK", (int)RLIMIT_MEMLOCK);
734   PyModule_AddIntConstant(mod, "RLIMIT_AS", (int)RLIMIT_AS);
735   PyModule_AddIntConstant(mod, "RLIMIT_LOCKS", (int)RLIMIT_LOCKS);
736
737   PyModule_AddIntConstant(mod, "RLIMIT_SIGPENDING", (int)RLIMIT_SIGPENDING);
738   PyModule_AddIntConstant(mod, "RLIMIT_MSGQUEUE", (int)RLIMIT_MSGQUEUE);
739
740   PyModule_AddIntConstant(mod, "VLIMIT_NSOCK", (int)VC_VLIMIT_NSOCK);
741   PyModule_AddIntConstant(mod, "VLIMIT_OPENFD", (int)VC_VLIMIT_OPENFD);
742   PyModule_AddIntConstant(mod, "VLIMIT_ANON", (int)VC_VLIMIT_ANON);
743   PyModule_AddIntConstant(mod, "VLIMIT_SHMEM", (int)VC_VLIMIT_SHMEM);
744
745   /* scheduler flags */
746   PyModule_AddIntConstant(mod,
747                           "VS_SCHED_CPU_GUARANTEED",
748                           VS_SCHED_CPU_GUARANTEED);
749 }