merge with 0.30.213
[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 #define NONE  ({ Py_INCREF(Py_None); Py_None; })
51
52 /*
53  * context create
54  */
55 static PyObject *
56 vserver_chcontext(PyObject *self, PyObject *args)
57 {
58   int  ctx_is_new;
59   xid_t  ctx;
60   uint_least64_t bcaps = ~vc_get_insecurebcaps();
61
62   if (!PyArg_ParseTuple(args, "I", &ctx))
63     return NULL;
64
65   if ((ctx_is_new = pl_chcontext(ctx, bcaps, 0)) < 0)
66     return PyErr_SetFromErrno(PyExc_OSError);
67
68   return PyBool_FromLong(ctx_is_new);
69 }
70
71 static PyObject *
72 vserver_setup_done(PyObject *self, PyObject *args)
73 {
74   xid_t  ctx;
75
76   if (!PyArg_ParseTuple(args, "I", &ctx))
77     return NULL;
78
79   if (pl_setup_done(ctx) < 0)
80     return PyErr_SetFromErrno(PyExc_OSError);
81
82   return NONE;
83 }
84
85 static PyObject *
86 vserver_isrunning(PyObject *self, PyObject *args)
87 {
88   xid_t  ctx;
89   PyObject *ret;
90   struct stat statbuf;
91   char fname[64];
92
93   if (!PyArg_ParseTuple(args, "I", &ctx))
94     return NULL;
95
96   sprintf(fname,"/proc/virtual/%d", ctx);
97
98   if(stat(&fname[0],&statbuf)==0)
99     ret = PyBool_FromLong(1);
100   else
101     ret = PyBool_FromLong(0);
102
103   return ret;
104 }
105
106 static PyObject *
107 __vserver_get_rlimit(xid_t xid, int resource) {
108   struct vc_rlimit limits;
109   PyObject *ret;
110
111   errno = 0;
112   if (vc_get_rlimit(xid, resource, &limits)==-1)
113     ret = PyErr_SetFromErrno(PyExc_OSError);
114   else
115     ret = Py_BuildValue("LLL",limits.hard, limits.soft, limits.min);
116
117   return ret;
118 }
119
120 static PyObject *
121 vserver_get_rlimit(PyObject *self, PyObject *args) {
122   xid_t xid;
123   int resource;
124   PyObject *ret;
125
126   if (!PyArg_ParseTuple(args, "Ii", &xid, &resource))
127     ret = NULL;
128   else
129     ret = __vserver_get_rlimit(xid, resource);
130
131   return ret;
132 }
133
134 static PyObject *
135 vserver_set_rlimit(PyObject *self, PyObject *args) {
136   struct vc_rlimit limits;
137   struct rlimit lim;
138   xid_t xid;
139   int resource, lresource;
140   PyObject *ret;
141
142   limits.min = VC_LIM_KEEP;
143   limits.soft = VC_LIM_KEEP;
144   limits.hard = VC_LIM_KEEP;
145
146   if (!PyArg_ParseTuple(args, "IiLLL", &xid, &resource, &limits.hard, &limits.soft, &limits.min))
147     return NULL;
148
149   lresource = resource;
150   switch (resource) {
151   case VC_VLIMIT_NSOCK:
152   case VC_VLIMIT_ANON:
153   case VC_VLIMIT_SHMEM:
154     goto do_vc_set_rlimit;
155   case VC_VLIMIT_OPENFD:
156     lresource = RLIMIT_NOFILE;
157     break;
158   default:
159     break;
160   }
161
162   getrlimit(lresource,&lim);
163   if (adjust_lim(&limits,&lim)) {
164     setrlimit(lresource, &lim);
165   }
166
167  do_vc_set_rlimit:
168   errno = 0;
169   if (vc_set_rlimit(xid, resource, &limits)==-1) 
170     ret = PyErr_SetFromErrno(PyExc_OSError);
171   else
172     ret = __vserver_get_rlimit(xid, resource);
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_share;
185   uint32_t  cpu_sched_flags = VC_VXF_SCHED_FLAGS;
186
187   if (!PyArg_ParseTuple(args, "II|I", &ctx, &cpu_share, &cpu_sched_flags))
188     return NULL;
189
190   /* ESRCH indicates that there are no processes in the context */
191   if (pl_setsched(ctx, cpu_share, cpu_sched_flags) &&
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
272   if (!PyArg_ParseTuple(args, "Ii", &ctx, &sig))
273     return NULL;
274
275   if (vc_ctx_kill(ctx, 0, sig) && errno != ESRCH)
276     return PyErr_SetFromErrno(PyExc_OSError);
277
278   return NONE;
279 }
280
281 static PyMethodDef  methods[] = {
282   { "chcontext", vserver_chcontext, METH_VARARGS,
283     "chcontext to vserver with provided flags" },
284   { "setup_done", vserver_setup_done, METH_VARARGS,
285     "Release vserver setup lock" },
286   { "setsched", vserver_setsched, METH_VARARGS,
287     "Change vserver scheduling attributes for given vserver context" },
288   { "setdlimit", vserver_set_dlimit, METH_VARARGS,
289     "Set disk limits for given vserver context" },
290   { "unsetdlimit", vserver_unset_dlimit, METH_VARARGS,
291     "Remove disk limits for given vserver context" },
292   { "getdlimit", vserver_get_dlimit, METH_VARARGS,
293     "Get disk limits for given vserver context" },
294   { "setrlimit", vserver_set_rlimit, METH_VARARGS,
295     "Set resource limits for given resource of a vserver context" },
296   { "getrlimit", vserver_get_rlimit, METH_VARARGS,
297     "Get resource limits for given resource of a vserver context" },
298   { "killall", vserver_killall, METH_VARARGS,
299     "Send signal to all processes in vserver context" },
300   { "isrunning", vserver_isrunning, METH_VARARGS,
301     "Check if vserver is running"},
302   { NULL, NULL, 0, NULL }
303 };
304
305 PyMODINIT_FUNC
306 initvserverimpl(void)
307 {
308   PyObject  *mod;
309
310   mod = Py_InitModule("vserverimpl", methods);
311
312   /* export the set of 'safe' capabilities */
313   PyModule_AddIntConstant(mod, "CAP_SAFE", ~vc_get_insecurebcaps());
314
315   /* export the default vserver directory */
316   PyModule_AddStringConstant(mod, "VSERVER_BASEDIR", DEFAULT_VSERVERDIR);
317
318   /* export limit-related constants */
319   PyModule_AddIntConstant(mod, "DLIMIT_KEEP", (int)VC_CDLIM_KEEP);
320   PyModule_AddIntConstant(mod, "DLIMIT_INF", (int)VC_CDLIM_INFINITY);
321   PyModule_AddIntConstant(mod, "VC_LIM_KEEP", (int)VC_LIM_KEEP);
322
323   PyModule_AddIntConstant(mod, "RLIMIT_CPU", (int)RLIMIT_CPU);
324   PyModule_AddIntConstant(mod, "RLIMIT_RSS", (int)RLIMIT_RSS);
325   PyModule_AddIntConstant(mod, "RLIMIT_NPROC", (int)RLIMIT_NPROC);
326   PyModule_AddIntConstant(mod, "RLIMIT_NOFILE", (int)RLIMIT_NOFILE);
327   PyModule_AddIntConstant(mod, "RLIMIT_MEMLOCK", (int)RLIMIT_MEMLOCK);
328   PyModule_AddIntConstant(mod, "RLIMIT_AS", (int)RLIMIT_AS);
329   PyModule_AddIntConstant(mod, "RLIMIT_LOCKS", (int)RLIMIT_LOCKS);
330
331   PyModule_AddIntConstant(mod, "RLIMIT_SIGPENDING", (int)RLIMIT_SIGPENDING);
332   PyModule_AddIntConstant(mod, "RLIMIT_MSGQUEUE", (int)RLIMIT_MSGQUEUE);
333
334   PyModule_AddIntConstant(mod, "VLIMIT_NSOCK", (int)VC_VLIMIT_NSOCK);
335   PyModule_AddIntConstant(mod, "VLIMIT_OPENFD", (int)VC_VLIMIT_OPENFD);
336   PyModule_AddIntConstant(mod, "VLIMIT_ANON", (int)VC_VLIMIT_ANON);
337   PyModule_AddIntConstant(mod, "VLIMIT_SHMEM", (int)VC_VLIMIT_SHMEM);
338
339   /* scheduler flags */
340   PyModule_AddIntConstant(mod,
341                           "VS_SCHED_CPU_GUARANTEED",
342                           VS_SCHED_CPU_GUARANTEED);
343 }