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