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