- clean up vserver_set_rlimit()
[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
43 #include "config.h"
44 #include "pathconfig.h"
45 #include "virtual.h"
46 #include "vserver.h"
47 #include "planetlab.h"
48 #include "vserver-internal.h"
49
50 /* I don't like needing to define __KERNEL__ -- mef */
51 #define __KERNEL__
52 #include "kernel/limit.h"
53 #undef __KERNEL__
54
55 #define NONE  ({ Py_INCREF(Py_None); Py_None; })
56
57 /*
58  * context create
59  */
60 static PyObject *
61 vserver_chcontext(PyObject *self, PyObject *args)
62 {
63   int  result;
64   xid_t  ctx;
65   uint32_t  flags = 0;
66   uint32_t  bcaps = ~vc_get_insecurebcaps();
67
68   if (!PyArg_ParseTuple(args, "I|K", &ctx, &flags))
69     return NULL;
70
71   if ((result = pl_chcontext(ctx, flags, bcaps, 0)) < 0)
72     return PyErr_SetFromErrno(PyExc_OSError);
73
74   return PyBool_FromLong(result);
75 }
76
77 static PyObject *
78 vserver_setup_done(PyObject *self, PyObject *args)
79 {
80   xid_t  ctx;
81
82   if (!PyArg_ParseTuple(args, "I", &ctx))
83     return NULL;
84
85   if (pl_setup_done(ctx) < 0)
86     return PyErr_SetFromErrno(PyExc_OSError);
87
88   return NONE;
89 }
90
91 static PyObject *
92 vserver_isrunning(PyObject *self, PyObject *args)
93 {
94   xid_t  ctx;
95   PyObject *ret;
96   struct stat statbuf;
97   char fname[64];
98
99   if (!PyArg_ParseTuple(args, "I", &ctx))
100     return NULL;
101
102   sprintf(fname,"/proc/virtual/%d", ctx);
103
104   if(stat(&fname[0],&statbuf)==0)
105     ret = PyBool_FromLong(1);
106   else
107     ret = PyBool_FromLong(0);
108
109   return ret;
110 }
111
112 static PyObject *
113 __vserver_get_rlimit(xid_t xid, int resource) {
114   struct vc_rlimit limits;
115   PyObject *ret;
116
117   errno = 0;
118   if (vc_get_rlimit(xid, resource, &limits)==-1)
119     ret = PyErr_SetFromErrno(PyExc_OSError);
120   else
121     ret = Py_BuildValue("LLL",limits.hard, limits.soft, limits.min);
122
123   return ret;
124 }
125
126 static PyObject *
127 vserver_get_rlimit(PyObject *self, PyObject *args) {
128   xid_t xid;
129   int resource;
130   PyObject *ret;
131
132   if (!PyArg_ParseTuple(args, "Ii", &xid, &resource))
133     ret = NULL;
134   else
135     ret = __vserver_get_rlimit(xid, resource);
136
137   return ret;
138 }
139
140 static PyObject *
141 vserver_set_rlimit(PyObject *self, PyObject *args) {
142   struct vc_rlimit limits;
143   struct rlimit lim;
144   xid_t xid;
145   int resource, lresource;
146   PyObject *ret;
147
148   limits.min = VC_LIM_KEEP;
149   limits.soft = VC_LIM_KEEP;
150   limits.hard = VC_LIM_KEEP;
151
152   if (!PyArg_ParseTuple(args, "IiLLL", &xid, &resource, &limits.hard, &limits.soft, &limits.min))
153     return NULL;
154
155   lresource = resource;
156   switch (resource) {
157   case VLIMIT_NSOCK:
158   case VLIMIT_ANON:
159   case VLIMIT_SHMEM:
160     goto do_vc_set_rlimit;
161   case VLIMIT_OPENFD:
162     lresource = RLIMIT_NOFILE;
163     break;
164   default:
165     break;
166   }
167
168   getrlimit(lresource,&lim);
169   if (adjust_lim(&limits,&lim)) {
170     setrlimit(lresource, &lim);
171   }
172
173  do_vc_set_rlimit:
174   errno = 0;
175   if (vc_set_rlimit(xid, resource, &limits)==-1) 
176     ret = PyErr_SetFromErrno(PyExc_OSError);
177   else
178     ret = __vserver_get_rlimit(xid, resource);
179
180   return ret;
181 }
182
183 /*
184  * setsched
185  */
186 static PyObject *
187 vserver_setsched(PyObject *self, PyObject *args)
188 {
189   xid_t  ctx;
190   uint32_t  cpu_share;
191   uint32_t  cpu_sched_flags = VC_VXF_SCHED_FLAGS;
192
193   if (!PyArg_ParseTuple(args, "II|I", &ctx, &cpu_share, &cpu_sched_flags))
194     return NULL;
195
196   /* ESRCH indicates that there are no processes in the context */
197   if (pl_setsched(ctx, cpu_share, cpu_sched_flags) &&
198       errno != ESRCH)
199     return PyErr_SetFromErrno(PyExc_OSError);
200
201   return NONE;
202 }
203
204 static PyObject *
205 vserver_get_dlimit(PyObject *self, PyObject *args)
206 {
207   PyObject *res;
208   char* path;
209   unsigned xid;
210   struct vcmd_ctx_dlimit_v0 data;
211   int r;
212
213   if (!PyArg_ParseTuple(args, "si", &path,&xid))
214     return NULL;
215
216   memset(&data, 0, sizeof(data));
217   data.name = path;
218   data.flags = 0;
219   r = vserver(VCMD_get_dlimit, xid, &data);
220   if (r>=0) {
221     res = Py_BuildValue("(i,i,i,i,i)",
222                         data.space_used,
223                         data.space_total,
224                         data.inodes_used,
225                         data.inodes_total,
226                         data.reserved);
227   } else {
228     res = PyErr_SetFromErrno(PyExc_OSError);
229   }
230
231   return res;
232 }
233
234
235 static PyObject *
236 vserver_set_dlimit(PyObject *self, PyObject *args)
237 {
238   char* path;
239   unsigned xid;
240   struct vcmd_ctx_dlimit_base_v0 init;
241   struct vcmd_ctx_dlimit_v0 data;
242
243   memset(&data,0,sizeof(data));
244   if (!PyArg_ParseTuple(args, "siiiiii", &path,
245                         &xid,
246                         &data.space_used,
247                         &data.space_total,
248                         &data.inodes_used,
249                         &data.inodes_total,
250                         &data.reserved))
251     return NULL;
252
253   data.name = path;
254   data.flags = 0;
255
256   memset(&init, 0, sizeof(init));
257   init.name = path;
258   init.flags = 0;
259
260   if ((vserver(VCMD_add_dlimit, xid, &init) && errno != EEXIST) ||
261       vserver(VCMD_set_dlimit, xid, &data))
262     return PyErr_SetFromErrno(PyExc_OSError);
263
264   return NONE;  
265 }
266
267 static PyObject *
268 vserver_unset_dlimit(PyObject *self, PyObject *args)
269 {
270   char  *path;
271   unsigned  xid;
272   struct vcmd_ctx_dlimit_base_v0  init;
273
274   if (!PyArg_ParseTuple(args, "si", &path, &xid))
275     return NULL;
276
277   memset(&init, 0, sizeof(init));
278   init.name = path;
279   init.flags = 0;
280
281   if (vserver(VCMD_rem_dlimit, xid, &init) && errno != ESRCH)
282     return PyErr_SetFromErrno(PyExc_OSError);
283
284   return NONE;  
285 }
286
287 static PyObject *
288 vserver_killall(PyObject *self, PyObject *args)
289 {
290   xid_t  ctx;
291   int  sig;
292
293   if (!PyArg_ParseTuple(args, "Ii", &ctx, &sig))
294     return NULL;
295
296   if (vc_ctx_kill(ctx, 0, sig) && errno != ESRCH)
297     return PyErr_SetFromErrno(PyExc_OSError);
298
299   return NONE;
300 }
301
302 static PyMethodDef  methods[] = {
303   { "chcontext", vserver_chcontext, METH_VARARGS,
304     "chcontext to vserver with provided flags" },
305   { "setup_done", vserver_setup_done, METH_VARARGS,
306     "Release vserver setup lock" },
307   { "setsched", vserver_setsched, METH_VARARGS,
308     "Change vserver scheduling attributes for given vserver context" },
309   { "setdlimit", vserver_set_dlimit, METH_VARARGS,
310     "Set disk limits for given vserver context" },
311   { "unsetdlimit", vserver_unset_dlimit, METH_VARARGS,
312     "Remove disk limits for given vserver context" },
313   { "getdlimit", vserver_get_dlimit, METH_VARARGS,
314     "Get disk limits for given vserver context" },
315   { "setrlimit", vserver_set_rlimit, METH_VARARGS,
316     "Set resource limits for given resource of a vserver context" },
317   { "getrlimit", vserver_get_rlimit, METH_VARARGS,
318     "Get resource limits for given resource of a vserver context" },
319   { "killall", vserver_killall, METH_VARARGS,
320     "Send signal to all processes in vserver context" },
321   { "isrunning", vserver_isrunning, METH_VARARGS,
322     "Check if vserver is running"},
323   { NULL, NULL, 0, NULL }
324 };
325
326 PyMODINIT_FUNC
327 initvserverimpl(void)
328 {
329   PyObject  *mod;
330
331   mod = Py_InitModule("vserverimpl", methods);
332
333   /* export the set of 'safe' capabilities */
334   PyModule_AddIntConstant(mod, "CAP_SAFE", ~vc_get_insecurebcaps());
335
336   /* export the default vserver directory */
337   PyModule_AddStringConstant(mod, "VSERVER_BASEDIR", DEFAULT_VSERVERDIR);
338
339   /* export limit-related constants */
340   PyModule_AddIntConstant(mod, "DLIMIT_KEEP", (int)CDLIM_KEEP);
341   PyModule_AddIntConstant(mod, "DLIMIT_INF", (int)CDLIM_INFINITY);
342   PyModule_AddIntConstant(mod, "VC_LIM_KEEP", (int)VC_LIM_KEEP);
343
344   PyModule_AddIntConstant(mod, "RLIMIT_CPU", (int)RLIMIT_CPU);
345   PyModule_AddIntConstant(mod, "RLIMIT_RSS", (int)RLIMIT_RSS);
346   PyModule_AddIntConstant(mod, "RLIMIT_NPROC", (int)RLIMIT_NPROC);
347   PyModule_AddIntConstant(mod, "RLIMIT_NOFILE", (int)RLIMIT_NOFILE);
348   PyModule_AddIntConstant(mod, "RLIMIT_MEMLOCK", (int)RLIMIT_MEMLOCK);
349   PyModule_AddIntConstant(mod, "RLIMIT_AS", (int)RLIMIT_AS);
350   PyModule_AddIntConstant(mod, "RLIMIT_LOCKS", (int)RLIMIT_LOCKS);
351
352   PyModule_AddIntConstant(mod, "RLIMIT_SIGPENDING", (int)RLIMIT_SIGPENDING);
353   PyModule_AddIntConstant(mod, "RLIMIT_MSGQUEUE", (int)RLIMIT_MSGQUEUE);
354
355   PyModule_AddIntConstant(mod, "VLIMIT_NSOCK", (int)VLIMIT_NSOCK);
356   PyModule_AddIntConstant(mod, "VLIMIT_OPENFD", (int)VLIMIT_OPENFD);
357   PyModule_AddIntConstant(mod, "VLIMIT_ANON", (int)VLIMIT_ANON);
358   PyModule_AddIntConstant(mod, "VLIMIT_SHMEM", (int)VLIMIT_SHMEM);
359
360   /* scheduler flags */
361   PyModule_AddIntConstant(mod,
362                           "VS_SCHED_CPU_GUARANTEED",
363                           VS_SCHED_CPU_GUARANTEED);
364 }