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