headers_check.pl 3.73 KB
Newer Older
1
#!/usr/bin/env perl
2
# SPDX-License-Identifier: GPL-2.0
3 4 5
#
# headers_check.pl execute a number of trivial consistency checks
#
6
# Usage: headers_check.pl dir arch [files...]
7 8 9 10 11 12 13 14 15 16 17
# 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.
#
18 19
# 2) It is checked that prototypes does not use "extern"
#
20
# 3) Check for leaked CONFIG_ symbols
21

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

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

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

foreach my $file (@files) {
	$filename = $file;
35 36 37

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

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

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

92
my $linux_asm_types;
93
sub check_asm_types
94
{
95 96 97
	if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) {
		return;
	}
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
	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;
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 144 145
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};
}

146 147
sub check_sizetypes
{
148 149 150
	if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) {
		return;
	}
151 152 153 154 155 156 157 158 159
	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;
	}
160 161 162
	if (my $included = ($line =~ /^\s*#\s*include\s+[<"](\S+)[>"]/)[0]) {
		check_include_typesh($included);
	}
163 164 165 166 167 168 169 170 171
	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;
	}
}