Fix vserver_isrunning() by doing a simple stat of /proc/virtual/
[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 = Py_BuildValue("i",1);
106   else
107     ret = Py_BuildValue("i",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   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 olim, nlim;
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   default:
163     break;
164   }
165
166   getrlimit(lresource,&olim);
167   if ((limits.min != VC_LIM_KEEP) && (limits.min > olim.rlim_cur)) {
168     nlim.rlim_cur = limits.min;
169     if (limits.min > olim.rlim_max) {
170       nlim.rlim_max = limits.min;
171     } else {
172       nlim.rlim_max = olim.rlim_max;
173     }
174     setrlimit(lresource, &nlim);
175   }
176
177  do_vc_set_rlimit:
178   if (vc_set_rlimit(xid, resource, &limits)) 
179     ret = PyErr_SetFromErrno(PyExc_OSError);
180   else
181     ret = __vserver_get_rlimit(xid, resource);
182
183   return ret;
184 }
185
186 /*
187  * setsched
188  */
189 static PyObject *
190 vserver_setsched(PyObject *self, PyObject *args)
191 {
192   xid_t  ctx;
193   uint32_t  cpu_share;
194   uint32_t  cpu_sched_flags = VC_VXF_SCHED_FLAGS;
195
196   if (!PyArg_ParseTuple(args, "II|I", &ctx, &cpu_share, &cpu_sched_flags))
197     return NULL;
198
199   /* ESRCH indicates that there are no processes in the context */
200   if (pl_setsched(ctx, cpu_share, cpu_sched_flags) &&
201       errno != ESRCH)
202     return PyErr_SetFromErrno(PyExc_OSError);
203
204   return NONE;
205 }
206
207 static PyObject *
208 vserver_get_dlimit(PyObject *self, PyObject *args)
209 {
210   PyObject *res;
211   char* path;
212   unsigned xid;
213   struct vcmd_ctx_dlimit_v0 data;
214   int r;
215
216   if (!PyArg_ParseTuple(args, "si", &path,&xid))
217     return NULL;
218
219   memset(&data, 0, sizeof(data));
220   data.name = path;
221   data.flags = 0;
222   r = vserver(VCMD_get_dlimit, xid, &data);
223   if (r>=0) {
224     res = Py_BuildValue("(i,i,i,i,i)",
225                         data.space_used,
226                         data.space_total,
227                         data.inodes_used,
228                         data.inodes_total,
229                         data.reserved);
230   } else {
231     res = PyErr_SetFromErrno(PyExc_OSError);
232   }
233
234   return res;
235 }
236
237
238 static PyObject *
239 vserver_set_dlimit(PyObject *self, PyObject *args)
240 {
241   char* path;
242   unsigned xid;
243   struct vcmd_ctx_dlimit_base_v0 init;
244   struct vcmd_ctx_dlimit_v0 data;
245
246   memset(&data,0,sizeof(data));
247   if (!PyArg_ParseTuple(args, "siiiiii", &path,
248                         &xid,
249                         &data.space_used,
250                         &data.space_total,
251                         &data.inodes_used,
252                         &data.inodes_total,
253                         &data.reserved))
254     return NULL;
255
256   data.name = path;
257   data.flags = 0;
258
259   memset(&init, 0, sizeof(init));
260   init.name = path;
261   init.flags = 0;
262
263   if ((vserver(VCMD_add_dlimit, xid, &init) && errno != EEXIST) ||
264       vserver(VCMD_set_dlimit, xid, &data))
265     return PyErr_SetFromErrno(PyExc_OSError);
266
267   return NONE;  
268 }
269
270 static PyObject *
271 vserver_unset_dlimit(PyObject *self, PyObject *args)
272 {
273   char  *path;
274   unsigned  xid;
275   struct vcmd_ctx_dlimit_base_v0  init;
276
277   if (!PyArg_ParseTuple(args, "si", &path, &xid))
278     return NULL;
279
280   memset(&init, 0, sizeof(init));
281   init.name = path;
282   init.flags = 0;
283
284   if (vserver(VCMD_rem_dlimit, xid, &init) && errno != ESRCH)
285     return PyErr_SetFromErrno(PyExc_OSError);
286
287   return NONE;  
288 }
289
290 static PyObject *
291 vserver_killall(PyObject *self, PyObject *args)
292 {
293   xid_t  ctx;
294   int  sig;
295
296   if (!PyArg_ParseTuple(args, "Ii", &ctx, &sig))
297     return NULL;
298
299   if (vc_ctx_kill(ctx, 0, sig) && errno != ESRCH)
300     return PyErr_SetFromErrno(PyExc_OSError);
301
302   return NONE;
303 }
304
305 static PyMethodDef  methods[] = {
306   { "chcontext", vserver_chcontext, METH_VARARGS,
307     "chcontext to vserver with provided flags" },
308   { "setup_done", vserver_setup_done, METH_VARARGS,
309     "Release vserver setup lock" },
310   { "setsched", vserver_setsched, METH_VARARGS,
311     "Change vserver scheduling attributes for given vserver context" },
312   { "setdlimit", vserver_set_dlimit, METH_VARARGS,
313     "Set disk limits for given vserver context" },
314   { "unsetdlimit", vserver_unset_dlimit, METH_VARARGS,
315     "Remove disk limits for given vserver context" },
316   { "getdlimit", vserver_get_dlimit, METH_VARARGS,
317     "Get disk limits for given vserver context" },
318   { "setrlimit", vserver_set_rlimit, METH_VARARGS,
319     "Set resource limits for given resource of a vserver context" },
320   { "getrlimit", vserver_get_rlimit, METH_VARARGS,
321     "Get resource limits for given resource of a vserver context" },
322   { "killall", vserver_killall, METH_VARARGS,
323     "Send signal to all processes in vserver context" },
324   { "isrunning", vserver_isrunning, METH_VARARGS,
325     "Check if vserver is running"},
326   { NULL, NULL, 0, NULL }
327 };
328
329 PyMODINIT_FUNC
330 initvserverimpl(void)
331 {
332   PyObject  *mod;
333
334   mod = Py_InitModule("vserverimpl", methods);
335
336   /* export the set of 'safe' capabilities */
337   PyModule_AddIntConstant(mod, "CAP_SAFE", ~vc_get_insecurebcaps());
338
339   /* export the default vserver directory */
340   PyModule_AddStringConstant(mod, "VSERVER_BASEDIR", DEFAULT_VSERVERDIR);
341
342   /* export limit-related constants */
343   PyModule_AddIntConstant(mod, "DLIMIT_KEEP", (int)CDLIM_KEEP);
344   PyModule_AddIntConstant(mod, "DLIMIT_INF", (int)CDLIM_INFINITY);
345   PyModule_AddIntConstant(mod, "VC_LIM_KEEP", (int)VC_LIM_KEEP);
346
347   PyModule_AddIntConstant(mod, "RLIMIT_CPU", (int)RLIMIT_CPU);
348   PyModule_AddIntConstant(mod, "RLIMIT_RSS", (int)RLIMIT_RSS);
349   PyModule_AddIntConstant(mod, "RLIMIT_NPROC", (int)RLIMIT_NPROC);
350   PyModule_AddIntConstant(mod, "RLIMIT_NOFILE", (int)RLIMIT_NOFILE);
351   PyModule_AddIntConstant(mod, "RLIMIT_MEMLOCK", (int)RLIMIT_MEMLOCK);
352   PyModule_AddIntConstant(mod, "RLIMIT_AS", (int)RLIMIT_AS);
353   PyModule_AddIntConstant(mod, "RLIMIT_LOCKS", (int)RLIMIT_LOCKS);
354
355   PyModule_AddIntConstant(mod, "RLIMIT_SIGPENDING", (int)RLIMIT_SIGPENDING);
356   PyModule_AddIntConstant(mod, "RLIMIT_MSGQUEUE", (int)RLIMIT_MSGQUEUE);
357
358   PyModule_AddIntConstant(mod, "VLIMIT_NSOCK", (int)VLIMIT_NSOCK);
359   PyModule_AddIntConstant(mod, "VLIMIT_OPENFD", (int)VLIMIT_OPENFD);
360   PyModule_AddIntConstant(mod, "VLIMIT_ANON", (int)VLIMIT_ANON);
361   PyModule_AddIntConstant(mod, "VLIMIT_SHMEM", (int)VLIMIT_SHMEM);
362
363   /* scheduler flags */
364   PyModule_AddIntConstant(mod,
365                           "VS_SCHED_CPU_GUARANTEED",
366                           VS_SCHED_CPU_GUARANTEED);
367 }