kernel config based on lsmod output

Update (October 7th, 2011):Kernels from 2.6.32 onwards should have the option to “make localmodconfig” and “make localyesconfig”. This post describes a dirty hack to get a result similar to “make localyesconfig”. If possible, use the official way instead of my python script.

After reading about the amazing 5-seconds bootup I decided to once again compile a kernel myself. Compiling a kernel is almost trivial these days, but customizing the configuration can still be quite confusing. For example, the names of the modules in lsmod aren’t the ones you select as config options. To map them, I found some scripts in the LQWiki, but they weren’t that easily to use, and also programming in bash is just painful.

So i wrote a python variant, that takes an input config(for example your distributions config) and changes the reply to “y” for all config options if the respective module is loaded(ie. if ext3 is loaded, CONFIG_EXT3_FS=y will be set).

In almost all cases you still want to tweak the resulting config file with make menuconfig. Also keep in mind that some things don’t work that easily if compiled in, for example if firmware has to be loaded from a file, the disk should be accessible.

#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
Script to modify kernel config based on lsmod output
Copyright (C) 2008 Andreas Goelzer
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Based on a previous config and the output of lsmod, this script determines
which modules could be compiled in and generates a new config.
See http://andreas.goelzer.de/kernel-config-based-on-lsmod-output for updates
"""
import re;
from optparse import OptionParser;
from os import popen;
from sys import stderr, stdout, stdin;
parser = OptionParser(version="%prog 0.31");
parser.add_option("-i", "--infile", dest="cfgfile",
help="input config file", default=".config", metavar="FILE");
parser.add_option("-o", "--outfile", dest="outfile",
help="output config file", default="-", metavar="FILE");
parser.add_option("-l", "--logfile", dest="logfile",
help="file to log errors to", default="-", metavar="FILE");
parser.add_option("-s", "--sourcedir", dest="sourcedir",
help="kernel source tree", default=".", metavar="DIR");
#parser.add_option("-v", "--verbose",
#action="store_true", dest="verbose", default=False,
#help="print debug messages");
(options, args) = parser.parse_args();
if(options.outfile == '-'): of = stdout;
else: of = open(options.outfile, 'w');
if(options.logfile != '-'): stderr = open(options.logfile, 'w');
loadedmods=popen('lsmod | tail -n+2').readlines();
getmodname=re.compile(r"^(?P<modname>\w*)");
#prob. need to replace kernel with sth. like (kernel|ubuntu) for an ubuntu kernel source
parsepath=re.compile(r"/kernel(?P<path>/.*/)(?P<file>.*).ko")
wantin=[];
for module in loadedmods:
modname = re.search(getmodname,module).group('modname');
moduleprops=re.search(parsepath,popen('modinfo -n ' + modname).read());
if(moduleprops):
#search the makefile for the module name
try:
f=open(options.sourcedir + moduleprops.group('path') + 'Makefile' , 'r');
except IOError:
stderr.write('Could not find Makefile for ' + modname + '\n');
continue
cont=f.read();
f.close();
m=re.search(r"obj-\$\((?P<cfgname>[A-Z0-9_]*)\)\W*\+=\W*"+moduleprops.group('file')+r"\.o",cont);
if(m):wantin.append(m.group('cfgname'));
else:stderr.write('Could not determine config name for ' + modname + '\n');
else:
stderr.write('Could not parse modinfo for ' + modname + '\n');
if(options.cfgfile != '-'):
f=open(options.cfgfile, 'r');
lines=f.readlines();
f.close();
else:
lines=stdin.readlines();
confparse = re.compile(r"\W*(?P<iscomment>#?)\W*(?P<cfgname>CONFIG_[A-Z0-9_]*)\W*=?\W*(?P<answer>[nmy]?)");
for line in lines:
matches = re.search(confparse,line);
if(matches and matches.group('cfgname') in wantin):
of.write(matches.group('cfgname')+'=y\n');
else:
#if(matches and matches.group('answer') == 'm'):of.write(matches.group('cfgname')+'=n\n');
of.write(line);

To use the script, call it for example like ./customconfig.py -i /boot/config-2.6.24-21-generic -o .config if it is located in a linux kernel directory. Then modify the resulting config to suit your needs with make menuconfig, and then you can proceed to compile your kernel.

I replaced the script with an updated version. Now that missing Makefile error should not prevent the script from finishing, modules it cannot find won’t get compiled in – that means, if that isofs module is crucial for your setup, make sure to select it manually.

I’m sorry, noticed that bug a while ago, but somehow forgot to update the script here :/

Great script! I’m trying to understand the config process and wondered if you could answer some questions. I’m trying to debloat my kernel compiles on Ubuntu 8.04 Hardy and am still fairly new at this.

Something that hasn’t been clear to me is if lsmod lists all modules regardless of whether they’re compiled into the kernel or compiled as loadable modules or just lists loadable modules.

Second question: Ubuntu splits it modules ( I don’t know why ) between the kernel and the lum ( linux-ubuntu-modules ) package such that most of my modules as reported by modinfo are in:

As to the format of the two config files, i have no idea, maybe you can just cat them together or so for an input file, and then use the resulting file for both. or use /boot/config-2.6.XX-YY-generic as an input config.

note that you can also compile vanilla kernels the usual way in ubuntu, works fine (no support though, but afaik also not with self-compiled ubuntu kernels)

At least that’s what I did in Perl and I assume it should work in python too.

Another interesting thing I noticed is that there can be either a many to one or one to many relationship between modules and config options. For instance CONFIG_FRAMEBUFFER_CONSOLE causes four different modules to be built whereas the drivers/cdrom/cdrom.o object has 5 different config option which all turn it on.

I’m trying to see now if there is a way to automate lum configuration, although I have the feeling that one may have to be done by hand.

Greetings! This is my first visit to your blog! We are a collection of volunteers and starting a new project in a community in the same niche. Your blog provided us valuable information to work on. You have done a marvellous job!