[CFT][RFC] Module auto-unloading solution.

From: Steve Youngs
Date: Wed Dec 17 2003 - 01:21:13 EST


Hi Folks!

Modules don't auto-unload, they haven't since the introduction of
kmod. Whether that's right or wrong is _not_ what this post is
about.

I do know that there are a lot of people out there using Linux who
like to have their unused modules silently and cleanly automatically
unload. For that reason, I put together the script at the end of this
post. So people have the option if they want it.

Before I offer it to the general public, it'd be fantastic if some of
you could look it over, kick the tyres and take it for a spin around
the block. All comments etc would be very welcome and greatly
appreciated.

Thanks.

---------------------------------------------------
#!/bin/bash

## Copyright (C) 2003 Steve Youngs

## RCS: $Id: auto-rmmod.sh,v 1.7 2003-12-17 15:34:51+10 steve Exp $
## Author: Steve Youngs <sryoungs@xxxxxxxxxxxxxx>
## Maintainer: Steve Youngs <sryoungs@xxxxxxxxxxxxxx>
## Created: <2003-11-25>
## Last-Modified: <2003-12-17 15:34:33 (steve)>
## Homepage: None yet. For now, email the Maintainer for the latest
## version

## Redistribution and use in source and binary forms, with or without
## modification, are permitted provided that the following conditions
## are met:
##
## 1. Redistributions of source code must retain the above copyright
## notice, this list of conditions and the following disclaimer.
##
## 2. Redistributions in binary form must reproduce the above copyright
## notice, this list of conditions and the following disclaimer in the
## documentation and/or other materials provided with the distribution.
##
## 3. Neither the name of the author nor the names of any contributors
## may be used to endorse or promote products derived from this
## software without specific prior written permission.
##
## THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
## IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
## WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
## DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
## FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
## SUBSTITUTE GOODS OR SERVICES LOSS OF USE, DATA, OR PROFITS OR
## BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
## WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
## OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
## IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

### Commentary:
##
## This script is for people who want their kernel modules auto-unloaded
## when they are not in use. It won't try to unload ethernet drivers
## because these modules don't set the "in-use" property. If you want
## to unload your ethernet drivers just do so manually with
## `modprobe -r module'.
##
## If you have any modules that you don't want this script to unload
## you can specify a regular expression of modules on the command
## line. See `auto-rmmod.sh --help' for details.
##
## *************************** W A R N I N G ***************************
## * *
## * Even though I have taken considerable care to ensure that ONLY *
## * unused modules are ever unloaded you should thoroughly test this *
## * script BEFORE putting it to use. *
## * *
## * For testing purposes you can use: `auto-rmmod.sh [REGEXP] --test' *
## * *
## *********************************************************************

## Setup and Usage:
##
## Check the paths in the variables listed after "### Code:", ensure
## that they are correct.
##
## Test with `auto-rmmod.sh [REGEXP] --test' until you're happy with
## what is going on.
##
## Next add a cron entry similar to this one to root's crontab:
##
## 0-59/10 * * * * exec /path/to/auto-rmmod.sh [REGEXP]
##
## That will run the script once every ten minutes. Now you can sit
## back and enjoy the wonders of automatic loading and unloading of
## your kernel modules.

## Note: Modules that don't want to auto-load:
##
## The loading mechanism for character device modules changed in
## 2.6.0-test10. In pre -test10 kernels these modules were called
## with `char-major-<major>', in -test10 and later kernels they are
## now called with `char-major-<major>-<minor>'. The modules,
## themselves, are supposed to export these chardev aliases, but as
## yet, not many of them do. To work around this until your module
## has been fixed put `alias char-major-<major>-<minor> module' or
## `alias char-major-<major>-* module' into your
## `/etc/modprobe.conf'. This will also be true of block devices,
## but as at -test11 it still hasn't been implemented.

## Feedback, bug reports and patches etc:
##
## All are welcome. Send them to the address listed at "Maintainer"
## at the top of this file.

### Todo:
##
##

### Code:

## Ensure that all of these are correct for your system.
BASENAME=/usr/bin/basename
CAT=/usr/bin/cat
CUT=/usr/bin/cut
FIND=/usr/bin/find
GREP=/usr/bin/grep
ID=/usr/bin/id
MODPROBE=/sbin/modprobe
SED=/usr/bin/sed
TR=/usr/bin/tr
XARGS=/usr/bin/xargs

############################################################
# Nothing Configurable Beyond this point #
############################################################

currentkernel=`uname -r`
ethernetdir=/lib/modules/$currentkernel/kernel/drivers/net
opts=$1

