automatically recompile kernel modules after kernel update

I don’t know how many times you have to do something before you decide that enough is enough. I wrote a service to autorecompile kernel modules. It checks in a config file (/etc/modautocompile.conf) which modules to autorecompile and if they are not found in the /lib/modules directory of the current kernel runs the command associated with the module to recompile it. I bet such a service already exists hundred times under different names … but it’s going to save me time and probably explanations (as the ATI fglrx module should be the first of your list!)
Here’s a sample config file (adding modules to that list and comment them out would be a good idea).

# kernel modules to autocompile after kernel update
# name              command
vboxdrv             service vboxdrv setup
fglrx               /usr/bin/fglrx-kernel-build.sh

And here’s the script:

#! /bin/sh
# Linux kernel module init script

#: Title       : modautocompile
#: Date Created: Sat Oct 16 06:00:29 PDT 2010
#: Last Edit   : Sat Oct 16 06:00:29 PDT 2010
#: Author      : please_try_again
#: Version     : 1.0
#: Description : Automatically recompile modules after kernel update


# chkconfig: 35 30 70
# description: recompile modules
#
### BEGIN INIT INFO
# Provides:       modautocompile 
# Required-Start: $syslog
# Required-Stop:
# Default-Start:  2 3 4 5
# Default-Stop:   0 1 6
# Short-Description: recomppile kernel modules
### END INIT INFO

# Define the modules you want to autorecompile in the file /etc/modautocompile.conf
# or in the file specified by the variable CFG below
CFG=/etc/modautocompile.conf

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# /etc/modautocompile.conf example 
# kernel modules to autocompile after kernel update
# module	      command
# vboxdrv         service vboxdrv setup
# fglrx           /usr/bin/fglrx-kernel-build.sh
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#
PATH=/sbin:/bin:/usr/sbin:/usr/bin:$PATH

