A very useful script

Paul Gortmaker (gpg109@rsphy1.anu.edu.au)
Mon, 1 Jul 1996 16:23:50 +1000 (EST)


Kprune is an intelligent script that prunes the kernel source down in
size, based on the information in your ".config" file and also based
on your input (optional).

For example, with v2.0 the source is about 23MB in total. Using a
typical config (i.e. arch/i386/defconfig) which has IDE HD, IDE CD,
3c509 ether, NFS, etc. etc. and running this script trims that 23MB
back to about 9MB by zapping about 14MB of unused stuff. Yup, that is
a reduction of 60% in total. You may do better or worse, depending
on how complex your configuration is. (A bare bones 486 config with
HDD, NE2k, EXT2, NFS, proc, serial gets down to about 7.5MB.)

I'd suggest running it with "-d" to begin with so you get a feel for
what would be deleted without actually deleting anything for real. Once
you are happy with it, you can just to a "kprune -q -t" and listen to
your disk churn.

Obviously you have to do a "make config" first to create ".config".
You also have to do a "make dep" before pruning the tree, as "make dep"
is dain-bramaged and gets upset when certain whole subdirs have been
pruned. B-) Kprune checks for both of the above before proceeding. After
pruning the tree, you should have lots of space for all your *.o files.

Just in case the various mailers munge the script, I have also put it
at the end of the following URL:

http://rsphy1.anu.edu.au/~gpg109/kprune

As usual, if it breaks you get to keep both parts.
Paul.

-------------------------8<----------------------8<-----------------
#!/bin/sh
#
# kprune: An interactive script that allows selective pruning
# of the kernel source tree, based on user input, and
# on the information contained in the ".config" file.
#
# Options:
# -a Automatic prune mode based on .config file data.
# -d Debug mode, don't delete anything. (implies "-t")
# -h Give help
# -t Keep a tally/total of kB deleted.
# -q quiet delete mode (implies "-a")
#
# The v2.0 kernel tree is now about 23MB in total and I hacked up
# this script to address that. It only targets whole directories and
# a handful of large (>50k) drivers. If that isn't good enough then
# you can do additional pruning by hand, or buy another hard disk. :)
# Use at own risk, no warranty, distributed under GPL, etc. etc.
#
# Paul Gortmaker

VERBOSE=y
AUDIT=n
AUTO=n
DEBUG=n
DISKSPACE=0
NAME=kprune

# Are we using bash (Can we *not* be ?)
if [ -z "$BASH" ];then
echo "$NAME requires bash" 1>&2
exit 1
fi

# Report some hocus-pocus usage message with optional error message to stderr
usage () {
if [ -n "$1" ];then
echo $NAME: Illegal option \"$1\" 1>&2
EXITVAL=1
else
EXITVAL=0
fi
echo "Usage: $NAME [-a] [-d] [-q] [-t]"
echo Prunes kernel of unused source based on user input and .config file.
echo -e \\t\-a\\tauto mode, delete only based on \".config\" file info.
echo -e \\t\-d\\tdebug mode, only report what would have been deleted.
echo -e \\t\-h\\tprint this help message.
echo -e \\t\-q\\tquiet mode, implies non-interactive \"-a\" mode.
echo -e \\t\-t\\ttally mode, report on total kB of files deleted.
exit $EXITVAL
}

# Delete funciton with auditing ability.
# DEBUG is for testing the script w/o untarring the kernel 50 times...
# usage: delete file1 [file2] [file3] ... [fileN]
#
function delete () {
if [ "$AUDIT" = "y" ]; then
SAVING=`du -csk $* 2> /dev/null | tail -n1 | sed 's/[ ]total//'`
DISKSPACE=$[$DISKSPACE+$SAVING]
fi
if [ "$DEBUG" = "y" ];then
echo Debug mode, would have deleted "$SAVING"kB in file\(s\):
for i in $*
do
echo -e \\t $i
done
echo Currently tagged "$DISKSPACE"kB of files.
echo
else
rm -rf $@
fi
}

# Grab some user input.
# usage: readln prompt default
#
function readln () {
if [ "$AUTO" = "y" ]; then
if [ "$VERBOSE" = "y" ]; then
echo -e "$1":\\tDefault="$2"
fi
ans=$2
else
case "$2" in
"y") defprompt="Y/n"
;;
"n") defprompt="N/y"
;;
esac

echo -n "$1" [$defprompt]
IFS='@' read ans </dev/tty || exit 1
[ -z "$ans" ] && ans=$2
fi
}

#
# Print a option group comment
# usage: comment txt_arg
#
function comment () {
if [ "$VERBOSE" = "y" ]; then
echo
echo "***" $1 "***"
echo
fi
}