# Check to see if this is a test run.
if [ "$opts" == "--test" -o "$2" == "--test" ]; then
if [ "$opts" == "--test" ]; then
unset opts
fi
MODPROBE="$MODPROBE --dry-run --verbose"
fi

# There's no point in running this unless we're root.
function chkuser() {
if [ `$ID --user` -ne 0 ]; then
echo "Error: You must be root to run this."
exit 1
fi
}

function buildregexp() {
# Create a regexp of ethernet modules.
$FIND $ethernetdir -type f -name \*.ko > /dev/null 2>&1
if [ $? -eq 0 ]; then
for file in `ls /lib/modules/$currentkernel/kernel/drivers/net/`; do
convertedname=`$BASENAME $file .ko|$SED s/-/_/`
if [ $internalpersist ]; then
internalpersist="$convertedname\|$internalpersist"
else
internalpersist="$convertedname"
fi
done
# Need to truncate a trailing '\|'.
internalpersist=`expr match "$internalpersist" '\(.*[^\\\\|]\)'`
fi

# Set the list of persistant modules to any ethernet modules.
if [ $internalpersist ]; then
persistantmods="$internalpersist"
fi

# Add any user supplied regexp to the list of modules to NOT unload.
if [[ $opts && $persistantmods ]]; then
persistantmods="$persistantmods\|$opts"
elif [ $opts ]; then
persistantmods="$opts"
fi
}

# The actual guts of this has to run 2 or 3 times to clean up all the
# modules. The reason behind this is that removing one module can
# free up another, so we take a couple of extra passes at it.
function doit() {
i=1
while [ $i -le 3 ]; do
if [ $persistantmods ]; then
$CAT /proc/modules | $GREP -v $persistantmods | \
$CUT -d ' ' -f 1,3 | $GREP ' 0$' | $CUT -d ' ' -f 1 | \
$TR '\n' ' ' | $XARGS $MODPROBE --remove
i=$[ i + 1 ]
else
$CAT /proc/modules | $CUT -d ' ' -f 1,3 | $GREP ' 0$' | \
$CUT -d ' ' -f 1 | $TR '\n' ' ' | $XARGS $MODPROBE --remove
i=$[ i + 1 ]
fi
done
}

function usage() {
cat<<EOF
`$BASENAME $0`
`$BASENAME $0` [REGEXP]
`$BASENAME $0` [OPTION]

REGEXP

Is a regular expression of module names that you DO NOT want this
script to unload. Be aware that the kernel converts dashes ('-') to
underscores ('_') in module names. Also note that you should NOT
include the suffix '.ko'.

Example: If you never want this script to unload 'foo-bar.ko',
'foo-baz.ko', and 'widgets.ko', the REGEXP would be
'foo_ba[rz]\|widgets'. Be sure to surround your REGEXP in single
quotes to avoid unexpected results.

See grep(1) for the format of REGEXP.

OPTION

-h|--help|--usage ..... Display this usage text.

--test ................ Run in "test mode". Display the modules to
be removed, but do not actually remove them.
EOF
}

case $opts in
\?|-\?|h|-h|--help|--usage)
usage
exit 0
;;
*)
chkuser
buildregexp
doit
exit 0
;;
esac

### auto-rmmod.sh ends here

## $Log: auto-rmmod.sh,v $
## Revision 1.7 2003-12-17 15:34:51+10 steve
## Doc fix.
##
## Revision 1.6 2003-12-17 14:59:05+10 steve
## Major rewrite, getting ready for general consumption.
## Added a "usage" function, command line options, and the option to run
## in "test" mode.
##
## Revision 1.5 2003-12-15 16:08:20+10 steve
## Even more doc fixes.
##
## Revision 1.4 2003-12-15 15:35:40+10 steve
## Rename to `auto-rmmod.sh'
##
## Revision 1.3 2003-12-15 15:33:06+10 steve
## Doc fixes.
##
## Revision 1.2 2003-11-25 09:54:46+10 steve
## Don't use an external file with the `-f' switch, just use a regexp
## directly from the script.
##

#Local Variables:
#time-stamp-start: "Last-Modified:[ ]+\\\\?[\"<]+"
#time-stamp-end: "\\\\?[\">]"
#time-stamp-line-limit: 10
#time-stamp-format: "%4y-%02m-%02d %02H:%02M:%02S (%u)"
#End:

--
|---<Steve Youngs>---------------<GnuPG KeyID: A94B3003>---|
| Ashes to ashes, dust to dust. |
| The proof of the pudding, is under the crust. |
|------------------------------<sryoungs@xxxxxxxxxxxxxx>---|

Attachment: pgp00004.pgp
Description: PGP signature