Source

clm-python-sysadmin / sysadmin / linux / kernel_modules.py

Full commit
#!/usr/bin/env python
"""
need to run as root to actually remove modules

"""

import string, subprocess

# module # # [modules..] Live #

import re
ws_comma = re.compile(r"""[,\s]""") # match commas and any whitespace 


def compare_uses(x,y):
    xn= len(x.usedby)
    yn = len(y.usedby)
    if xn > yn:
        return 1
    if xn < yn:
        return -1
    else:
        return 0

class Module(object):
    def __init__(self, name, usedby):
        self.name=name
        self.usedby = usedby

    def __str__(self):
        return "<%s(%d)>" % (self.name, len(self.usedby) )
    
    def __repr__(self):
        return "<%s(%d)>" % (self.name, len(self.usedby) )

class KernelModules(object):
    """get currently loaded modules and manipulate them"""
    def __init__(self):
        self.moduleslist = open(r'/proc/modules').readlines()
        self.moduledict = dict()
        for mm in self.moduleslist:
            ss = ws_comma.split(mm)
            name = ss[0]
            depcandidates = [nn for nn in ss[3:] if nn and nn !='Live' and nn != '-' and nn[0:2] != '0x']
            # print [name,depcandidates]
            newmod = Module(name=name,usedby=depcandidates)
            self.moduledict[name] = newmod

            
    def make_module_dep_tree(self, module_name):
        """returns a tree structure of a module and all the modules that
        uses it"""
        try:
            mm = self.moduledict[module_name]
        except KeyError:
            print "Error! Name", module_name, "is not loaded in the kernel"
            return []
        
        if not mm.usedby:
            return [mm]
        else:
            mlist = [mm] + [self.make_module_dep_tree(x) for x in mm.usedby]
            return mlist

    def flatten_dep_tree(self, deptree, darray=[], holds={}):
        # print deptree
        for mm in deptree:
            if isinstance(mm, Module):
                if mm not in holds:
                    darray.append(mm)
                    holds[mm] = 1
            else:
                # print "not Module:", mm
                if mm:
                    self.flatten_dep_tree(mm, darray=darray, holds=holds)
        return darray
        
    def find_module_uses(self, module_name):
        uses = []
        for mname, moduleobj in self.moduledict.iteritems():
            if module_name in moduleobj.usedby:
                uses.append(moduleobj)
        return uses

    def clean_module(self, name):
        dt = self.make_module_dep_tree(name)
        flat = self.flatten_dep_tree(dt)
        flat.sort(cmp=compare_uses)
        print "flattend sorted modules:", flat
        flatnames = [ mm.name for mm in flat]
        self.modprobe_remove(flatnames)
        return flatnames

    def modprobe_remove(self, namearray):
        args = ["modprobe", "-r"] + namearray
        ret = subprocess.call(args)
            
if __name__=='__main__':            
    pass