# Walk a list of CONFIG_XXX;xxx;yyy;zzz args and offer to delete the file(s)
# xxx, yyy and zzz if CONFIG_XXX is not defined.
# usage: walklist "CONFIG_ABC;abc CONFIG_DEF;def1;def2 .... "
#
function walklist () {

for i in $@
do
FILES=""
OLDIFS=$IFS
IFS=\;
read OPT FILELIST <<-EOF
$i
EOF
for j in $FILELIST
do
FILES="$FILES $j"
done
IFS=$OLDIFS
OPTVAL=$(eval echo "\${$OPT}")
if [ -z "$OPTVAL" ]; then
readln "Delete $OPT files ($FILELIST)" y
if [ $ans = "y" ];then
delete $FILES
fi
fi
done

}

# Parse the user options and call them an idiot if they supply bogus opts.
for i in $*
do
case $i in
-a) AUTO="y"; continue;;
-d) DEBUG="y"; AUDIT="y"; continue;;
-h) usage;;
-t) AUDIT="y"; continue;;
-q) VERBOSE="n"; AUTO="y"; continue;;
*) usage $i;;
esac
done

# Has the user created a ".config" file yet via make {x,menu,""}config?
if [ ! -f .config ]; then
echo You must run \"make config\" before running $NAME. 1>&2
exit 1
fi

# See what the user has enabled at the moment
source .config

# The "make dep" step will barf if we prune the tree before it
# is run, so we make sure that is done before pruning as well.
if [ ! -f .depend ]; then
echo You must run \"make depend\" before using $NAME. 1>&2
exit 1
fi

# This implictly assumes that the asm dirs have the name "asm-$ARCH"
ARCHDIRS="alpha i386 m68k mips ppc sparc"

# There is no magic CONFIG_XXX that will give us the arch as easy as this.
# Using "uname -m" is ugly because it can be i[3456]86, etc.
unalias ls 2> /dev/null
ARCH=`ls -l include/asm | sed 's/^.*asm-//'`

# Lists of big architechture specific files that *aren't* tied to a
# CONFIG_XXX option. Nothing for some of these guys at the moment.
FILES_i386=""
FILES_mips=""
FILES_ppc=""
FILES_alpha="drivers/char/tga.c"
FILES_sparc="drivers/sbus"
FILES_m68k="\
drivers/block/amiflop.c \
drivers/block/ataflop.c \
drivers/scsi/atari_* "

comment "Unused Processor Architecture Specific Files"
for i in $ARCHDIRS
do
if [ $i != $ARCH ]; then
ARCH_LIST=FILES_$i
ARCH_FILES=$(eval echo "\${$ARCH_LIST}")
readln "Delete files for $i architecture" y
if [ $ans = "y" ]; then
delete arch/"$i" include/asm-"$i" $ARCH_FILES
fi
fi
done

# Various unused filesystems can be deleted as well
FSLIST="\
CONFIG_AFFS_FS;fs/affs \
CONFIG_FAT_FS;fs/msdos \
CONFIG_EXT_FS;fs/ext \
CONFIG_EXT2_FS;fs/ext2 \
CONFIG_HPFS_FS;fs/hpfs \
CONFIG_ISO9660_FS;fs/isofs \
CONFIG_MINIX_FS;fs/minix \
CONFIG_NFS_FS;fs/nfs \
CONFIG_PROC_FS;fs/proc \
CONFIG_SMB_FS;fs/smbfs \
CONFIG_UMSDOS_FS;fs/umsdos \
CONFIG_VFAT_FS;fs/vfat \
CONFIG_XIA_FS;fs/xiafs "

comment "Unused file systems"
walklist $FSLIST

# Can also nuke SCSI or at least some large drivers if not being used.
# Only the real monsters are targeted at the moment
SCSIDRVRS="\
CONFIG_BLK_DEV_SD;drivers/scsi/sd.c \
CONFIG_CHR_DEV_ST;drivers/scsi/st.c \
CONFIG_BLK_DEV_SR;drivers/scsi/sr.c \
CONFIG_CHR_DEV_SG;drivers/scsi/sg.c \
CONFIG_SCSI_ADVANSYS;drivers/scsi/advansys.* \
CONFIG_SCSI_BUSLOGIC;drivers/scsi/BusLogic.* \
CONFIG_SCSI_NCR53C7xx;drivers/scsi/53c[78]* \
CONFIG_SCSI_AIC7XXX;drivers/scsi/aic7xxx* \
CONFIG_SCSI_AM53C974;drivers/scsi/AM53C974.* \
CONFIG_SCSI_QLOGIC_ISP;drivers/scsi/qlogicisp* "

comment "Unused SCSI support/drivers"
if [ -z "$CONFIG_SCSI" ];then
walklist "CONFIG_SCSI;drivers/scsi"
else
walklist $SCSIDRVRS
fi

# drivers/char is a mess. (i.e. no subdirs). Target large files anyway.
CHARDRVRS="\
CONFIG_BAYCOM;drivers/char/baycom.c \
CONFIG_CYCLADES;drivers/char/cyclades.c \
CONFIG_DIGI;drivers/char/pcxx*;drivers/char/digi* \
CONFIG_FTAPE;drivers/char/ftape \
CONFIG_ISTALLION;drivers/char/istallion.c \
CONFIG_RISCOM8;drivers/char/riscom8* \
CONFIG_SCC;drivers/char/scc.c \
CONFIG_SERIAL;drivers/char/serial.c \
CONFIG_STALLION;drivers/char/stallion.c \
CONFIG_QIC02_TAPE;drivers/char/tpqic02.c "

