Merge pull request #3 from wking/cython
authorAndy Grover <andy@groveronline.com>
Mon, 22 Oct 2012 18:10:09 +0000 (11:10 -0700)
committerAndy Grover <andy@groveronline.com>
Mon, 22 Oct 2012 18:10:09 +0000 (11:10 -0700)
Convert from a raw C extension to Cython and flesh out Module attributes.

18 files changed:
.gitignore [new file with mode: 0644]
MANIFEST.in [new file with mode: 0644]
README
README.rst [new symlink]
kmod/__init__.py [new file with mode: 0644]
kmod/_libkmod_h.pxd [new file with mode: 0644]
kmod/_util.pxd [new file with mode: 0644]
kmod/_util.pyx [new file with mode: 0644]
kmod/error.py [new file with mode: 0644]
kmod/kmod.pxd [new file with mode: 0644]
kmod/kmod.pyx [new file with mode: 0644]
kmod/list.pxd [new file with mode: 0644]
kmod/list.pyx [new file with mode: 0644]
kmod/module.pxd [new file with mode: 0644]
kmod/module.pyx [new file with mode: 0644]
kmod/version.py [new file with mode: 0644]
libkmod.c [deleted file]
setup.py

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..a8bcce1
--- /dev/null
@@ -0,0 +1,7 @@
+__pycache__
+MANIFEST
+build
+dist
+*.c
+*.pyc
+*.so
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644 (file)
index 0000000..b6f9f6f
--- /dev/null
@@ -0,0 +1,3 @@
+include COPYING
+include COPYING.LESSER
+recursive-include kmod *.pxd
diff --git a/README b/README
index 53a238aedc540ae1658721764e43fbea3cddaf7f..8ca3aae6312e2bd682db8b2ec6391ee6976f4f60 100644 (file)
--- a/README
+++ b/README
@@ -20,28 +20,21 @@ https://github.com/agrover/python-kmod
 Example (python invoked as root)
 --------------------------------
 
->>>import kmod
-
->>>km = kmod.Kmod()
-
->>>km.loaded_modules()
-
-[('nfs', 407706),
- ('nfs_acl', 12741)
-
-...
-
- ('virtio_blk', 17549)]
-
->>>km.modprobe("btrfs")
-
->>>km.rmmod("btrfs")
+::
+
+  >>> import kmod
+  >>> km = kmod.Kmod()
+  >>> km.loaded_modules()
+  [('nfs', 407706),
+   ('nfs_acl', 12741)
+   ...
+   ('virtio_blk', 17549)]
+  >>> km.modprobe("btrfs")
+  >>> km.rmmod("btrfs")
 
 Building
 --------
 
-Ensure Python and kmod headers are installed and run:
-
-python setup.py build
-
+Ensure Python, Cython, and the kmod headers are installed and run::
 