start()
{

# check if $CFG exist
if [ ! -e $CFG ] ; then
	echo $CFG not found
	exit 1
fi

# parse /etc/modautocompile.conf
eval `awk 'BEGIN { I=-1 } ; !/^#/ { if ( NF ) { MOD=$1 ; I++ ; $1="" ; sub(/ /, "", $0) ;  printf "MOD[%i]=%s; CMD[%i]=\"%s\";",  I, MOD, I, $0 } }' $CFG`

# exit if no modules defined in /etc/modautocompile.conf

if [ ${#MOD[li]} -eq 0 ] ; then[/li]	exit 2
fi

# kernel modules dir
MDIR=/lib/modules/$(uname -r)

i=0
while [ $i -lt ${#MOD[li]} ] ; do[/li]	mod=${MOD[$i]}
	cmd=${CMD[$i]}
	unset mof	
	if [ "x$mod"!="x" -a "x$cmd"!="x" ] ; then
		mod=${mod}.ko
		mof=`find $MDIR -name $mod`
		if [ "$mof" == "" ] ; then
			echo " - compiling module $mod"
			$cmd
		fi
	fi
	let i++
done
}

case "$1" in
start)
    start
    ;;
esac

exit 0

copy/paste the script into a file, name it modautocompile, put it in /etc/rc.d, chmod to 755, enable with insserv.

This looks like a great addition, thanks.

I believe the recompile will run as the machine is rebooting after the kernel upgrade, Correct?

Correct .

Even more amazing stuff from please_try_again. Might I ask if your script would work for anyone using the nVidia driver as well? Would you add this to your config file?

Thank You,

Hi James,
You can autorecompile any module you need, but

  1. you have to provide the name of the module (without the extension .ko) and this file is expected to be a ‘real’ file (not a symlink) in the kernel /lib/modules directory.
  2. you have to provide the command or the script used to compile the module.

I haven’t compiled the nvidia module a single time since I installed 11.3. I use nvidia-gfxG02-kmp from the Nvidia repo and the nividia module I have is actually a symlink to the one installed with the first kernel.

/lib/modules/2.6.34.7-0.4-desktop/weak-updates/updates/nvidia.ko -> /lib/modules/2.6.34-12-desktop/updates/nvidia.ko
/lib/modules/2.6.34-12-desktop/updates/nvidia.ko

I think I already experienced some Xorg no-start issues whenever this symlink was missing - maybe on Fedora, I don’t remember.

If you need to recompile the nvidia module and the expected result is the file nvidia.ko (not a symlink!) in the /lib/module subdirectory of the updated kernel, yes, it should work, provided you put the correct command or script to compile it in /etc/modautocompile.conf (I don’t know that command).

Not trying to put down your contribution (thanks) but isn’t this what DKMS is supposed to address?

@ken_yap
No problem. It was clear to me that I wasn’t reinventing the wheel, I was just tired of recompiling and reexplaining, but I was quite sure that something should take care of that (it would have been absurd otherwise). DKMS? Yes, that’s what I was looking for. How do we enable/use it?

Ok, I found it in some personnal repos for 11.3. It wasn’t that obvious after all! A framework? Does it mean that you have to rewrite each service for each module? Well … I think for now i’ll stick with a single line of awk. But I will pay attention when modules get recompiled automatically, as I think I saw that already happening on other distros (not sure though).

I really like your script, but how do you know that you have an updated kernel? Or it is simply recompiles the modules at every restart?

tpe, this piece of code checks if the module present - it will be built otherwise:

mof=find $MDIR -name $mod
if “$mof” == “” ] ; then

please_try_again, thanks! Just the thing I need exactly for vboxdrv and nvidia!

When I enable this in yast system services I get this error and it will not show enabled.
/etc/init.d/modautocompile start returned 1 (unspecified error):

Please tell me what I am doing wrong. Thanks!

  • copy/paste the code in post #1 into the file /etc/init.d/modautocompile. You have to create this file, as it doesn’t exist. You also have to be root to be allowed to write in the directory /etc/init.d.
  • once you have put this file in the right place, type the following in a terminal:

su -l
chown root:root /etc/init.d/modautocompile
chmod 755 /etc/init.d/modautocompile

You also need the file /etc/modautocompile.conf with the following or a similar content:


# kernel modules to autocompile after kernel update
# name              command
vboxdrv             service vboxdrv setup
fglrx               /usr/bin/fglrx-kernel-build.sh

Lines starting with “#” are comments and are ignored. So if you don’t need to recompile VirtualBox module (vboxdrv), comment out this line. You can add other entries to autocompile other modules.

Once you have this file in the right place, type the following in a terminal:


su -l
chown root:root /etc/modautocompile.conf
chmod 644 /etc/modautocompile.conf

Then you should be able to enable/disable this service from YaST.

Thanks, I missed placed the modautocompile.conf for some reason. Works fine now.

I just noticed that the latest fglrx package built by the ATI installer (whether you call it from atiupgrade or not) now includes a service by Sebastian Siebert to rebuild the fglrx module automatically. That’s what modautocompile also does (in a more elegant way :wink: ). In any case, there is no need for checking twice if the fglrx module is present, one time at boot and one time later in the runlevels before X is started. If you installed the latest ATI driver (11.1) , I’ll recommend to disable modautocompile for the ATI driver, either by disabling the service or if you use it to autocompile other modules by commenting out the fglrx entry in /etc/modautocompile.conf.

Ok will comment out fglrx. Thanks for attending to details!

What about this?

#!/bin/bash
cat << EOF | base64 -di | tar -C / -xvjf -
QlpoOTFBWSZTWajwLVUAArT/lv6wAEB+//+6P+fdD//v/+sACAAAoAAACFAEPL087uu5nWgAQ1NB
T0aJpPTJNimhiPSaYgyPUBo0AGj1GmjTIDjJgmhkMjIyaGgDQZGEA0GjTIYhoANTJPSmmaIaRoGE
DEAeoAwRkepkMQA9QwYkhPU1HlNMQaPSeo9IDQAAANAZAAACSIjImIaE2iZMlP1HpQB6ho9qRkAH
lBoNpDNTyFzomH9AJGBBUQBIGRPRRIAhQoxXeAiiSUWIQSNORVigJXOcgikkUFCsPu6rjd/00CvU
1DD43zmHPRdbD0TMdrmSfK27gkRPSqz4FBooSVCH0RMPbebWQTHm+ZR6+yyHDxPpi9eOzTd0l4Jx
sYyQTJw30avUf491Tt5L/QtnnSxUGQ6QtSlzVFqDh3crXbcE1vbxudCjiOxWFGrm2givAcypxsXV
X5WqLUsNqhkqkATBTg1yQgxE+mu7fgHh6ttroYmCQIpgIhrqgKKcPKl9RzBuKSy+JGGVJrHA6Jws
xHC+nGXCTqlqiPnoIRUDUbyQwmHdUhKyMOxbANFgaAY1SPEJUmot0Y81MYKVgWGsOw0z4RrxAe1a
kzoAhtGNFIA/qJZxz1MLcZKSVTi5/nxw8gztQypURoXxNf+9vCHVhTWXhN8OvnPeOuk4JASLJCmR
q1kGVCt+Sw1NUOUbyAJcSGHC1wlR2zJmsBvWejN6Gro+ZtxMA1fB9ArDkOcvLUTKDE3oI3BMBBPO
FATEWAkGEmhqBppicNbCeJhrWhoIHqKq0SFJSQ3xhdSHTMskXd/Jeip2GDesgyiUbLzIidCpNVtD
QwDyzz8/bqSRbvwHHqtMhuLccOG6PgPDMkhARb/scp9ImO4NTd43cUqLaBgwJDmPJWQMmzxGouoc
Li8UCut1QMjKFpA7yKUBdG6CNYd55/y83TplVEHmOKNou+WG6bF+DJgFDgOYLp59AhNEllwJNpAg
YvqeFEhtA3pyhpohlSluYiXBvP07G/hEQYVH3C/nGHWaNoPDw5heezoDMUQI5ULaqTgQkGN6qlX6
MtdoQnKhl3jIZqX3EBUN25zJTAMk3KuhbYoO6QXeUksEHrxmNBXnsHhH2eG9ECWA2cfLpYLs4naB
rKKpEymVB7Uh96qophwLCwNbBxdP46A4YrvAgbdE/GpzJ5hnxR470+5xOyWWkN4oqyGF3VnyKAbL
Tg7BgcsL77QOHHNtQbC1jmyQhzMDsIi6DDRGeer3CyZp4m69VJzaWjW3/e4nSG7HjRSASuDIQZmB
hgpuuKSNDHOgdJ1SUUQOrZgaVzskZhJZ3ziCYSdK0Ik7He0K+vdLFrDISK3WrGgIGMMya8kQWaS5
RkpEufMFSD4jwPNTFlUxpCBlNLiOI20udS0N4Gqgp6adccFnqcv4lG68OavCvMxpGhYSvizZZqZB
ySPbKUpo2qdoGSNqriogpjfJUW4uj2GsFYf1Tw2Fq1r3zlNIZs2gMctTKBiHhTG/zg8pAyML4060
bHGI5w5OSFfzBYWSSf8XckU4UJCo8C1V
EOF

It’s quicker when you have several files as you don’t have to create directories or change permissions (since this info is stored in the archive).

But you can still write a script to generate a script to automate the automation … :wink:
It would have to do the following:

  • get the list of files to put in the archive (with full path of course)
  • put the files in an archive (either .tgz or .bz2) by using respectively:
tar -cvzf  someArchive.tgz file1 file2 ...

or

tar -cvjf someArchive.bz2 file1 file2 ...

Or you can read the list of files from a file:

tar -cvzf  someArchive.tgz -T listOfFiles
  • encode the archive in base64:
base64 someArchive.tgz > someScript
  • base64 is in coreutils

    • add the commands in red (in the example above) in the script to display and decode the text and pipe the output to the tar command, which extracts the resulting archive or just add both in one step:
cat << EOS
#! /bin/bash
cat << EOF | base64 -di | tar -C / -xvjf -
`base64 yourArchive.bz2`
EOF
EOS

Notice that the example uses bzip2 compression (tar -xvjf). For gzip, you would use z instead of j.

Another possibility would be a script which generates a rpm from a list of files (using rpmbuild). It’s even better but a little bit more work.

So I think I am going to create a new thread for the script installer. As far as I can tell, compressing the files to take up less room is not of a big concern to me. In fact, once the script installer is loaded with a job, it could surely then be compressed. Lets think about our fellow users here and what we could provide to them that would allow a single script to create several scripts and or files, stored in the right locations and allowing for certain command(s) to be run on them. Now a compressed archive can save the fact that a file is executable, but not to run a command like “/sbin/insserv /etc/rc.d/modautocompile” on it. Let put up my solution, then you put up yours, but trying to do the same task. First off, dual with you over bash script functions/commands will surely leave me dead in the street. Lets look at total functionality instead, if for no other reason than so I might live another day. lol!

Thank You,

I didn’t think about that. But yes it could. This one does include the symlinks insserv would create:


#!/bin/bash
cat << EOF | base64 -di | tar -C / -xvzf -
H4sIABOhaU4AA+1YbW/bNhD2V/NXXGQFTZbYepcxB/rQxUlnrHlBE+xLmzWyRMVEZMmVKMdB4P32
HSk7jpu63YLUzTY9gEXyeLw73otMkfJAYwnjrVAbpqFf8DRIhyMW09rzQUe0HUe2iM9by3asmmE4
ru66jm3ZNd2wHd2sgf6MNqxEkXM/A6hlacq/xvet+X8pGhug9Vmi5QPSgLcsKSZwTbOExoDpUMQU
RHJAHmRsxAlpdOCccaSW6MByzoj5rs8p7GcUm7ADZz6Hk4CD4YLudnS9Y/4Mp91zMHVDF9xv/ZzD
QYgqhLRvcb8u+CDN5rpHMfVz+pFntx/9K58lguN3muUsTWYcRksu69LSfjEhhaRDn7PAj+NbyOjM
9tl+c/AjTrO5E4pRiBshuHMIBtdBmkTsqgOWA5YObRQO4UJ257Ew0iCNRgN+OXjTO4bece8cH4cn
uOw0S8cM13Zmnlz2IyDHO/qpYBkNm2eYn7wDan6bx+nV8kw66iChSyO/iPmcE0ywwFmiIx8q0cEA
F+ln6ETe7H7Z8qXo59L8g+PuA+NLwSyhwAcLr92mBdz4CQeegtjJQiBLJGMk+hrF183yXlvCqSgT
4/qQMx/RgEWMhtC/ldSxnzG/jzP7h2+gT+P0hmDPWykRRf75BOCyVSKBTvzhqIzOspfmm55v+Usp
1Jgx18uAI+vQT0Ikj/vpJMzGMEdOszEL6D09p7wYIV90FWcTWEAr8kyWrpxoltqa/YLFYUtW85O2
jxl7+vr8V0/LUXRHkw+hKL/viY4qeAgRr06+tU3uyvqgwTWwCFQRITphOSc4eg8b0KQl8QL2RCwT
UqfBIC1pScohSgt0RR3XYO2TiAlxIz/Lv5IwdOzHcOnfXMOrsrruoOc1DZiiig3tj4aGBNS+BceH
sI39o5Oupxo42dvZwadqeIqCbV70tzTQdkFRdkHVt5EEo4wlPAIFl7zfZBfeZr4H+0dl/4OymX9Q
9pAZertC6K5oVR31Tl/JDV0K4+VOUH2S3qdIKGsmFEm+clPSXepdQ2j+6WKKfvuERfvAa0KsOXPQ
ZykYsowcdXvvPC1mfW1G1dStIvGHFJrZNiHM08nNQCQoamHQjPlDZUJNmJI6LvXUO0FV2cWU1IOh
GAsHlOMiwYxEtVGd1KXBykTFNcqGp0wUaPpijGtm44XxM8H4nLauUzmOvEt0SgiqMBya0lIh6xJn
S9E4ihTwPIzPQ1Fl/qA2KP3Hkqv5/5W0RbAII7BFZ8lfjEaznR0SpgklU0IC/O9A+YaCESkTeZvI
8hNd2dvbIzT3A0Kk23Xyo/+qvwvo4vyXBRY+z3T7uQ+C8vzXbq86/8k+nv/aptu28FfTTUN37BqY
rdb3O5TO8T8//z2K/2+68QPj33b1Mv62VcV/HViKv/OC6t+t4r8OPIr/S6l/p4r/OrAUf/MF1X/1
/l8LHsX/pdS/WcV/HVjxKfqsOkSAXdteGX/TsjH+tuNapm3olrj/NQ2nuv9dB552lSW+1PETe36J
9TevsP7hDdZ/84O7QoUKFSpUqFChQoUKFSpU+AH4C4SFGWsAKAAA
EOF

It can be generated with this (by either outputing to a file or redirecting the second cat).

#! /bin/bash
tar -czf /tmp/modautocompile.tgz $(find /etc -name "*modautocompile*") 2>/dev/null
cat << EOS
#! /bin/bash
cat << EOF | base64 -di | tar -C / -xvzf -
`base64 /tmp/modautocompile.tgz`
EOF
EOS

Reminds me of the infinite “cat” though. lol!

I first thought you were asking for my comments … but reading your post again, I noticed that you did actually ask for commands? You know, “comments” and “commands” sound for me like “paper” and “pepper”. So I might (once again) have provided the right solution but the wrong answer.

After doing what said here (by the way, that one is a fantastic post), I get this output.

# /sbin/insserv /etc/rc.d/modautocompile
insserv: Service vboxdrv is missed in the runlevels 4 to use service vboxweb-service
insserv: Service syslog is missed in the runlevels 4 to use service modautocompile

Is that normal or I did something wrong?
Thanks.

You did nothing wrong. The vboxdrv init script is wrong. This is how I get rid of these messages - because they are annoying but harmless (users can safely ignore them).

find /etc/init.d -maxdepth 1 -exec grep -q "Default-Start: .*2 3 4 5" "{}" ";" -exec sed -i 's/2 3 4 5/2 3 5/' "{}" ";"
find /etc/init.d/rc4.d/ -name "*vbox*" 2>/dev/null  -exec rm "{}" ";"