Add killall() function, tidy up.
[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
40 #include "config.h"
41 #include "pathconfig.h"
42 #include "planetlab.h"
43 #include "virtual.h"
44 #include "vserver.h"
45 #include "vserver-internal.h"
46
47 static int
48 get_rspec(PyObject *resources, rspec_t *rspec)
49 {
50   PyObject  *cpu_share;
51
52   if (!PyMapping_Check(resources))
53     {
54       PyErr_SetString(PyExc_TypeError, "invalid rspec");
55       return -1;
56     }
57   if ((cpu_share = PyMapping_GetItemString(resources, "nm_cpu_share")) &&
58       (cpu_share = PyNumber_Int(cpu_share)))
59     rspec->cpu_share = PyInt_AsLong(cpu_share);
60
61   return 0;
62 }
63
64 /*
65  * context create
66  */
67 static PyObject *
68 vserver_chcontext(PyObject *self, PyObject *args)
69 {
70   xid_t  ctx;
71   uint32_t  flags = 0;
72   uint32_t  bcaps = ~vc_get_insecurebcaps();
73   rspec_t  rspec = { 32, VC_VXF_SCHED_FLAGS, -1, -1 };
74   PyObject  *resources;
75
76   if (!PyArg_ParseTuple(args, "IO|K", &ctx, &resources, &flags) ||
77       get_rspec(resources, &rspec))
78     return NULL;
79
80   if (pl_chcontext(ctx, flags, bcaps, &rspec))
81     return PyErr_SetFromErrno(PyExc_OSError);
82
83   return Py_None;
84 }
85
86 static PyObject *
87 vserver_set_rlimit(PyObject *self, PyObject *args) {
88         struct vc_rlimit limits;
89         xid_t xid;
90         int resource;
91         PyObject *ret;
92
93         limits.min = VC_LIM_KEEP;
94         limits.soft = VC_LIM_KEEP;
95         limits.hard = VC_LIM_KEEP;
96
97         if (!PyArg_ParseTuple(args, "IiL", &xid, &resource, &limits.hard))
98                 return NULL;
99
100         ret = Py_None;
101         if (vc_set_rlimit(xid, resource, &limits)) 
102                 ret = PyErr_SetFromErrno(PyExc_OSError);
103         else if (vc_get_rlimit(xid, resource, &limits)==-1)
104                 ret = PyErr_SetFromErrno(PyExc_OSError);
105         else
106                 ret = Py_BuildValue("L",limits.hard);
107
108         return ret;
109 }
110
111 static PyObject *
112 vserver_get_rlimit(PyObject *self, PyObject *args) {
113         struct vc_rlimit limits;
114         xid_t xid;
115         int resource;
116         PyObject *ret;
117
118         limits.min = VC_LIM_KEEP;
119         limits.soft = VC_LIM_KEEP;
120         limits.hard = VC_LIM_KEEP;
121
122         if (!PyArg_ParseTuple(args, "Ii", &xid, &resource))
123                 return NULL;
124
125         ret = Py_None;
126         if (vc_get_rlimit(xid, resource, &limits)==-1)
127                 ret = PyErr_SetFromErrno(PyExc_OSError);
128         else
129                 ret = Py_BuildValue("L",limits.hard);
130
131         return ret;
132 }
133
134 /*
135  * setsched
136  */
137 static PyObject *
138 vserver_setsched(PyObject *self, PyObject *args)
139 {
140   xid_t  ctx;
141   rspec_t  rspec = { 32, VC_VXF_SCHED_FLAGS, -1, -1 };
142   PyObject  *resources;
143
144   if (!PyArg_ParseTuple(args, "IO", &ctx, &resources) ||
145       get_rspec(resources, &rspec))
146     return NULL;
147
148   if (pl_setsched(ctx, rspec.cpu_share, rspec.cpu_sched_flags))
149     return PyErr_SetFromErrno(PyExc_OSError);
150
151   return Py_None;
152 }
153
154 static PyObject *
155 vserver_get_dlimit(PyObject *self, PyObject *args)
156 {
157         PyObject *res;
158         char* path;
159         unsigned xid;
160         struct vcmd_ctx_dlimit_v0 data;
161         int r;
162
163         if (!PyArg_ParseTuple(args, "si", &path,&xid))
164                 return NULL;
165
166         memset(&data, 0, sizeof(data));
167         data.name = path;
168         data.flags = 0;
169         r = vserver(VCMD_get_dlimit, xid, &data);
170         if (r>=0) {
171                 res = Py_BuildValue("(i,i,i,i,i)",
172                                     data.space_used,
173                                     data.space_total,
174                                     data.inodes_used,
175                                     data.inodes_total,
176                                     data.reserved);
177         } else {
178                 res = PyErr_SetFromErrno(PyExc_OSError);
179         }
180
181         return res;
182 }
183
184
185 static PyObject *
186 vserver_set_dlimit(PyObject *self, PyObject *args)
187 {
188         char* path;
189         unsigned xid;
190         struct vcmd_ctx_dlimit_base_v0 init;
191         struct vcmd_ctx_dlimit_v0 data;
192
193         memset(&data,0,sizeof(data));
194         if (!PyArg_ParseTuple(args, "siiiiii", &path,
195                               &xid,
196                               &data.space_used,
197                               &data.space_total,
198                               &data.inodes_used,
199                               &data.inodes_total,
200                               &data.reserved))
201                 return NULL;
202
203         data.name = path;
204         data.flags = 0;
205
206         memset(&init, 0, sizeof(init));
207         init.name = path;
208         init.flags = 0;
209
210         if ((vserver(VCMD_add_dlimit, xid, &init) && errno != EEXIST) ||
211             vserver(VCMD_set_dlimit, xid, &data))
212           return PyErr_SetFromErrno(PyExc_OSError);
213
214         return Py_None; 
215 }
216
217 static PyObject *
218 vserver_unset_dlimit(PyObject *self, PyObject *args)
219 {
220   char  *path;
221   unsigned  xid;
222   struct vcmd_ctx_dlimit_base_v0  init;
223
224   if (!PyArg_ParseTuple(args, "si", &path, &xid))
225     return NULL;
226
227   memset(&init, 0, sizeof(init));
228   init.name = path;
229   init.flags = 0;
230
231   if (vserver(VCMD_rem_dlimit, xid, &init) && errno != ESRCH)
232     return PyErr_SetFromErrno(PyExc_OSError);
233
234   return Py_None;       
235 }
236
237 static PyObject *
238 vserver_killall(PyObject *self, PyObject *args)
239 {
240   xid_t  ctx;
241   int  sig;
242
243   if (!PyArg_ParseTuple(args, "Ii", &ctx, &sig))
244     return NULL;
245
246   if (vc_ctx_kill(ctx, 0, sig) && errno != ESRCH)
247     return PyErr_SetFromErrno(PyExc_OSError);
248
249   return Py_None;
250 }
251
252 static PyMethodDef  methods[] = {
253   { "chcontext", vserver_chcontext, METH_VARARGS,
254     "chcontext to vserver with provided flags" },
255   { "setsched", vserver_setsched, METH_VARARGS,
256     "Change vserver scheduling attributes for given vserver context" },
257   { "setdlimit", vserver_set_dlimit, METH_VARARGS,
258     "Set disk limits for given vserver context" },
259   { "unsetdlimit", vserver_unset_dlimit, METH_VARARGS,
260     "Remove disk limits for given vserver context" },
261   { "getdlimit", vserver_get_dlimit, METH_VARARGS,
262     "Get disk limits for given vserver context" },
263   { "setrlimit", vserver_set_rlimit, METH_VARARGS,
264     "Set resource limits for given resource of a vserver context" },
265   { "getrlimit", vserver_get_rlimit, METH_VARARGS,
266     "Get resource limits for given resource of a vserver context" },
267   { "killall", vserver_killall, METH_VARARGS,
268     "Send signal to all processes in vserver context" },
269   { NULL, NULL, 0, NULL }
270 };
271
272 PyMODINIT_FUNC
273 initvserverimpl(void)
274 {
275   PyObject  *mod;
276
277   mod = Py_InitModule("vserverimpl", methods);
278
279   /* export the set of 'safe' capabilities */
280   PyModule_AddIntConstant(mod, "CAP_SAFE", ~vc_get_insecurebcaps());
281
282   /* export the default vserver directory */
283   PyModule_AddStringConstant(mod, "VSERVER_BASEDIR", DEFAULT_VSERVERDIR);
284
285   /* export limit-related constants */
286   PyModule_AddIntConstant(mod, "DLIMIT_KEEP", (int)CDLIM_KEEP);
287   PyModule_AddIntConstant(mod, "DLIMIT_INF", (int)CDLIM_INFINITY);
288 }