+  $ python setup.py build
diff --git a/README.rst b/README.rst
new file mode 120000 (symlink)
index 0000000..100b938
--- /dev/null
@@ -0,0 +1 @@
+README
\ No newline at end of file
diff --git a/kmod/__init__.py b/kmod/__init__.py
new file mode 100644 (file)
index 0000000..5d3f129
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#               2012 W. Trevor King
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU Lesser General Public License v.2.1.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# Author: Andy Grover <agrover redhat com>
+
+"Libkmod -- Python interface to kmod API."
+
+from .version import __version__
+from .kmod import Kmod
diff --git a/kmod/_libkmod_h.pxd b/kmod/_libkmod_h.pxd
new file mode 100644 (file)
index 0000000..a616a26
--- /dev/null
@@ -0,0 +1,108 @@
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#               2012 W. Trevor King
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU Lesser General Public License v.2.1.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+cimport libc.stdint as _stdint
+
+
+cdef extern from *:
+    ctypedef char* const_char_ptr 'const char *'
+    ctypedef char* const_char_const_ptr 'const char const *'
+    ctypedef void* const_void_ptr 'const void *'
+
+
+cdef extern from 'stdbool.h':
+    ctypedef struct bool:
+        pass
+
+
+cdef extern from 'libkmod.h':
+    # library user context - reads the config and system
+    # environment, user variables, allows custom logging
+    cdef struct kmod_ctx:
+        pass
+
+    kmod_ctx *kmod_new(
+        const_char_ptr dirname, const_char_const_ptr config_paths)
+    kmod_ctx *kmod_ref(kmod_ctx *ctx)
+    kmod_ctx *kmod_unref(kmod_ctx *ctx)
+
+    # Management of libkmod's resources
+    int kmod_load_resources(kmod_ctx *ctx)
+    void kmod_unload_resources(kmod_ctx *ctx)
+
+    # access to kmod generated lists
+    cdef struct kmod_list:
+        pass
+    ctypedef kmod_list* const_kmod_list_ptr 'const struct kmod_list *'
+    kmod_list *kmod_list_next(
+        const_kmod_list_ptr list, const_kmod_list_ptr curr)
+    kmod_list *kmod_list_prev(
+        const_kmod_list_ptr list, const_kmod_list_ptr curr)
+    kmod_list *kmod_list_last(const_kmod_list_ptr list)
+
+    # Operate on kernel modules
+    cdef struct kmod_module:
+        pass
+    ctypedef kmod_module* const_kmod_module_ptr 'const struct kmod_module *'
+    int kmod_module_new_from_name(
+        kmod_ctx *ctx, const_char_ptr name, kmod_module **mod)
+    int kmod_module_new_from_lookup(
+        kmod_ctx *ctx, const_char_ptr given_alias, kmod_list **list)
+    int kmod_module_new_from_loaded(kmod_ctx *ctx, kmod_list **list)
+
+    kmod_module *kmod_module_ref(kmod_module *mod)
+    kmod_module *kmod_module_unref(kmod_module *mod)
+    int kmod_module_unref_list(kmod_list *list)
+    kmod_module *kmod_module_get_module(kmod_list *entry)
+
+    # Flags to kmod_module_probe_insert_module
+    # codes below can be used in return value, too
+    enum: KMOD_PROBE_APPLY_BLACKLIST
+
+    #ctypedef int (*install_callback_t)(
+    #    kmod_module *m, const_char_ptr cmdline, const_void_ptr data)
+    #ctypedef void (*print_action_callback_t)(
+    #    kmod_module *m, bool install, const_char_ptr options)
+
+    int kmod_module_remove_module(
+        kmod_module *mod, unsigned int flags)
+    int kmod_module_insert_module(
+        kmod_module *mod, unsigned int flags, const_char_ptr options)
+    int kmod_module_probe_insert_module(
+        kmod_module *mod, unsigned int flags, const_char_ptr extra_options,
+        int (*run_install)(
+            kmod_module *m, const_char_ptr cmdline, void *data),
+        const_void_ptr data,
+        void (*print_action)(
+            kmod_module *m, bool install, const_char_ptr options),
+        )
+
+    const_char_ptr kmod_module_get_name(const_kmod_module_ptr mod)
+    const_char_ptr kmod_module_get_path(const_kmod_module_ptr mod)
+    const_char_ptr kmod_module_get_options(const_kmod_module_ptr mod)
+    const_char_ptr kmod_module_get_install_commands(const_kmod_module_ptr mod)
+    const_char_ptr kmod_module_get_remove_commands(const_kmod_module_ptr mod)
+
+    # Information regarding "live information" from module's state, as
+    # returned by kernel
+    int kmod_module_get_refcnt(const_kmod_module_ptr mod)
+    long kmod_module_get_size(const_kmod_module_ptr mod)
+
+    # Information retrieved from ELF headers and section
+    int kmod_module_get_info(const_kmod_module_ptr mod, kmod_list **list)
+    const_char_ptr kmod_module_info_get_key(const_kmod_list_ptr entry)
+    const_char_ptr kmod_module_info_get_value(const_kmod_list_ptr entry)
+    void kmod_module_info_free_list(kmod_list *list)
+
+    int kmod_module_get_versions(const_kmod_module_ptr mod, kmod_list **list)
+    const_char_ptr kmod_module_version_get_symbol(const_kmod_list_ptr entry)
+    _stdint.uint64_t kmod_module_version_get_crc(const_kmod_list_ptr entry)
+    void kmod_module_versions_free_list(kmod_list *list)
diff --git a/kmod/_util.pxd b/kmod/_util.pxd
new file mode 100644 (file)
index 0000000..5193f6e
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#               2012 W. Trevor King
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU Lesser General Public License v.2.1.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+cimport _libkmod_h
+
+
+cdef object char_ptr_to_str(_libkmod_h.const_char_ptr bytes)
diff --git a/kmod/_util.pyx b/kmod/_util.pyx
new file mode 100644 (file)
index 0000000..097efaf
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#               2012 W. Trevor King
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU Lesser General Public License v.2.1.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+import sys as _sys
+
+cimport _libkmod_h
+
+
+cdef object char_ptr_to_str(_libkmod_h.const_char_ptr char_ptr):
+    if char_ptr is NULL:
+        return None
+    if _sys.version_info >= (3,):  # Python 3
+        return str(char_ptr, 'ascii')
+    # Python 2
+    return unicode(char_ptr, 'ascii')
diff --git a/kmod/error.py b/kmod/error.py
new file mode 100644 (file)
index 0000000..d1848b8
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#               2012 W. Trevor King
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU Lesser General Public License v.2.1.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+class KmodError (Exception):
+    pass
diff --git a/kmod/kmod.pxd b/kmod/kmod.pxd
new file mode 100644 (file)
index 0000000..8b42b63
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#               2012 W. Trevor King
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU Lesser General Public License v.2.1.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+cimport _libkmod_h
+
+
+cdef class Kmod (object):
+    cdef _libkmod_h.kmod_ctx *_kmod_ctx
+    cdef object mod_dir
diff --git a/kmod/kmod.pyx b/kmod/kmod.pyx
new file mode 100644 (file)
index 0000000..f2cc8d3
--- /dev/null
@@ -0,0 +1,105 @@
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#               2012 W. Trevor King
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU Lesser General Public License v.2.1.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"Define the Kmod class"
+
+cimport cython as _cython
+cimport _libkmod_h
+from error import KmodError as _KmodError
+cimport module as _module
+import module as _module
+cimport list as _list
+import list as _list
+
+
+cdef class Kmod (object):
+    "Wrap a struct kmod_ctx* item"
+    def __cinit__(self):
+        self._kmod_ctx = NULL
+        self.mod_dir = None
+
+    def __dealloc__(self):
+        self._cleanup()
+
+    def __init__(self, mod_dir=None):
+        self.set_mod_dir(mod_dir=mod_dir)
+
+    def set_mod_dir(self, mod_dir=None):
+        self.mod_dir = mod_dir
+        self._setup()
+
+    def _setup(self):
+        cdef char *mod_dir = NULL
+        self._cleanup()
+        if self.mod_dir:
+            mod_dir = self.mod_dir
+        self._kmod_ctx = _libkmod_h.kmod_new(mod_dir, NULL);
+        if self._kmod_ctx is NULL:
+            raise _KmodError('Could not initialize')
+        _libkmod_h.kmod_load_resources(self._kmod_ctx)
+
+    def _cleanup(self):
+        if self._kmod_ctx is not NULL:
+            _libkmod_h.kmod_unload_resources(self._kmod_ctx);
+            self._kmod_ctx = NULL
+
+    def loaded(self):
+        "iterate through currently loaded modules"
+        cdef _list.ModList ml = _list.ModList()
+        cdef _list.ModListItem mli
+        err = _libkmod_h.kmod_module_new_from_loaded(self._kmod_ctx, &ml.list)
+        if err < 0:
+            raise _KmodError('Could not get loaded modules')
+        for item in ml:
+            mli = <_list.ModListItem> item
+            mod = _module.Module()
+            mod.from_mod_list_item(item)
+            yield mod
+
+    def lookup(self, alias_name, flags=_libkmod_h.KMOD_PROBE_APPLY_BLACKLIST):
+        "iterate through modules matching `alias_name`"
+        cdef _list.ModList ml = _list.ModList()
+        cdef _list.ModListItem mli
+        if hasattr(alias_name, 'encode'):
+            alias_name = alias_name.encode('ascii')
+        err = _libkmod_h.kmod_module_new_from_lookup(
+            self._kmod_ctx, alias_name, &ml.list)
+        if err < 0:
+            raise _KmodError('Could not modprobe')
+        for item in ml:
+            mli = <_list.ModListItem> item
+            mod = _module.Module()
+            mod.from_mod_list_item(item)
+            yield mod
+
+    @_cython.always_allow_keywords(True)
+    def module_from_name(self, name):
+        cdef _module.Module mod = _module.Module()
+        if hasattr(name, 'encode'):
+            name = name.encode('ascii')
+        err = _libkmod_h.kmod_module_new_from_name(
+            self._kmod_ctx, name, &mod.module)
+        if err < 0:
+            raise _KmodError('Could not get module')
+        return mod
+
+    def list(self):
+        "iterate through currently loaded modules and sizes"
+        for mod in self.loaded():
+            yield (mod.name, mod.size)
+
+    def modprobe(self, alias_name, *args, **kwargs):
+        for mod in self.lookup(alias_name=alias_name):
+            mod.insert(*args, **kwargs)
+
+    def rmmod(self, module_name, *args, **kwargs):
+       mod = self.module_from_name(name=module_name)
+       mod.remove(*args, **kwargs)
diff --git a/kmod/list.pxd b/kmod/list.pxd
new file mode 100644 (file)
index 0000000..b51a2fa
--- /dev/null
@@ -0,0 +1,20 @@
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#               2012 W. Trevor King
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU Lesser General Public License v.2.1.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+cimport _libkmod_h
+
+
+cdef class ModListItem (object):
+    cdef _libkmod_h.kmod_list *list
+
+
+cdef class ModList (ModListItem):
+    cdef _libkmod_h.kmod_list *_next
diff --git a/kmod/list.pyx b/kmod/list.pyx
new file mode 100644 (file)
index 0000000..9d9c959
--- /dev/null
@@ -0,0 +1,40 @@
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#               2012 W. Trevor King
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU Lesser General Public License v.2.1.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+cimport _libkmod_h
+
+
+cdef class ModListItem (object):
+    "Wrap a struct kmod_list* list item"
+    def __cinit__(self):
+        self.list = NULL
+
+
+cdef class ModList (ModListItem):
+    "Wrap a struct kmod_list* list with iteration"
+    def __cinit__(self):
+        self._next = NULL
+
+    def __dealloc__(self):
+        if self.list is not NULL:
+            _libkmod_h.kmod_module_unref_list(self.list)
+
+    def __iter__(self):
+        self._next = self.list
+        return self
+
+    def __next__(self):
+        if self._next is NULL:
+            raise StopIteration()
+        mli = ModListItem()
+        mli.list = self._next
+        self._next = _libkmod_h.kmod_list_next(self.list, self._next)
+        return mli
diff --git a/kmod/module.pxd b/kmod/module.pxd
new file mode 100644 (file)
index 0000000..4e24f35
--- /dev/null
@@ -0,0 +1,19 @@
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#               2012 W. Trevor King
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU Lesser General Public License v.2.1.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+cimport _libkmod_h
+cimport list as _list
+
+
+cdef class Module (object):
+    cdef _libkmod_h.kmod_module *module
+
+    cpdef from_mod_list_item(self, _list.ModListItem item)
diff --git a/kmod/module.pyx b/kmod/module.pyx
new file mode 100644 (file)
index 0000000..ed51bfa
--- /dev/null
@@ -0,0 +1,139 @@
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#               2012 W. Trevor King
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU Lesser General Public License v.2.1.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+import collections as _collections
+
+cimport libc.errno as _errno
+
+cimport _libkmod_h
+from error import KmodError as _KmodError
+cimport list as _list
+import list as _list
+cimport _util
+import _util
+
+
+cdef class Module (object):
+    "Wrap a struct kmod_module* item"
+    def __cinit__(self):
+        self.module = NULL
+
+    def __dealloc__(self):
+        self._cleanup()
+
+    def _cleanup(self):
+        if self.module is not NULL:
+            _libkmod_h.kmod_module_unref(self.module)
+            self.module = NULL
+
+    cpdef from_mod_list_item(self, _list.ModListItem item):
+        self._cleanup()
+        self.module = _libkmod_h.kmod_module_get_module(item.list)
+
+    def _name_get(self):
+        return _util.char_ptr_to_str(
+            _libkmod_h.kmod_module_get_name(self.module))
+    name = property(fget=_name_get)
+
+    def _path_get(self):
+        return _util.char_ptr_to_str(
+            _libkmod_h.kmod_module_get_path(self.module))
+    path = property(fget=_path_get)
+
+    def _options_get(self):
+        return _util.char_ptr_to_str(
+            _libkmod_h.kmod_module_get_options(self.module))
+    options = property(fget=_options_get)
+
+    def _install_commands_get(self):
+        return _util.char_ptr_to_str(
+            _libkmod_h.kmod_module_get_install_commands(self.module))
+    install_commands = property(fget=_install_commands_get)
+
+    def _remove_commands_get(self):
+        return _util.char_ptr_to_str(
+            _libkmod_h.kmod_module_get_remove_commands(self.module))
+    remove_commands = property(fget=_remove_commands_get)
+
+    def _refcnt_get(self):
+        return _libkmod_h.kmod_module_get_refcnt(self.module)
+    refcnt = property(fget=_refcnt_get)
+
+    def _size_get(self):
+        return _libkmod_h.kmod_module_get_size(self.module)
+    size = property(fget=_size_get)
+
+    def _info_get(self):
+        cdef _list.ModList ml = _list.ModList()
+        cdef _list.ModListItem mli
+        err = _libkmod_h.kmod_module_get_info(self.module, &ml.list)
+        if err < 0:
+            raise _KmodError('Could not get info')
+        info = _collections.OrderedDict()
+        try:
+            for item in ml:
+                mli = <_list.ModListItem> item
+                key = _util.char_ptr_to_str(
+                    _libkmod_h.kmod_module_info_get_key(mli.list))
+                value = _util.char_ptr_to_str(
+                    _libkmod_h.kmod_module_info_get_value(mli.list))
+                info[key] = value
+        finally:
+            _libkmod_h.kmod_module_info_free_list(ml.list)
+            ml.list = NULL
+        return info
+    info = property(fget=_info_get)
+
+    def _versions_get(self):
+        cdef _list.ModList ml = _list.ModList()
+        cdef _list.ModListItem mli
+        err = _libkmod_h.kmod_module_get_versions(self.module, &ml.list)
+        if err < 0:
+            raise _KmodError('Could not get versions')
+        try:
+            for item in ml:
+                mli = <_list.ModListItem> item
+                symbol = _util.char_ptr_to_str(
+                    _libkmod_h.kmod_module_version_get_symbol(mli.list))
+                crc = _libkmod_h.kmod_module_version_get_crc(mli.list)
+                yield {'symbol': symbol, 'crc': crc}
+        finally:
+            _libkmod_h.kmod_module_versions_free_list(ml.list)
+            ml.list = NULL
+    versions = property(fget=_versions_get)
+
+    def insert(self, flags=0, extra_options=None, install_callback=None,
+               data=None, print_action_callback=None):
+        cdef char *opt = NULL
+        #cdef _libkmod_h.install_callback_t install = NULL
+        cdef int (*install)(
+            _libkmod_h.kmod_module *, _libkmod_h.const_char_ptr, void *)
+        install = NULL
+        cdef void *d = NULL
+        #cdef _libkmod_h.print_action_callback_t print_action = NULL
+        cdef void (*print_action)(
+            _libkmod_h.kmod_module *, _libkmod_h.bool,
+            _libkmod_h.const_char_ptr)
+        print_action = NULL
+        if extra_options:
+            opt = extra_options
+        # TODO: convert callbacks and data from Python object to C types
+        err = _libkmod_h.kmod_module_probe_insert_module(
+            self.module, flags, opt, install, d, print_action)
+        if err == -_errno.EEXIST:
+            raise _KmodError('Module already loaded')
+        elif err < 0:
+            raise _KmodError('Could not load module')
+
+    def remove(self, flags=0):
+        err = _libkmod_h.kmod_module_remove_module(self.module, flags)
+        if err < 0:
+            raise _KmodError('Could not remove module')
diff --git a/kmod/version.py b/kmod/version.py
new file mode 100644 (file)
index 0000000..4b74d6c
--- /dev/null
@@ -0,0 +1,12 @@
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#               2012 W. Trevor King
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU Lesser General Public License v.2.1.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+__version__ = '0.1'
diff --git a/libkmod.c b/libkmod.c
deleted file mode 100644 (file)
index 82f0de8..0000000
--- a/libkmod.c
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * Libkmod -- Python interface to kmod API.
- *
- * Copyright (C) 2012 Red Hat, Inc. All rights reserved.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU Lesser General Public License v.2.1.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * Author: Andy Grover <agrover redhat com>
- *
- */
-
-#include <Python.h>
-#include <libkmod.h>
-
-typedef struct {
-    PyObject_HEAD
-    struct kmod_ctx *ctx;
-} kmodobject;
-
-static PyTypeObject KmodObjType;
-
-static PyObject *KmodError;
-
-/* ----------------------------------------------------------------------
- * kmod toplevel module methods
- */
-static PyObject *
-kmod_library_get_version(PyObject *self, PyObject *unused_args)
-{
-    return Py_BuildValue("s", "0.1");
-}
-
-/* ----------------------------------------------------------------------
- * Kmod object initialization/deallocation
- */
-static int
-kmod_obj_init(PyObject *self, PyObject *args, PyObject *kwds)
-{
-    kmodobject *kmod = (kmodobject *)self;
-    char *mod_dir = NULL;
-
-    if (!PyArg_ParseTuple(args, "|s", &mod_dir))
-       return -1;
-
-    /* init can be called multiple times */
-    if (kmod->ctx) {
-        kmod_unload_resources(kmod->ctx);
-        kmod_unref(kmod->ctx);
-    }
-
-    kmod->ctx = kmod_new(mod_dir, NULL);
-    if (!kmod->ctx) {
-        PyErr_SetString(KmodError, "Could not initialize");
-        return -1;
-    }
-
-    kmod_load_resources(kmod->ctx);
-
-    return 0;
-}
-
-static void
-kmod_obj_dealloc(PyObject *self)
-{
-    kmodobject *kmod = (kmodobject *)self;
-
-    kmod_unload_resources(kmod->ctx);
-
-    /* if already closed, don't reclose it */
-    if (kmod->ctx != NULL){
-            kmod_unref(kmod->ctx);
-    }
-    //self->ob_type->tp_free((PyObject*)self);
-    PyObject_Del(self);
-}
-
-/*
- * list currently loaded modules and sizes
- */
-static PyObject *
-kmod_obj_loaded_modules(PyObject *self, PyObject *unused_args)
-{
-    kmodobject *kmod = (kmodobject *)self;
-    struct kmod_list *list, *itr;
-    int err;
-
-    err = kmod_module_new_from_loaded(kmod->ctx, &list);
-    if (err < 0) {
-        PyErr_SetString(KmodError, "Could not get loaded modules");
-        return NULL;
-    }
-
-    PyObject *pylist = PyList_New(0);
-    if (!pylist) {
-        kmod_module_unref_list(list);
-        return PyErr_NoMemory();
-    }
-
-    /* refcountapallooza. */
-    kmod_list_foreach(itr, list) {
-        struct kmod_module *mod = kmod_module_get_module(itr);
-        const char *name = kmod_module_get_name(mod);
-        long size = kmod_module_get_size(mod);
-
-        PyObject *entry = Py_BuildValue("(sl)", name, size);
-        if (!entry) {
-            Py_DECREF(pylist);
-            kmod_module_unref(mod);
-            kmod_module_unref_list(list);
-            return NULL;
-        }
-
-        if (PyList_Append(pylist, entry) == -1) {
-            Py_DECREF(entry);
-            Py_DECREF(pylist);
-            kmod_module_unref(mod);
-            kmod_module_unref_list(list);
-            return NULL;
-        }
-
-        Py_DECREF(entry);
-        kmod_module_unref(mod);
-    }
-    kmod_module_unref_list(list);
-
-    return pylist;
-}
-
-static PyObject *
-kmod_obj_modprobe(PyObject *self, PyObject *args)
-{
-    kmodobject *kmod = (kmodobject *)self;
-    struct kmod_list *list = NULL, *itr;
-    struct kmod_module *mod;
-    char *alias_name;
-    unsigned int flags = KMOD_PROBE_APPLY_BLACKLIST;
-    int err;
-
-    if (!PyArg_ParseTuple(args, "s", &alias_name))
-       return NULL;
-
-    err = kmod_module_new_from_lookup(kmod->ctx, alias_name, &list);
-    if (err < 0) {
-        PyErr_SetString(KmodError, "Could not modprobe");
-        return NULL;
-    }
-
-    kmod_list_foreach(itr, list) {
-        mod = kmod_module_get_module(itr);
-
-        err = kmod_module_probe_insert_module(mod, flags,
-            NULL, NULL, NULL, NULL);
-
-        if (err < 0) {
-            if (err == -EEXIST) {
-                PyErr_SetString(KmodError, "Module already loaded");
-                    goto err;
-            } else {
-                PyErr_SetString(KmodError, "Could not load module");
-                    goto err;
-            }
-        }
-
-        kmod_module_unref(mod);
-    }
-    kmod_module_unref_list(list);
-
-    Py_INCREF(Py_None);
-    return Py_None;
-
-err:
-    kmod_module_unref(mod);
-    kmod_module_unref_list(list);
-    return NULL;
-}
-
-static PyObject *
-kmod_obj_rmmod(PyObject *self, PyObject *args)
-{
-    kmodobject *kmod = (kmodobject *)self;
-    struct kmod_module *mod;
-    char *module_name;
-    int err;
-
-    if (!PyArg_ParseTuple(args, "s", &module_name))
-        return NULL;
-
-    err = kmod_module_new_from_name(kmod->ctx, module_name, &mod);
-    if (err < 0) {
-        PyErr_SetString(KmodError, "Could  get module");
-        return NULL;
-    }
-
-    err = kmod_module_remove_module(mod, 0);
-    if (err < 0) {
-        PyErr_SetString(KmodError, "Could not remove module");
-        kmod_module_unref(mod);
-        return NULL;
-    }
-    kmod_module_unref(mod);
-
-    Py_INCREF(Py_None);
-    return Py_None;
-}
-
-/* ----------------------------------------------------------------------
- * Method tables and other bureaucracy
- */
-
-static PyMethodDef kmod_lib_methods[] = {
-    {"getVersion", kmod_library_get_version, METH_NOARGS },
-    {NULL, NULL}           /* sentinel */
-};
-
-static PyMethodDef kmod_obj_methods[] = {
-    {"loaded_modules", kmod_obj_loaded_modules, METH_NOARGS,
-    "List loaded kernel modules, and their sizes"},
-    {"modprobe", kmod_obj_modprobe, METH_VARARGS,
-    "Load a kernel module"},
-    {"rmmod", kmod_obj_rmmod, METH_VARARGS,
-    "Unload a kernel module"},
-    {NULL, NULL}           /* sentinel */
-};
-
-
-static PyTypeObject KmodObjType = {
-    PyObject_HEAD_INIT(NULL)
-    .tp_name = "kmod.Kmod",
-    .tp_basicsize = sizeof(kmodobject),
-    .tp_new = PyType_GenericNew,
-    .tp_init = kmod_obj_init,
-    .tp_dealloc = kmod_obj_dealloc,
-    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
-    .tp_doc = "kmod.Kmod object",
-    .tp_methods = kmod_obj_methods,
-};
-
-#ifndef PyMODINIT_FUNC    /* declarations for DLL import/export */
-#define PyMODINIT_FUNC void
-#endif
-PyMODINIT_FUNC
-initkmod(void)
-{
-    PyObject *m;
-
-    if (PyType_Ready(&KmodObjType) < 0)
-        return;
-
-    m = Py_InitModule3("kmod", kmod_lib_methods, "kmod module");
-    if (!m)
-        return;
-
-    Py_INCREF(&KmodObjType);
-    PyModule_AddObject(m, "Kmod", (PyObject *)&KmodObjType);
-
-    KmodError = PyErr_NewException("kmod.KmodError",
-                                   NULL, NULL);
-    if (KmodError) {
-        /* Each call to PyModule_AddObject decrefs it; compensate: */
-        Py_INCREF(KmodError);
-        PyModule_AddObject(m, "KmodError", KmodError);
-    }
-}
index 09c6675daeee9fa2823bec6c92ef31e8b85d92e3..bbef37a4b025d1fe09ba96ee6d5645fddfe184f0 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -1,10 +1,49 @@
-from distutils.core import setup, Extension
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#               2012 W. Trevor King
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU Lesser General Public License v.2.1.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
-libkmod = Extension('kmod',
-                    sources = ['libkmod.c'],
-                    libraries= ['kmod'])
+from distutils.core import setup
+from distutils.extension import Extension as _Extension
+import os as _os
+import sys as _sys
 
-setup (name = 'kmod',
-       version = '0.1',
-       description = 'Python binding for kmod',
-       ext_modules = [libkmod])
+from Cython.Distutils import build_ext as _build_ext
+
+
+package_name = 'kmod'
+
+# read version from local kmod/version.py without pulling in
+# kmod/__init__.py
+_sys.path.insert(0, package_name)
+from version import __version__
+
+
+_this_dir = _os.path.dirname(__file__)
+
+ext_modules = []
+for filename in sorted(_os.listdir(package_name)):
+    basename,extension = _os.path.splitext(filename)
+    if extension == '.pyx':
+        ext_modules.append(
+            _Extension(
+                '{}.{}'.format(package_name, basename),
+                [_os.path.join(package_name, filename)],
+                libraries=['kmod'],
+                ))
+
+setup(
+    name=package_name,
+    version=__version__,
+    description='Python binding for kmod',
+    packages=[package_name],
+    provides=[package_name],
+    cmdclass = {'build_ext': _build_ext},
+    ext_modules=ext_modules,
+    )