#!/usr/bin/perl -w # # $Id: kernel-helper.pl,v 2.9 2003/01/13 05:28:43 jmates Exp $ # # Copyright (c) 2001, Jeremy Mates. This script is free software; # you can redistribute it and/or modify it under the same terms as # Perl itself. # # Run perldoc(1) on this file for additional documentation. # ###################################################################### # # REQUIREMENTS require 5; use strict; ###################################################################### # # MODULES use Carp; # better error reporting use Getopt::Std; # command line option processing ###################################################################### # # VARIABLES # default method to use when parsing dmesg and config files my $method; chomp($method = `uname`); # re-conf and re-dmesg match the device in $1 and parent device # in $2. prefix is what to tag disabled lines with in output. # extra is a built-in hack for devices I like enabled by default. my $how = { 'simple' => { 're-conf' => '^([^\s:]+):\s*(.*)', 're-dmesg' => '^([^\s:]+):\s*(.*)', 'prefix' => '#', }, 'OpenBSD' => { 'extra' => 'root mainbus isa pci inphy', 're-conf' => '^([a-z]+).{0,3}?\s+at\s+([a-z]+)', 're-dmesg' => '^([a-z]+)\d*\s+at\s+([a-z]+)', 'prefix' => '#PRUNED#', }, 'FreeBSD' => { 'extra' => 'npx sio ata atadisk atapicd ppbus miibus scbus da sa cd pass', 're-conf' => '^device\s+([a-z]+)(?:\d*.*?at\s+([a-z]+))?', 're-dmesg' => '^([a-z]+)\d*:(?:.*?on\s+([a-z]+)\d*)?', 'prefix' => '#PRUNED#', } }; my $VERSION; ($VERSION = '$Revision: 2.9 $ ') =~ s/[^0-9.]//g; my (%opts, $dmesg_lookup, $debug); ###################################################################### # # MAIN # parse command-line options getopts('h?k:K:m:ld', \%opts); help() if exists $opts{'h'} or exists $opts{'?'}; if (exists $opts{'l'}) { print "Available -m methods: ", join (" ", sort keys %$how), "\n"; exit; } # load user-supplied spared devices list(s) $how->{$method}->{'extra'} .= $opts{'k'} if exists $opts{'k'}; $how->{$method}->{'evict'} .= $opts{'K'} if exists $opts{'K'}; $method = $opts{'m'} if exists $opts{'m'}; unless (exists $how->{$method}) { warn "No such method: $method\n"; die "Available -m methods: ", join (" ", sort keys %$how), "\n"; } $debug = 1 if exists $opts{'d'}; # read required files... my $kconf_file = shift or help(); my $dmesg_file = shift; # read in dmesg output, turn into lookup table unless (defined $dmesg_file) { $dmesg_lookup = parse_dmesg(*STDIN, $how->{$method}->{'re-dmesg'}); } else { open DMESG, $dmesg_file or die "Problem opening $dmesg_file: $!\n"; $dmesg_lookup = parse_dmesg(*DMESG, $how->{$method}->{'re-dmesg'}); close DMESG; } #use Data::Dumper; #warn Dumper $dmesg_lookup; # walk arch-specific conf file, disabling devices not in lookup table open CONF, $kconf_file or die "Problem opening $kconf_file: $!\n"; while () { chomp; my $zorch; my ($dev, $req) = /$how->{$method}->{'re-conf'}/; if ($dev) { unless (exists $dmesg_lookup->{$dev}) { warn "Disabling $dev (", $req || '-', ") as not in lookup table\n" if $debug; $zorch = 1; } if (defined $dmesg_lookup->{$dev} and $req) { unless ($dmesg_lookup->{$dev} =~ /\b$req\b/) { warn "Disabling $dev ($req) as no supporting requirement\n" if $debug; $zorch = 1; } } if ($how->{$method}->{'extra'} =~ /\b$dev\b/) { warn "Extra match on $dev, not disabling\n" if $debug; $zorch = 0; } if ($how->{$method}->{'evict'} and $how->{$method}->{'evict'} =~ /\b$dev\b/) { warn "Forced to disable $dev!\n" if $debug; $zorch = 1; } $_ = $how->{$method}->{prefix} . $_ if $zorch; } print $_, "\n"; } close CONF; exit; ###################################################################### # # SUBROUTINES # extracts dmesg(8) device list into hash, returns reference of such # expects filehandle containing dmesg output, and a regex to match # entries with sub parse_dmesg { my $fh = shift; my $regex = shift; my $dmesg_lookup; while (<$fh>) { chomp; s/^\s+//; next if /^#/; s/\s+$//; next if /^$/; my ($dev, $req) = /$regex/; if ($dev) { $req = '' unless $req; $dmesg_lookup->{$dev} .= ' ' . $req; } } return $dmesg_lookup; } # takes a filename to open, and returns a stringified version of # the file (as additonal device keys to match against). # sub load_extras { # my $file = shift; # my $tmp; # # open FILE, $file or die "Couldn't load $file: $!\n"; # while () { # chomp; # s/^\s+//; # next if /^#/; # s/\s+$//; # next if /^$/; # # $tmp .= ' ' . $_; # } # close FILE; # # return $tmp; # } # a generic help blarb sub help { print <<"HELP"; Usage: $0 arch-conf-file [dmesg-file] Kernel configuration unused device pruner. Options for version $VERSION: -h/-? Display this message -k en List of extra devices not to disable, space or CSV. -K di Devices to disable (done after enable check). -m xx Use method xx for parsing files. Defaults to output of uname(1) command. -l List available methods and quit. Run perldoc(1) on this script for additional documentation. HELP exit; } ###################################################################### # # DOCUMENTATION =head1 NAME kernel-helper.pl - unused device pruner for *BSD kernel config =head1 SYNOPSIS Run the following to create the beginnings of a new kernel configuration on OpenBSD. # cd /usr/src/sys/arch/`uname -m`/conf # dmesg | kernel-helper.pl GENERIC > MYCONFIG =head1 DESCRIPTION =head2 Overview This script uses information extracted from dmesg(8) to comment out lines in *BSD configuration files (FreeBSD and OpenBSD, at present). The lines disabled are those that do not reference any of the devices detected at startup. This allows one to easily build a kernel that runs faster and takes up less memory (at the cost of flexibility). One should always review the changes done to the configuration file by this script, as something vital may have been disabled. Lines changed by this script are marked with C<#PRUNED#> by default. For debugging purposes, you should also build a generic kernel from the GENERIC configuration, in case of problems with the machine running the customized kernel. =head2 Normal Usage $ kernel-helper.pl [options] arch-conf-file [dmesg-file] See L<"OPTIONS"> for details on the command line switches supported. The I is the kernel configuration file containing all the device definitions for your system, whose location various by the system and arch in question. FreeBSD: C OpenBSD: C I is optional, and if omitted the script will attempt to read the dmesg information from STDIN. This allows live dmesg output to be fed into the script. The resulting configuration file is printed to STDOUT. =head1 OPTIONS This script currently supports the following command line switches: =over 4 =item B<-h>, B<-?> Prints a brief usage note about the script. =item B<-m> I Use I instead of the default pull from uname(1). =item B<-l> List available methods and quit. =item B<-k> I List of I not to disable. Should be the device name(s) separated by whitespace or comma. =item B<-K> I List of I to be sure to disable. This step is done after the enable checkes. =item B<-d> Invoke debug mode. Such output is done to STDERR. =back =head1 EXAMPLES The B<-k> and B<-K> options can be used to fine-tune which devices you do and do not want; the following enables USB, and the Hub and Keyboard subdrivers on OpenBSD. # kernel-helper.pl -k "usb uhub ukbd" GENERIC /tmp/dmesg.out > MYCONFIG Due to the custom prefix appended to changed lines in the resulting configuration file (C<#PRUNED#> by default), undoing the changes is easy, in the event you are applying an already customized config to new or updated hardware. # perl -i.orig -ple 's/#PRUNED#//' MYCONFIG See perlrun(1) for more information on the above command line arguments to perl. =head1 ENVIRONMENT Expects to be run on FreeBSD or OpenBSD systems, which are detected automatically via uname(1). Otherwise, one can specify a method to use manually. =head1 BUGS =head2 Reporting Bugs Newer versions of this script may be available from: http://sial.org/code/perl/ If the bug is in the latest version, send a report to the author. Patches that fix problems or add new features are welcome. =head2 Known Issues The script tends to trash various devices that one may need; one should always review whether the resulting config is actually viable. I use the script as a "close enough" starting point for kernel configuration. USB is notable for getting trampled on, unless you have all the devices you will ever use plugged and detected at boot. =head1 SEE ALSO config(8), OpenBSD's options(4), perl(1) Another set of perl scripts by Camiel Dobbelaar to do similar things (found after writing this script) on OpenBSD: http://www.sentia.org/downloads/tweakboot http://www.sentia.org/downloads/tweakcompile =head1 AUTHOR Jeremy Mates, http://sial.org/contact/ =head1 COPYRIGHT Copyright (c) 2001, Jeremy Mates. This script is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 VERSION $Id: kernel-helper.pl,v 2.9 2003/01/13 05:28:43 jmates Exp $ =cut