-#!/usr/bin/perl -w
-#
-# Copyright (c) 2001-2008 Silicon Graphics, Inc. All Rights Reserved.
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it would be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-#
-#
-# srcdiff is used to compare current user level code with the current
-# kernel code and advise of any differences between files which are
-# sharing some or all of their content.
-#
-# There are two classes of sharing which we will check - header files
-# in the include directory, which must be exactly the same (use diff)
-# and source files which contain routines which must be exactly the
-# same (but the userland file is always a subset of the kernel file,
-# and hence a more flexible mechanism to "diff" is required).
-#
-# NB: to cross check that srcdiff is finding all the functions in the
-# user source file, providing you have "mkproto" installed, you
-# can "cd xfsprogs/libxfs" and cut&paste this in a bourne shell:
-# $ for file in xfs_*.c; do
-# > mkproto -nps < $file | perl -ne '
-# > END { print " $count\t- " }
-# > s/^.* (xfs\w+|\*xfs\w+|xlog\w+|\*xlog\w+) \(.*/\1/ && { $count++ }'
-# > echo $file
-# > done
-# (compare this to "srcdiff | fgrep Total:")
-#
-
-use strict;
-
-die "WORKAREA not set" unless defined $ENV{'WORKAREA'};
-die "KWORKAREA not set" unless defined $ENV{'KWORKAREA'};
-die "DMWORKAREA not set" unless defined $ENV{'DMWORKAREA'};
-chdir $ENV{'WORKAREA'};
-my $dmworkarea = $ENV{'DMWORKAREA'};
-my $kworkarea = $ENV{'KWORKAREA'};
-my $xdiff = $ENV{'XDIFF'};
-my $quiet = 0;
-my $usage = 0;
-
-if ( ! -f "$kworkarea/xfs_fs.h" ) {
- $kworkarea .= '/fs/xfs';
- die "Cannot find XFS in KWORKAREA" unless -f "$kworkarea/xfs_fs.h";
-}
-die "Cannot find DMAPI in DMWORKAREA" unless -f "$dmworkarea/dmapi.h";
-
-foreach (@ARGV) {
- if (/^-q$/) {
- $quiet++;
- } else {
- print STDERR "Illegal option $_\n";
- $usage++;
- }
-}
-
-if ($usage) {
- print STDERR "Usage: $0 [-q]\n";
- exit 1;
-}
-
-my @pkglist = qw( xfstests attr acl dmapi xfsdump xfsprogs );
-my @difflist = qw(
- xfs_ag.h xfs_alloc.h xfs_alloc_btree.h xfs_arch.h
- xfs_attr_leaf.h xfs_attr_sf.h xfs_bit.h xfs_bmap.h
- xfs_bmap_btree.h xfs_btree.h xfs_buf_item.h
- xfs_da_btree.h xfs_dfrag.h xfs_dinode.h
- xfs_dir2.h xfs_dir2_block.h xfs_dir2_data.h
- xfs_dir2_leaf.h xfs_dir2_node.h xfs_dir2_sf.h
- xfs_extfree_item.h xfs_ialloc.h
- xfs_imap.h xfs_ialloc_btree.h xfs_inode.h xfs_inode_item.h
- xfs_inum.h xfs_log.h xfs_log_priv.h xfs_log_recover.h
- xfs_mount.h xfs_quota.h xfs_rtalloc.h
- xfs_sb.h xfs_trans.h xfs_trans_space.h xfs_types.h xfs_fs.h
-);
-
-sub straightdiff {
- my ( $file, $prefix1, $prefix2 ) = @_;
-
- `diff $prefix1/$file $prefix2/$file >/dev/null 2>&1`;
- if (!$quiet) {
- print sprintf("\t%-35s ... ", $file);
- if ($? != 0) { printf("FAILED\n(%s/%s differs to %s/%s)\n",
- $prefix1, $file, $prefix2, $file); }
- else { print "ok\n"; }
- } elsif ($? != 0) {
- printf("\t%-35s ... FAILED\n(%s/%s differs to %s/%s)\n",
- $file, $prefix1, $file, $prefix2, $file);
- if (defined($xdiff)) {
- `$xdiff $prefix1/$file $prefix2/$file`;
- }
- }
-}
-
-#
-# xfstests directory m4 directory is a repository of all of the
-# custom m4 macros used in the packages we look after.
-#
-sub m4macrodiff {
- my ( $package ) = @_;
-
- foreach (`ls $package/m4/*.m4`) {
- my $m4 = `basename $_`;
- chomp($m4);
- straightdiff $m4, "$package/m4", "xfstests/m4";
- }
-}
-
-my $first = shift @pkglist;
-foreach (@pkglist) {
- print "\n=== Checking $_ package ===\n";
- m4macrodiff $_;
- straightdiff 'buildrules', "$first/include", "$_/include";
- straightdiff 'buildmacros', "$first/include", "$_/include";
- straightdiff 'Makefile', "$first/build", "$_/build";
- straightdiff 'Makefile', "$first/build/rpm", "$_/build/rpm";
- straightdiff 'Makefile', "$first/build/tar", "$_/build/tar";
-}
-print "\n=== Checking headers ===\n";
-foreach (@difflist) {
- straightdiff $_, 'xfsprogs/include', "$kworkarea";
-}
-straightdiff 'dmapi_kern.h', 'dmapi/include', "$dmworkarea";
-straightdiff 'dmapi.h', 'dmapi/include', "$dmworkarea";
-
-#
-# setstate
-# Implements a tri-state FSA, see comments for state transitions
-# (knows about the way the XFS kernel code is written, & makes
-# some assumptions so as to not need to parse generic C code).
-# Accepts one line at a time from a source file, picking out the
-# function bodies so they can be subsequently compared.
-#
-
-my $line; # line number in current source file
-my $state; # current FSA state
-my $funcbody; # current function body (contents)
-
-sub setstate {
- my ( $newline ) = @_;
- $line++;
-
- # - state 0:
- # if line looks like start of a function, transition to 1
- # & squirrel line away as line 1 of current function
- if ($state == 0) {
- if ($newline =~ m/^[xfs|xlog]/) {
- $state = 1;
- $funcbody = $newline;
- }
- }
-
- # - state 1:
- # if line looks like start of a function, stay here
- # & squirrel line away as line 1 of current function
- # otherwise if line isn't start of function body,
- # squirrel line away as next line of current function
- # (args/..., but not sure this is a real function yet)
- # otherwise (start of function)
- # squirrel line away as next line of current function
- # transition to state 2
- elsif ($state == 1) {
- if ($newline =~ m/^[xfs|xlog]/) {
- $funcbody = $newline;
- }
- elsif ($newline =~ m/^\{/) {
- $state = 2;
- $funcbody .= $newline;
- }
- }
-
- # - state 2:
- # if line looks like end of function body,
- # squirrel line away as last line of current function
- # tell someone we have a complete function ready
- # transition to state 0
- # otherwise
- # squirrel line away as next line of current function
- elsif ($state == 2) {
- $funcbody .= $newline;
- if ($newline =~ m/^\}/) {
- $state = 0;
- return $funcbody;
- }
- }
-
- else {
- die "unknown state transition";
- }
- return undef; # i.e. not at end of a function
-}
-
-sub listfuncs {
- my ( $file ) = @_;
- my @funcs;
-
- $funcbody = '';
- $state = $line = 0;
-
- open(USER, "$file") || die "cannot open $file";
- while (<USER>) {
- my $func = setstate($_);
- push @funcs, $func if (defined($func)); # store function away
- }
- close USER;
- return @funcs;
-}
-
-sub hashfuncs {
- my ( $file ) = @_;
- my %funcs;
-
- $funcbody = '';
- $state = $line = 0;
-
- open(KERN, "$file") || die "cannot open $file";
- while (<KERN>) {
- my $func = setstate($_);
- if (defined($func)) {
- $func =~ m/^([xfs|xlog]\w+)\s*\(/;
- next unless defined($1);
- my $name = $1;
- if (defined($func)) {
- $funcs{$name} = $func; # store function away
- }
- }
- }
- close KERN;
- return %funcs;
-}
-
-sub diffme {
- my ( $sa, $sb ) = @_;
-
- return unless defined($xdiff);
-
- open(FILEA, "> /tmp/diff.user.$$") || die "cannot write to /tmp/diff.user.$$";
- open(FILEB, "> /tmp/diff.kern.$$") || die "cannot write to /tmp/diff.kern.$$";
- print FILEA $sa;
- print FILEB $sb;
- close FILEA;
- close FILEB;
- `$xdiff /tmp/diff.user.$$ /tmp/diff.kern.$$`;
- unlink ("/tmp/diff.user.$$","/tmp/diff.kern.$$");
-}
-
-sub functiondiff {
- my ( $file, $prefix1, $prefix2 ) = @_;
- my $plural = '';
- my $count = 0;
- my $name;
- my $found = 0;
-
- print "\n=== Checking $file routines ===\n" unless ($quiet);
-
- # iterate over user funcs, match up to kernel funcs
- #
- my @user = listfuncs "$prefix1/$file";
- my %kern = hashfuncs "$prefix2/$file";
-
- foreach my $userfunc (@user) {
-
- $userfunc =~ m/^([xfs|xlog]\w+)\s*\(/;
- next unless (defined($1));
- $name = $1;
- $count++;
-
- if (exists($kern{$name})) {
- if ($userfunc ne $kern{$name}) {
- print "\n=== $file routines ===\n"
- if (!$found++ && $quiet);
-
- printf("\t%-35s ... ", $name);
- print "FAILED\n";
- diffme $userfunc, $kern{$name};
- }
- elsif (!$quiet) {
- printf("\t%-35s ... ", $name);
- print "ok\n";
- }
- }
- else {
- print "Cannot find kernel function $userfunc";
- print " in file $prefix2/$file\n";
- }
- }
- ($count != 1) && ( $plural = 's' );
- print "( Total: $count routine$plural checked in $file )\n" unless ($quiet);
-}
-
-# xfsprogs/{libxfs,libxlog}/* fs/xfs/*
-my @funclist = qw(
- xfs_alloc.c xfs_alloc_btree.c xfs_attr.c xfs_attr_leaf.c
- xfs_bmap.c xfs_bmap_btree.c xfs_btree.c xfs_da_btree.c
- xfs_dir2.c xfs_dir2_block.c xfs_dir2_data.c xfs_dir2_leaf.c
- xfs_dir2_node.c xfs_dir2_sf.c xfs_ialloc.c xfs_ialloc_btree.c
- xfs_inode.c xfs_mount.c xfs_rtalloc.c xfs_trans.c
-);
-
-print "\n=== Checking libxfs code ===\n";
-foreach (@funclist) {
- functiondiff $_, 'xfsprogs/libxfs', "$kworkarea";
-}
-print "\n=== Checking libxlog code ===\n";
-functiondiff 'xfs_log_recover.c', 'xfsprogs/libxlog', "$kworkarea";