Fixed a number of bugs:
[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 "config.h"
37 #include "compat.h"
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <errno.h>
42 #include <string.h>
43 #include <sys/ioctl.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <fcntl.h>
47 #include <unistd.h>
48 #include <stdint.h>
49
50 #include "vserver.h"
51 #include "vserver-internal.h"
52 #include "sched_cmd.h"
53 #include "virtual.h"
54
55 /*
56  * context create
57  */
58 static PyObject *
59 vserver_create(PyObject *self, PyObject *args)
60 {
61         xid_t ctx, xid;
62
63         if (!PyArg_ParseTuple(args, "I", &ctx))
64                 return NULL;
65
66         xid = vc_ctx_create(ctx);
67 #ifdef MEF_DEBUG
68         printf("vserver_create xid = %d\n",xid);
69 #endif
70         if (xid == VC_NOCTX && errno != EEXIST)
71                 return PyErr_SetFromErrno(PyExc_OSError);
72         return Py_None;
73 }
74
75 /*
76  * set flags
77  */
78 static PyObject *
79 vserver_flags(PyObject *self, PyObject *args)
80 {
81         struct vc_ctx_caps caps;
82         struct vc_ctx_flags flags;
83 #ifdef MEF_DEBUG
84         xid_t xid;
85 #endif
86         xid_t ctx;
87
88         caps.ccaps = ~vc_get_insecureccaps();
89         caps.cmask = ~0ull;
90         caps.bcaps = ~vc_get_insecurebcaps();
91         caps.bmask = ~0ull;
92
93         flags.flagword = VC_VXF_STATE_SETUP| VC_VXF_INFO_LOCK;
94         flags.mask = VC_VXF_STATE_SETUP | VC_VXF_INFO_LOCK;
95
96         if (!PyArg_ParseTuple(args, "I", &ctx))
97                 return NULL;
98
99 #ifdef MEF_DEBUG
100         xid = vc_get_task_xid(0);
101         printf("vserver_flags xid = %d, ctx = %d\n",xid,ctx);
102 #endif
103
104         if (vc_set_ccaps(ctx, &caps) == -1)
105                 return PyErr_SetFromErrno(PyExc_OSError);
106
107 #ifdef MEF_DEBUG
108         xid = vc_get_task_xid(0);
109         printf("vserver_flags xid = %d, ctx = %d\n",xid,ctx);
110 #endif
111
112         if (vc_set_cflags(ctx, &flags) == -1)
113                 return PyErr_SetFromErrno(PyExc_OSError);
114
115 #ifdef MEF_DEBUG
116         xid = vc_get_task_xid(0);
117         printf("vserver_flags xid = %d, ctx = %d\n",xid,ctx);
118 #endif
119
120
121         return Py_None;
122 }
123
124 /*
125  * enter
126  */
127 static PyObject *
128 vserver_enter(PyObject *self, PyObject *args)
129 {
130         xid_t ctx, xid;
131         if (!PyArg_ParseTuple(args, "I", &ctx))
132                 return NULL;
133
134         xid = vc_get_task_xid(0);
135 #ifdef MEF_DEBUG
136         printf("vserver_enter xid = %d\n",xid);
137 #endif
138         if (xid != ctx) {
139                 if (xid!=0) {
140                         errno=EPERM;
141                         return PyErr_SetFromErrno(PyExc_OSError);
142                 } else if (vc_ctx_migrate(ctx) == -1)
143                         return PyErr_SetFromErrno(PyExc_OSError);
144         }
145
146         return Py_None;
147 }
148
149 static PyObject *
150 vserver_set_rlimit(PyObject *self, PyObject *args) {
151         struct vc_rlimit limits;
152         xid_t xid;
153         int resource;
154         PyObject *ret;
155
156         limits.min = VC_LIM_KEEP;
157         limits.soft = VC_LIM_KEEP;
158         limits.hard = VC_LIM_KEEP;
159
160         if (!PyArg_ParseTuple(args, "IiL", &xid, &resource, &limits.hard))
161                 return NULL;
162
163         ret = Py_None;
164         if (vc_set_rlimit(xid, resource, &limits)) 
165                 ret = PyErr_SetFromErrno(PyExc_OSError);
166         else if (vc_get_rlimit(xid, resource, &limits)==-1)
167                 ret = PyErr_SetFromErrno(PyExc_OSError);
168         else
169                 ret = Py_BuildValue("L",limits.hard);
170
171         return ret;
172 }
173
174 static PyObject *
175 vserver_get_rlimit(PyObject *self, PyObject *args) {
176         struct vc_rlimit limits;
177         xid_t xid;
178         int resource;
179         PyObject *ret;
180
181         limits.min = VC_LIM_KEEP;
182         limits.soft = VC_LIM_KEEP;
183         limits.hard = VC_LIM_KEEP;
184
185         if (!PyArg_ParseTuple(args, "Ii", &xid, &resource))
186                 return NULL;
187
188         ret = Py_None;
189         if (vc_get_rlimit(xid, resource, &limits)==-1)
190                 ret = PyErr_SetFromErrno(PyExc_OSError);
191         else
192                 ret = Py_BuildValue("L",limits.hard);
193
194         return ret;
195 }
196
197 /*
198  * setsched
199  */
200 static PyObject *
201 vserver_setsched(PyObject *self, PyObject *args)
202 {
203   xid_t  xid;
204   struct vc_set_sched sched;
205   struct vc_ctx_flags flags;
206   unsigned cpuguaranteed = 0;
207
208   sched.set_mask = (VC_VXSM_FILL_RATE | 
209                     VC_VXSM_INTERVAL | 
210                     VC_VXSM_TOKENS_MIN | 
211                     VC_VXSM_TOKENS_MAX);
212
213   if (!PyArg_ParseTuple(args, "I|I|I|I|I|I|I", &xid, 
214                         &sched.fill_rate,
215                         &sched.interval,
216                         &sched.tokens,
217                         &sched.tokens_min,
218                         &sched.tokens_max,
219                         &cpuguaranteed))
220     return NULL;
221
222   flags.flagword = VC_VXF_INFO_LOCK;
223   flags.mask = VC_VXF_INFO_LOCK;
224   flags.flagword |= VC_VXF_SCHED_HARD;
225   flags.mask |= VC_VXF_SCHED_HARD;
226 #define VC_VXF_SCHED_SHARE       0x00000800ull
227   if (cpuguaranteed==0) {
228           flags.flagword |= VC_VXF_SCHED_SHARE;
229           flags.mask |= VC_VXF_SCHED_SHARE;
230   }
231
232   if (vc_set_cflags(xid, &flags) == -1)
233           return PyErr_SetFromErrno(PyExc_OSError);
234
235   if (vc_set_sched(xid, &sched) == -1)
236           return PyErr_SetFromErrno(PyExc_OSError);
237
238   return Py_None;
239 }
240
241 /*
242  * setsched
243  */
244
245 /*  inode vserver commands */
246 #define VCMD_add_dlimit         VC_CMD(DLIMIT, 1, 0)
247 #define VCMD_rem_dlimit         VC_CMD(DLIMIT, 2, 0)
248 #define VCMD_set_dlimit         VC_CMD(DLIMIT, 5, 0)
249 #define VCMD_get_dlimit         VC_CMD(DLIMIT, 6, 0)
250
251 #define CDLIM_UNSET             (0ULL)
252 #define CDLIM_INFINITY          (~0ULL)
253 #define CDLIM_KEEP              (~1ULL)
254
255 static PyObject *
256 vserver_get_dlimit(PyObject *self, PyObject *args)
257 {
258         PyObject *res;
259         char* path;
260         unsigned xid;
261         struct vcmd_ctx_dlimit_v0 data;
262         int r;
263
264         if (!PyArg_ParseTuple(args, "si", &path,&xid))
265                 return NULL;
266
267         memset(&data, 0, sizeof(data));
268         data.name = path;
269         data.flags = 0;
270         r = vserver(VCMD_get_dlimit, xid, &data);
271         if (r>=0) {
272                 res = Py_BuildValue("(i,i,i,i,i)",
273                                     data.space_used,
274                                     data.space_total,
275                                     data.inodes_used,
276                                     data.inodes_total,
277                                     data.reserved);
278         } else {
279                 res = PyErr_SetFromErrno(PyExc_OSError);
280         }
281
282         return res;
283 }
284
285
286 static PyObject *
287 vserver_set_dlimit(PyObject *self, PyObject *args)
288 {
289         char* path;
290         unsigned xid;
291         struct vcmd_ctx_dlimit_base_v0 init;
292         struct vcmd_ctx_dlimit_v0 data;
293         int r;
294
295         memset(&data,0,sizeof(data));
296         if (!PyArg_ParseTuple(args, "siiiiii", &path,
297                               &xid,
298                               &data.space_used,
299                               &data.space_total,
300                               &data.inodes_used,
301                               &data.inodes_total,
302                               &data.reserved))
303                 return NULL;
304
305         data.name = path;
306         data.flags = 0;
307
308         memset(&init, 0, sizeof(init));
309         init.name = path;
310         init.flags = 0;
311
312         r = vserver(VCMD_rem_dlimit, xid, &init);
313         if (r<0){}
314         r = vserver(VCMD_add_dlimit, xid, &init);
315         if (r<0){}
316         r = vserver(VCMD_set_dlimit, xid, &data);
317         if (r<0){}
318         return Py_None; 
319 }
320
321 static PyMethodDef  methods[] = {
322   { "create", vserver_create, METH_VARARGS,
323     "Create a new vserver context" },
324   { "flags", vserver_flags, METH_VARARGS,
325     "Set the default flags and caps" },
326   { "enter", vserver_enter, METH_VARARGS,
327     "Enter the vserver context" },
328   { "setsched", vserver_setsched, METH_VARARGS,
329     "Change vserver scheduling attributes for given vserver context" },
330   { "setdlimit", vserver_set_dlimit, METH_VARARGS,
331     "Set disk limits for given vserver context" },
332   { "getdlimit", vserver_get_dlimit, METH_VARARGS,
333     "Get disk limits for given vserver context" },
334   { "setrlimit", vserver_set_rlimit, METH_VARARGS,
335     "Set resource limits for given resource of a vserver context" },
336   { "getrlimit", vserver_get_rlimit, METH_VARARGS,
337     "Get resource limits for given resource of a vserver context" },
338   { NULL, NULL, 0, NULL }
339 };
340
341 PyMODINIT_FUNC
342 initvserverimpl(void)
343 {
344   Py_InitModule("vserverimpl", methods);
345 }