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