From 8936ad36dbfca70d29cabbde95ffc91536205d2f Mon Sep 17 00:00:00 2001 From: gord Date: Wed, 9 Nov 2005 20:47:25 +0000 Subject: [PATCH] Add kabi script to CVS. --- build/Rules.in | 25 ++++ build/kabi | 364 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 389 insertions(+) create mode 100755 build/kabi diff --git a/build/Rules.in b/build/Rules.in index 19862f2..f03bb80 100644 --- a/build/Rules.in +++ b/build/Rules.in @@ -23,6 +23,31 @@ ifeq ($(PATCHLEVEL),) include autoMakefile +# The kernel ABI files for the nonfree modules. +KABIS := $(NONFREE_MODULES:%$(KMODEXT)=%.kabi) + +all: archive-nonfree-modules + +# Where to archive the nonfree modules for binary distribution. +# If this directory has a colon in it, SSH/SCP are used to go out on the network. +nonfreedir := $$HOME/nonfree +#nonfreedir := moraine.clusterfs.com:/home/lustre-nonfree + +# Put the nonfree modules and corresponding KABI files into the binary +# archive. We assume that if the CVS subdirectory doesn't exist, we +# don't want to archive. +archive-nonfree-modules: $(KABIS) $(NONFREE_MODULES) + test -d CVS || exit 0; \ + list="$(NONFREE_MODULES)"; for mod in $$list; do \ + perl $(top_srcdir)/build/kabi -v archive $(nonfreedir) $$mod || exit $$?; \ + done + +# Generate the Kernel ABI files for the nonfree modules. +$(KABIS): $(NONFREE_MODULES) + for mod in $(NONFREE_MODULES); do \ + CC="$(CC)" perl $(top_srcdir)/build/kabi --with-linux="$(LINUX)" module $$mod || exit $$?; \ + done + fix-kext-ownership: @if test -d $(DESTDIR)$(kextdir) ; then \ echo chown -R root:wheel $(DESTDIR)$(kextdir) ; \ diff --git a/build/kabi b/build/kabi new file mode 100755 index 0000000..a57a46c --- /dev/null +++ b/build/kabi @@ -0,0 +1,364 @@ +#! /usr/bin/perl +# kabi - Linux Kernel Application Binary Interface manager +# Copyright (C) 2005 Cluster File Systems, Inc. +# All rights reserved. +# +# Gordon Matzigkeit , 2005-10-21 + +use warnings; +use strict; + +my $VERSION = '0.2'; + +my $CC = $ENV{'CC'} || 'gcc'; +my $LINUX = '/usr/src/linux'; +my $MODE; +my $OUTPUT; +my @ARGS; +my $VERBOSE = 0; + +my $progname = $0; +$progname =~ s/^.*\///; +my $modename = $progname; + +sub usage +{ + my ($status) = @_; + if ($status) { + print STDERR "Try \`$0 --help' for more information\n"; + } else { + print < for Cluster File Systems. +EOF + } + exit $status; +} + +my @args = @ARGV; +while ($#args >= 0) { + if ($args[0] =~ /^--with-l(i(n(u(x)?)?)?)?=(.*)/) { + $LINUX = $5; + } elsif ($args[0] =~ /^--with-l(i(n(u(x)?)?)?)?$/) { + shift @args; + $LINUX = $args[0]; + } elsif ($args[0] =~ /^--h(e(l(p)?)?)?$/) { + usage(0); + } elsif ($args[0] =~ /^--vers(i(o(n)?)?)?$/) { + print "KABI $VERSION\n"; + exit 0; + } elsif ($args[0] eq '-v' || $args[0] =~ /^--verb(o(s(e)?)?)?$/) { + $VERBOSE = 1; + } elsif ($args[0] =~ /^-/) { + print STDERR "$progname: unrecognized option \`$args[0]'\n"; + usage(1); + } elsif (!defined $MODE) { + $MODE = $args[0]; + } else { + push @ARGS, $args[0]; + } + shift @args; +} + + +if (!defined $MODE) { + print STDERR "$progname: you must specify a MODE\n"; + usage(1); +} + +$modename .= ": $MODE"; +if ($MODE eq 'archive') { + if ($#ARGS != 1) { + print STDERR "$modename: you must specify a DIR and KMOD\n"; + usage(1); + } + + my $ARCHIVE = $ARGS[0]; + my $KMOD = $ARGS[1]; + + my $KABI = $KMOD; + $KABI =~ s/\.k?o$//; + $KABI .= '.kabi'; + + open(MD5SUM, "md5sum $KABI|") or + die "$modename: cannot execute \`md5sum': $!\n"; + my $hash = ; + close(MD5SUM); + $hash =~ s/\s+.*//s; + + my $TAG = ''; + if (-d 'CVS') { + open(TAG, '; + close(TAG); + chomp $TAG; + $TAG = "/$TAG"; + } + + my ($dir, @sh_c, @cp); + if ($ARCHIVE =~ /^([^:][^:]+):(.*)$/) { + $dir = $2; + @sh_c = ('ssh', '-o', 'BatchMode=yes', $1); + @cp = ('scp', '-B'); + } else { + $dir = $ARCHIVE; + @sh_c = ('sh', '-c'); + @cp = ('cp'); + } + + system(@sh_c, "test -d $dir"); + if ($? >> 8 != 0) { + print STDERR "$modename: warning: \`$dir' is not reachable or does not exist\n"; + exit 0; + } + + print "archiving $KMOD in $ARCHIVE$TAG/$KMOD/$hash\n" + if $VERBOSE; + foreach my $d ("$dir$TAG", "$dir$TAG/$KMOD", "$dir$TAG/$KMOD/$hash") { + system(@sh_c, "test -d $d || mkdir $d"); + if ($? >> 8 != 0) { + exit $? >> 8; + } + } + system(@cp, $KMOD, $KABI, "$ARCHIVE$TAG/$KMOD/$hash"); + exit $? >> 8; +} elsif ($MODE eq 'module') { + + if ($#ARGS != 0) { + print STDERR "$modename: you must specify exactly one KMOD\n"; + usage(1); + } + + my $KMOD = $ARGS[0]; + + if (!defined $OUTPUT) { + $OUTPUT = $KMOD; + $OUTPUT =~ s/\.k?o$//; + $OUTPUT .= '.kabi'; + } + print "create $OUTPUT\n" if $VERBOSE; + open(OUT, ">$OUTPUT") or + die "$modename: cannot create \`$OUTPUT': $!\n"; + + my $outname = $OUTPUT; + $outname =~ s/^.*\///; + print OUT <) { + if (/\"__versions\"/) { + $versions = 1; + } elsif ($versions) { + if (/^\s*\{\s*(0x[0-9a-f]+)\s*,\s*\"([^\"]*)\"\s*\}\s*,\s*$/) { + $vers{$2} = $1; + push(@undefs, $2); + } elsif (/^\s*\}\s*;\s*$/) { + $versions = 0; + } + } + } + close(MOD); + } else { + open(NM, "nm $KMOD |") or + die "$modename: cannot execute \`nm $KMOD': $!\n"; + while ($_ = ) { + if (/^\s*U\s*(.*\S)\s*$/) { + push @undefs, $1; + } + } + close(NM); + } + + foreach my $undef (sort @undefs) + { + print OUT "usym $undef"; + if (defined $vers{$undef}) { + print OUT " ", $vers{$undef}; + } + print OUT "\n"; + } + + close(OUT) or + die "$modename: cannot write \`$OUTPUT': $!\n"; + +} elsif ($MODE eq 'match') { + my @KABIS; + my @KMODS; + + my @todo = @ARGS; + while ($#todo >= 0) { + my $t = shift @todo; + if ($t =~ /\.kabi$/) { + push @KABIS, $t; + } elsif (-d $t) { + # Add all the contents of the directory to our todo list. + opendir(DIR, $t); + while (my $ent = readdir(DIR)) { + if ($ent =~ /^\./) { + # Skip dotfiles. + } elsif (-d "$t/$ent") { + # Recurse into subdirectories. + unshift @todo, "$t/$ent"; + } elsif ($ent =~ /\.k?o$/) { + # Add kernel modules. + unshift @todo, "$t/$ent"; + } + } + closedir(DIR); + } else { + # It's an explicit kernel module. + push @KMODS, $t; + } + } + + if ($#KABIS < 0) { + print STDERR "$modename: you must specify at least one KABI\n"; + usage(1); + } + + my %dsyms; + + if (-f "$LINUX/Module.symvers") { + # Look up the version numbers in Module.symvers. + open(VERS, "<$LINUX/Module.symvers") or + die "$modename: cannot read \`$LINUX/Module.symvers': $!\n"; + while ($_ = ) { + if (/^(0x[0-9a-f]+)\s+(\S+)/) { + $dsyms{$2} = hex($1); + } + } + close(VERS); + } else { + # Read in all the non-versioned symbols defined by this kernel. + open(MAP, "<$LINUX/System.map") or + die "$modename: cannot read \`$LINUX/System.map': $!\n"; + while ($_ = ) { + if (/^[0-9a-fA-F]*\s+[ABCDGIRSTW]+\s*(.*\S)\s*$/) { + $dsyms{$1} = 0; + } + } + close(MAP); + } + + # Find the symbols for the installed modules, too. + foreach my $mod (@KMODS) { + open(NM, "nm $mod |") or + die "$modename: cannot execute \`nm $mod': $!\n"; + while ($_ = ) { + if (/^[0-9a-fA-F]*\s+[ABCDGIRSTW]+\s*(.*\S)\s*$/) { + $dsyms{$1} = 0; + } + } + close(NM); + } + + # Also get the kernel version. + my $kver = kernel_version(); + + # Read each kabi file and print out the ones that are plausible + # matches. + foreach my $kabi (@KABIS) { + open(KABI, "<$kabi") or + die "$modename: cannot read \`$kabi': $!\n"; + my $possible = 1; + while ($possible && ($_ = )) { + if (/^\s*#/) { + # Skip comments. + } elsif (/^\s*kver\s+(.*\S)\s*$/) { + my $modkver = $1; + if ($modkver ne $kver) { + print STDERR "$kabi:$.: module version \`$modkver' differs from \`$kver'\n" + if $VERBOSE; + $possible = 0; + } + } elsif (/^\s*usym\s+(\S+)\s*(\S+)?\s*$/) { + my ($modsym, $symver) = ($1, hex($2)); + if (!defined $dsyms{$modsym}) { + print STDERR "$kabi:$.: module symbol \`$modsym' is not defined\n" + if $VERBOSE; + $possible = 0; + } elsif (defined $symver && $dsyms{$modsym} != 0 && $dsyms{$modsym} != $symver) { + printf STDERR "$kabi:$.: module symbol \`$modsym' is version 0x%x, not 0x%x\n", $dsyms{$modsym}, $symver + if $VERBOSE; + $possible = 0; + } + } elsif (/^\s*(\S+)/) { + print STDERR "$kabi:$.: unrecognized descriptor line \`$1'\n"; + } + } + close(KABI); + + if ($possible) { + # We got a match. + print "$kabi\n"; + } + } + +} else { + print STDERR "$progname: unrecognized mode \`$MODE'\n"; + usage(1); +} + + +# Read the kernel version from its built source tree. +sub kernel_version +{ + my $verfile = "$LINUX/include/linux/version.h"; + open(VERSION, "<$verfile") or + die "$modename: cannot read \`$verfile': $!\n"; + + my $ver; + while ($_ = ) { + if (/^\s*#\s*define\s+UTS_RELEASE\s+"(.*)"\s*$/) { + $ver = $1; + last; + } + } + + close(VERSION); + + if (!defined $ver) { + die "$modename: cannot find UTS_RELEASE in \`$verfile'\n"; + } + return "linux-$ver"; +} + +exit 0; -- 1.8.3.1