headers_check.pl 3.68 KB
Newer Older
1
#!/usr/bin/perl -w
2 3 4
#
# headers_check.pl execute a number of trivial consistency checks
#
5
# Usage: headers_check.pl dir arch [files...]
6 7 8 9 10 11 12 13 14 15 16
# dir:   dir to look for included files
# arch:  architecture
# files: list of files to check
#
# The script reads the supplied files line by line and:
#
# 1) for each include statement it checks if the
#    included file actually exists.
#    Only include files located in asm* and linux* are checked.
#    The rest are assumed to be system include files.
#
17 18
# 2) It is checked that prototypes does not use "extern"
#
19
# 3) Check for leaked CONFIG_ symbols
20 21

use strict;
22
use File::Basename;
23 24 25 26 27 28 29 30 31 32

my ($dir, $arch, @files) = @ARGV;

my $ret = 0;
my $line;
my $lineno = 0;
my $filename;

foreach my $file (@files) {
	$filename = $file;
33 34 35

	open(my $fh, '<', $filename)
		or die "$filename: $!\n";
36
	$lineno = 0;
37
	while ($line = <$fh>) {
38
		$lineno++;
39 40 41
		&check_include();
		&check_asm_types();
		&check_sizetypes();
42
		&check_declarations();
43
		# Dropped for now. Too much noise &check_config();
44
	}
45
	close $fh;
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
}
exit $ret;

sub check_include
{
	if ($line =~ m/^\s*#\s*include\s+<((asm|linux).*)>/) {
		my $inc = $1;
		my $found;
		$found = stat($dir . "/" . $inc);
		if (!$found) {
			$inc =~ s#asm/#asm-$arch/#;
			$found = stat($dir . "/" . $inc);
		}
		if (!$found) {
			printf STDERR "$filename:$lineno: included file '$inc' is not exported\n";
			$ret = 1;
		}
	}
}
65

66
sub check_declarations
67
{
68 69 70 71
	# soundcard.h is what it is
	if ($line =~ m/^void seqbuf_dump\(void\);/) {
		return;
	}
72 73 74 75
	# drm headers are being C++ friendly
	if ($line =~ m/^extern "C"/) {
		return;
	}
76
	if ($line =~ m/^(\s*extern|unsigned|char|short|int|long|void)\b/) {
77
		printf STDERR "$filename:$lineno: " .
78 79
			      "userspace cannot reference function or " .
			      "variable defined in the kernel\n";
80 81
	}
}
82 83 84

sub check_config
{
85
	if ($line =~ m/[^a-zA-Z0-9_]+CONFIG_([a-zA-Z0-9_]+)[^a-zA-Z0-9_]/) {
86 87 88 89
		printf STDERR "$filename:$lineno: leaks CONFIG_$1 to userspace where it is not valid\n";
	}
}

90
my $linux_asm_types;
91
sub check_asm_types
92
{
93 94 95
	if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) {
		return;
	}
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
	if ($lineno == 1) {
		$linux_asm_types = 0;
	} elsif ($linux_asm_types >= 1) {
		return;
	}
	if ($line =~ m/^\s*#\s*include\s+<asm\/types.h>/) {
		$linux_asm_types = 1;
		printf STDERR "$filename:$lineno: " .
		"include of <linux/types.h> is preferred over <asm/types.h>\n"
		# Warn until headers are all fixed
		#$ret = 1;
	}
}

my $linux_types;
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
my %import_stack = ();
sub check_include_typesh
{
	my $path = $_[0];
	my $import_path;

	my $fh;
	my @file_paths = ($path, $dir . "/" .  $path, dirname($filename) . "/" . $path);
	for my $possible ( @file_paths ) {
	    if (not $import_stack{$possible} and open($fh, '<', $possible)) {
		$import_path = $possible;
		$import_stack{$import_path} = 1;
		last;
	    }
	}
	if (eof $fh) {
	    return;
	}

	my $line;
	while ($line = <$fh>) {
		if ($line =~ m/^\s*#\s*include\s+<linux\/types.h>/) {
			$linux_types = 1;
			last;
		}
		if (my $included = ($line =~ /^\s*#\s*include\s+[<"](\S+)[>"]/)[0]) {
			check_include_typesh($included);
		}
	}
	close $fh;
	delete $import_stack{$import_path};
}

144 145
sub check_sizetypes
{
146 147 148
	if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) {
		return;
	}
149 150 151 152 153 154 155 156 157
	if ($lineno == 1) {
		$linux_types = 0;
	} elsif ($linux_types >= 1) {
		return;
	}
	if ($line =~ m/^\s*#\s*include\s+<linux\/types.h>/) {
		$linux_types = 1;
		return;
	}
158 159 160
	if (my $included = ($line =~ /^\s*#\s*include\s+[<"](\S+)[>"]/)[0]) {
		check_include_typesh($included);
	}
161 162 163 164 165 166 167 168 169
	if ($line =~ m/__[us](8|16|32|64)\b/) {
		printf STDERR "$filename:$lineno: " .
		              "found __[us]{8,16,32,64} type " .
		              "without #include <linux/types.h>\n";
		$linux_types = 2;
		# Warn until headers are all fixed
		#$ret = 1;
	}
}