Make disk limit handling more NM-friendly, get rid of dependency on
[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 "pathconfig.h"
51 #include "vserver.h"
52 #include "vserver-internal.h"
53 #include "sched_cmd.h"
54 #include "virtual.h"
55
56 #define MEF_DEBUG 1
57 /*
58  * context create
59  */
60 static PyObject *
61 vserver_chcontext(PyObject *self, PyObject *args)
62 {
63         xid_t xid, ctx;
64         struct vc_ctx_caps caps;
65         struct vc_ctx_flags flags;
66         struct vc_vx_info vc;
67         unsigned long long v;
68
69         v = VC_VXF_STATE_SETUP;
70         if (!PyArg_ParseTuple(args, "I|K", &ctx, &v))
71                 return NULL;
72
73         caps.ccaps = ~vc_get_insecureccaps();
74         caps.cmask = ~0ull;
75         caps.bcaps = ~vc_get_insecurebcaps();
76         caps.bmask = ~0ull;
77
78         xid = VC_NOCTX;
79         if (vc_get_vx_info(ctx,&vc) != 0) {
80                 xid = vc_ctx_create(ctx);
81                 if (xid == VC_NOCTX && errno != EEXIST)
82                         return PyErr_SetFromErrno(PyExc_OSError);
83         }
84
85         flags.mask = flags.flagword = v;
86         if (vc_set_cflags(ctx, &flags) == -1)
87                 return PyErr_SetFromErrno(PyExc_OSError);
88
89         if (xid == VC_NOCTX && vc_ctx_migrate(ctx) == -1)
90                 return PyErr_SetFromErrno(PyExc_OSError);
91
92 #ifdef MEF_DEBUG
93         printf("vserver_create xid = %d(%d)\n",xid,ctx);
94 #endif
95         return Py_None;
96 }
97
98 static PyObject *
99 vserver_set_rlimit(PyObject *self, PyObject *args) {
100         struct vc_rlimit limits;
101         xid_t xid;
102         int resource;
103         PyObject *ret;
104
105         limits.min = VC_LIM_KEEP;
106         limits.soft = VC_LIM_KEEP;
107         limits.hard = VC_LIM_KEEP;
108
109         if (!PyArg_ParseTuple(args, "IiL", &xid, &resource, &limits.hard))
110                 return NULL;
111
112         ret = Py_None;
113         if (vc_set_rlimit(xid, resource, &limits)) 
114                 ret = PyErr_SetFromErrno(PyExc_OSError);
115         else if (vc_get_rlimit(xid, resource, &limits)==-1)
116                 ret = PyErr_SetFromErrno(PyExc_OSError);
117         else
118                 ret = Py_BuildValue("L",limits.hard);
119
120         return ret;
121 }
122
123 static PyObject *
124 vserver_get_rlimit(PyObject *self, PyObject *args) {
125         struct vc_rlimit limits;
126         xid_t xid;
127         int resource;
128         PyObject *ret;
129
130         limits.min = VC_LIM_KEEP;
131         limits.soft = VC_LIM_KEEP;
132         limits.hard = VC_LIM_KEEP;
133
134         if (!PyArg_ParseTuple(args, "Ii", &xid, &resource))
135                 return NULL;
136
137         ret = Py_None;
138         if (vc_get_rlimit(xid, resource, &limits)==-1)
139                 ret = PyErr_SetFromErrno(PyExc_OSError);
140         else
141                 ret = Py_BuildValue("L",limits.hard);
142
143         return ret;
144 }
145
146 /*
147  * setsched
148  */
149 static PyObject *
150 vserver_setsched(PyObject *self, PyObject *args)
151 {
152   xid_t  xid;
153   struct vc_set_sched sched;
154   struct vc_ctx_flags flags;
155   unsigned cpuguaranteed = 0;
156
157   sched.set_mask = (VC_VXSM_FILL_RATE | 
158                     VC_VXSM_INTERVAL | 
159                     VC_VXSM_TOKENS_MIN | 
160                     VC_VXSM_TOKENS_MAX);
161
162   if (!PyArg_ParseTuple(args, "I|I|I|I|I|I|I", &xid, 
163                         &sched.fill_rate,
164                         &sched.interval,
165                         &sched.tokens,
166                         &sched.tokens_min,
167                         &sched.tokens_max,
168                         &cpuguaranteed))
169     return NULL;
170
171   flags.flagword = VC_VXF_SCHED_HARD;
172   flags.mask |= VC_VXF_SCHED_HARD;
173 #define VC_VXF_SCHED_SHARE       0x00000800ull
174   if (cpuguaranteed==0) {
175           flags.flagword |= VC_VXF_SCHED_SHARE;
176           flags.mask |= VC_VXF_SCHED_SHARE;
177   }
178
179   if (vc_set_cflags(xid, &flags) == -1)
180           return PyErr_SetFromErrno(PyExc_OSError);
181
182   if (vc_set_sched(xid, &sched) == -1)
183           return PyErr_SetFromErrno(PyExc_OSError);
184
185   return Py_None;
186 }
187
188 /*
189  * setsched
190  */
191
192 static PyObject *
193 vserver_get_dlimit(PyObject *self, PyObject *args)
194 {
195         PyObject *res;
196         char* path;
197         unsigned xid;
198         struct vcmd_ctx_dlimit_v0 data;
199         int r;
200
201         if (!PyArg_ParseTuple(args, "si", &path,&xid))
202                 return NULL;
203
204         memset(&data, 0, sizeof(data));
205         data.name = path;
206         data.flags = 0;
207         r = vserver(VCMD_get_dlimit, xid, &data);
208         if (r>=0) {
209                 res = Py_BuildValue("(i,i,i,i,i)",
210                                     data.space_used,
211                                     data.space_total,
212                                     data.inodes_used,
213                                     data.inodes_total,
214                                     data.reserved);
215         } else {
216                 res = PyErr_SetFromErrno(PyExc_OSError);
217         }
218
219         return res;
220 }
221
222
223 static PyObject *
224 vserver_set_dlimit(PyObject *self, PyObject *args)
225 {
226         char* path;
227         unsigned xid;
228         struct vcmd_ctx_dlimit_base_v0 init;
229         struct vcmd_ctx_dlimit_v0 data;
230
231         memset(&data,0,sizeof(data));
232         if (!PyArg_ParseTuple(args, "siiiiii", &path,
233                               &xid,
234                               &data.space_used,
235                               &data.space_total,
236                               &data.inodes_used,
237                               &data.inodes_total,
238                               &data.reserved))
239                 return NULL;
240
241         data.name = path;
242         data.flags = 0;
243
244         memset(&init, 0, sizeof(init));
245         init.name = path;
246         init.flags = 0;
247
248         if ((vserver(VCMD_add_dlimit, xid, &init) && errno != EEXIST) ||
249             vserver(VCMD_set_dlimit, xid, &data))
250           return PyErr_SetFromErrno(PyExc_OSError);
251
252         return Py_None; 
253 }
254
255 static PyMethodDef  methods[] = {
256   { "chcontext", vserver_chcontext, METH_VARARGS,
257     "chcontext to vserver with provided flags" },
258   { "setsched", vserver_setsched, METH_VARARGS,
259     "Change vserver scheduling attributes for given vserver context" },
260   { "setdlimit", vserver_set_dlimit, METH_VARARGS,
261     "Set disk limits for given vserver context" },
262   { "getdlimit", vserver_get_dlimit, METH_VARARGS,
263     "Get disk limits for given vserver context" },
264   { "setrlimit", vserver_set_rlimit, METH_VARARGS,
265     "Set resource limits for given resource of a vserver context" },
266   { "getrlimit", vserver_get_rlimit, METH_VARARGS,
267     "Get resource limits for given resource of a vserver context" },
268   { NULL, NULL, 0, NULL }
269 };
270
271 PyMODINIT_FUNC
272 initvserverimpl(void)
273 {
274   PyObject  *mod;
275
276   mod = Py_InitModule("vserverimpl", methods);
277
278   /* export the set of 'safe' capabilities */
279   PyModule_AddIntConstant(mod, "CAP_SAFE", ~vc_get_insecurebcaps());
280
281   /* export the default vserver directory */
282   PyModule_AddStringConstant(mod, "VSERVER_BASEDIR", DEFAULT_VSERVERDIR);
283
284   /* export a constant to indicate unchanged disk quota values */
285   PyModule_AddIntConstant(mod, "DLIMIT_KEEP", (int)CDLIM_KEEP);
286 }