update FSF address in COPYING and COPYING.LESSER
[python-kmod.git] / libkmod.c
1 /*
2  * Libkmod -- Python interface to kmod API.
3  *
4  * Copyright (C) 2012 Red Hat, Inc. All rights reserved.
5  *
6  * This copyrighted material is made available to anyone wishing to use,
7  * modify, copy, or redistribute it subject to the terms and conditions
8  * of the GNU Lesser General Public License v.2.1.
9  *
10  * You should have received a copy of the GNU Lesser General Public License
11  * along with this program; if not, write to the Free Software Foundation,
12  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
13  *
14  * Author: Andy Grover <agrover redhat com>
15  *
16  */
17
18 #include <Python.h>
19 #include <libkmod.h>
20
21 typedef struct {
22     PyObject_HEAD
23     struct kmod_ctx *ctx;
24 } kmodobject;
25
26 static PyTypeObject KmodObjType;
27
28 static PyObject *KmodError;
29
30 /* ----------------------------------------------------------------------
31  * kmod toplevel module methods
32  */
33 static PyObject *
34 kmod_library_get_version(PyObject *self, PyObject *unused_args)
35 {
36     return Py_BuildValue("s", "0.1");
37 }
38
39 /* ----------------------------------------------------------------------
40  * Kmod object initialization/deallocation
41  */
42 static int
43 kmod_obj_init(PyObject *self, PyObject *args, PyObject *kwds)
44 {
45     kmodobject *kmod = (kmodobject *)self;
46     char *mod_dir = NULL;
47
48     if (!PyArg_ParseTuple(args, "|s", &mod_dir))
49        return -1;
50
51     /* init can be called multiple times */
52     if (kmod->ctx) {
53         kmod_unload_resources(kmod->ctx);
54         kmod_unref(kmod->ctx);
55     }
56
57     kmod->ctx = kmod_new(mod_dir, NULL);
58     if (!kmod->ctx) {
59         PyErr_SetString(KmodError, "Could not initialize");
60         return -1;
61     }
62
63     kmod_load_resources(kmod->ctx);
64
65     return 0;
66 }
67
68 static void
69 kmod_obj_dealloc(PyObject *self)
70 {
71     kmodobject *kmod = (kmodobject *)self;
72
73     kmod_unload_resources(kmod->ctx);
74
75     /* if already closed, don't reclose it */
76     if (kmod->ctx != NULL){
77             kmod_unref(kmod->ctx);
78     }
79     //self->ob_type->tp_free((PyObject*)self);
80     PyObject_Del(self);
81 }
82
83 /*
84  * list currently loaded modules and sizes
85  */
86 static PyObject *
87 kmod_obj_loaded_modules(PyObject *self, PyObject *unused_args)
88 {
89     kmodobject *kmod = (kmodobject *)self;
90     struct kmod_list *list, *itr;
91     int err;
92
93     err = kmod_module_new_from_loaded(kmod->ctx, &list);
94     if (err < 0) {
95         PyErr_SetString(KmodError, "Could not get loaded modules");
96         return NULL;
97     }
98
99     PyObject *pylist = PyList_New(0);
100     if (!pylist) {
101         kmod_module_unref_list(list);
102         return PyErr_NoMemory();
103     }
104
105     /* refcountapallooza. */
106     kmod_list_foreach(itr, list) {
107         struct kmod_module *mod = kmod_module_get_module(itr);
108         const char *name = kmod_module_get_name(mod);
109         long size = kmod_module_get_size(mod);
110
111         PyObject *entry = Py_BuildValue("(sl)", name, size);
112         if (!entry) {
113             Py_DECREF(pylist);
114             kmod_module_unref(mod);
115             kmod_module_unref_list(list);
116             return NULL;
117         }
118
119         if (PyList_Append(pylist, entry) == -1) {
120             Py_DECREF(entry);
121             Py_DECREF(pylist);
122             kmod_module_unref(mod);
123             kmod_module_unref_list(list);
124             return NULL;
125         }
126
127         Py_DECREF(entry);
128         kmod_module_unref(mod);
129     }
130     kmod_module_unref_list(list);
131
132     return pylist;
133 }
134
135 static PyObject *
136 kmod_obj_modprobe(PyObject *self, PyObject *args)
137 {
138     kmodobject *kmod = (kmodobject *)self;
139     struct kmod_list *list = NULL, *itr;
140     struct kmod_module *mod;
141     char *alias_name;
142     unsigned int flags = KMOD_PROBE_APPLY_BLACKLIST;
143     int err;
144
145     if (!PyArg_ParseTuple(args, "s", &alias_name))
146        return NULL;
147
148     err = kmod_module_new_from_lookup(kmod->ctx, alias_name, &list);
149     if (err < 0) {
150         PyErr_SetString(KmodError, "Could not modprobe");
151         return NULL;
152     }
153
154     kmod_list_foreach(itr, list) {
155         mod = kmod_module_get_module(itr);
156
157         err = kmod_module_probe_insert_module(mod, flags,
158             NULL, NULL, NULL, NULL);
159
160         if (err < 0) {
161             if (err == -EEXIST) {
162                 PyErr_SetString(KmodError, "Module already loaded");
163                     goto err;
164             } else {
165                 PyErr_SetString(KmodError, "Could not load module");
166                     goto err;
167             }
168         }
169
170         kmod_module_unref(mod);
171     }
172     kmod_module_unref_list(list);
173
174     Py_INCREF(Py_None);
175     return Py_None;
176
177 err:
178     kmod_module_unref(mod);
179     kmod_module_unref_list(list);
180     return NULL;
181 }
182
183 static PyObject *
184 kmod_obj_rmmod(PyObject *self, PyObject *args)
185 {
186     kmodobject *kmod = (kmodobject *)self;
187     struct kmod_module *mod;
188     char *module_name;
189     int err;
190
191     if (!PyArg_ParseTuple(args, "s", &module_name))
192         return NULL;
193
194     err = kmod_module_new_from_name(kmod->ctx, module_name, &mod);
195     if (err < 0) {
196         PyErr_SetString(KmodError, "Could  get module");
197         return NULL;
198     }
199
200     err = kmod_module_remove_module(mod, 0);
201     if (err < 0) {
202         PyErr_SetString(KmodError, "Could not remove module");
203         kmod_module_unref(mod);
204         return NULL;
205     }
206     kmod_module_unref(mod);
207
208     Py_INCREF(Py_None);
209     return Py_None;
210 }
211
212 /* ----------------------------------------------------------------------
213  * Method tables and other bureaucracy
214  */
215
216 static PyMethodDef kmod_lib_methods[] = {
217     {"getVersion", kmod_library_get_version, METH_NOARGS },
218     {NULL, NULL}           /* sentinel */
219 };
220
221 static PyMethodDef kmod_obj_methods[] = {
222     {"loaded_modules", kmod_obj_loaded_modules, METH_NOARGS,
223     "List loaded kernel modules, and their sizes"},
224     {"modprobe", kmod_obj_modprobe, METH_VARARGS,
225     "Load a kernel module"},
226     {"rmmod", kmod_obj_rmmod, METH_VARARGS,
227     "Unload a kernel module"},
228     {NULL, NULL}           /* sentinel */
229 };
230
231
232 static PyTypeObject KmodObjType = {
233     PyObject_HEAD_INIT(NULL)
234     .tp_name = "kmod.Kmod",
235     .tp_basicsize = sizeof(kmodobject),
236     .tp_new = PyType_GenericNew,
237     .tp_init = kmod_obj_init,
238     .tp_dealloc = kmod_obj_dealloc,
239     .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
240     .tp_doc = "kmod.Kmod object",
241     .tp_methods = kmod_obj_methods,
242 };
243
244 #ifndef PyMODINIT_FUNC    /* declarations for DLL import/export */
245 #define PyMODINIT_FUNC void
246 #endif
247 PyMODINIT_FUNC
248 initkmod(void)
249 {
250     PyObject *m;
251
252     if (PyType_Ready(&KmodObjType) < 0)
253         return;
254
255     m = Py_InitModule3("kmod", kmod_lib_methods, "kmod module");
256     if (!m)
257         return;
258
259     Py_INCREF(&KmodObjType);
260     PyModule_AddObject(m, "Kmod", (PyObject *)&KmodObjType);
261
262     KmodError = PyErr_NewException("kmod.KmodError",
263                                    NULL, NULL);
264     if (KmodError) {
265         /* Each call to PyModule_AddObject decrefs it; compensate: */
266         Py_INCREF(KmodError);
267         PyModule_AddObject(m, "KmodError", KmodError);
268     }
269 }