comment "Unused Character Devices"
walklist $CHARDRVRS

# drivers/block is a mess. (i.e. no subdirs). Target large files anyway.
BLKDRVRS="\
CONFIG_BLK_DEV_FD;drivers/block/floppy.c \
CONFIG_BLK_DEV_IDE;drivers/block/ide.* \
CONFIG_BLK_DEV_IDECD;drivers/block/ide-cd.c \
CONFIG_BLK_DEV_IDETAPE;drivers/block/ide-tape.* "

comment "Unused Block Drivers"
walklist $BLKDRVRS

# drivers/net is a mess. (i.e. no subdirs). Target large files anyway.
# The dgrs firmware is good for 1/2 MB!!
NETDRVRS="\
CONFIG_ARCNET;drivers/net/arcnet.c \
CONFIG_DE4X5;drivers/net/de4x5.* \
CONFIG_DEPCA;drivers/net/depca.* \
CONFIG_DGRS;drivers/net/dgrs* \
CONFIG_EWRK3;drivers/net/ewrk3.* \
CONFIG_PPP;drivers/net/ppp.c \
CONFIG_PT;drivers/net/pt.* \
CONFIG_SMC9194;drivers/net/smc9194.* \
CONFIG_SK_G16;drivers/net/sk_g16.* \
CONFIG_WAVELAN;drivers/net/wavelan.* "

comment "Unused Network Device Drivers"
if [ -z "$CONFIG_NETDEVICES" ];then
walklist "CONFIG_NETDEVICES;drivers/net"
else
walklist $NETDRVRS
fi

# drivers/cdrom is a mess. (i.e. no subdirs). Target large files anyway.
CDROMDRVRS="\
CONFIG_AZTCD;drivers/cdrom/aztcd.c \
CONFIG_CDU31A;drivers/cdrom/cdu31a.c \
CONFIG_CDU535;drivers/cdrom/sonycd535.c \
CONFIG_MCDX;drivers/cdrom/mcdx.c \
CONFIG_OPTCD;drivers/cdrom/optcd.c \
CONFIG_SBPCD;drivers/cdrom/sbpcd.c "

comment "Unused CD-ROM Drivers (non IDE/SCSI)"
if [ -z "$CONFIG_CD_NO_IDESCSI" ];then
walklist "CONFIG_CD_NO_IDESCSI;drivers/cdrom"
else
walklist $CDROMDRVRS
fi

# ISDN is nice and tidy with drivers in subdirs :-)
ISDNDRVRS="\
CONFIG_ISDN_DRV_TELES;drivers/isdn/teles \
CONFIG_ISDN_DRV_ICN;drivers/isdn/icn \
CONFIG_ISDN_DRV_PCBIT;drivers/isdn/pcbit "

comment "Unused ISDN Drivers"
if [ -z "$CONFIG_ISDN" ];then
walklist "CONFIG_ISDN;drivers/isdn"
else
walklist $ISDNDRVRS
fi

# Unused net protocols, etc
NETPROTS="\
CONFIG_ATALK;net/appletalk \
CONFIG_AX25;net/ax25 \
CONFIG_BRIDGE;net/bridge \
CONFIG_INET;net/ipv4 \
CONFIG_IPX;net/ipx \
CONFIG_NET;net/802 \
CONFIG_NETROM;net/netrom "

comment "Unused Networking Protocols/Functionality"
walklist $NETPROTS

# Nuke other driver subdirs as an all or nothing approach.
comment "Misc. Other Drivers, documentation, etc."
walklist "CONFIG_SOUND;drivers/sound"
walklist "CONFIG_PCI;drivers/pci"

# Don't blast the Documentation dir unless user explicitly says "y"
# Also offer to clean up misc README files, Changelog, etc.
readln "Delete Documentation directory and all README/Changelog files" n
if [ $ans = "y" ];then
delete Documentation
READMES=`find . -name 'README*' -print`
if [ -n "$READMES" ];then
delete $READMES
fi
CHANGELOG=`find . -name 'Change*' -print`
if [ -n "$CHANGELOG" ];then
delete $CHANGELOG
fi
fi

if [ "$AUDIT" = "y" ];then
echo; echo "There was a total of "$DISKSPACE"kB of deleted files."
fi

if [ "$VERBOSE" = "y" ];then
echo
echo "After compiling and installing the kernel, you may wish to do:"
echo -e \\t"rm -f vmlinux"
echo -e \\t"rm -f arch/i386/boot/compressed/piggy.o"
echo -e \\t"rm -f arch/i386/boot/compressed/vmlinux"
echo -e \\t"rm -f arch/i386/boot/zImage"
echo -e \\t"rm -f core \`find . -name '*.a' -print\`"
echo "to recover 2 -> 3MB without sacrificing future rebuild times."
echo
fi