1#!/usr/bin/perl -w
2#
3# headers_check.pl execute a number of trivial consistency checks
4#
5# Usage: headers_check.pl dir arch [files...]
6# dir:   dir to look for included files
7# arch:  architecture
8# files: list of files to check
9#
10# The script reads the supplied files line by line and:
11#
12# 1) for each include statement it checks if the
13#    included file actually exists.
14#    Only include files located in asm* and linux* are checked.
15#    The rest are assumed to be system include files.
16#
17# 2) It is checked that prototypes does not use "extern"
18#
19# 3) Check for leaked CONFIG_ symbols
20
21use strict;
22
23my ($dir, $arch, @files) = @ARGV;
24
25my $ret = 0;
26my $line;
27my $lineno = 0;
28my $filename;
29
30foreach my $file (@files) {
31	$filename = $file;
32
33	open(my $fh, '<', $filename)
34		or die "$filename: $!\n";
35	$lineno = 0;
36	while ($line = <$fh>) {
37		$lineno++;
38		&check_include();
39		&check_asm_types();
40		&check_sizetypes();
41		&check_declarations();
42		# Dropped for now. Too much noise &check_config();
43	}
44	close $fh;
45}
46exit $ret;
47
48sub check_include
49{
50	if ($line =~ m/^\s*#\s*include\s+<((asm|linux).*)>/) {
51		my $inc = $1;
52		my $found;
53		$found = stat($dir . "/" . $inc);
54		if (!$found) {
55			$inc =~ s#asm/#asm-$arch/#;
56			$found = stat($dir . "/" . $inc);
57		}
58		if (!$found) {
59			printf STDERR "$filename:$lineno: included file '$inc' is not exported\n";
60			$ret = 1;
61		}
62	}
63}
64
65sub check_declarations
66{
67	if ($line =~m/^(\s*extern|unsigned|char|short|int|long|void)\b/) {
68		printf STDERR "$filename:$lineno: " .
69			      "userspace cannot reference function or " .
70			      "variable defined in the kernel\n";
71	}
72}
73
74sub check_config
75{
76	if ($line =~ m/[^a-zA-Z0-9_]+CONFIG_([a-zA-Z0-9_]+)[^a-zA-Z0-9_]/) {
77		printf STDERR "$filename:$lineno: leaks CONFIG_$1 to userspace where it is not valid\n";
78	}
79}
80
81my $linux_asm_types;
82sub check_asm_types
83{
84	if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) {
85		return;
86	}
87	if ($lineno == 1) {
88		$linux_asm_types = 0;
89	} elsif ($linux_asm_types >= 1) {
90		return;
91	}
92	if ($line =~ m/^\s*#\s*include\s+<asm\/types.h>/) {
93		$linux_asm_types = 1;
94		printf STDERR "$filename:$lineno: " .
95		"include of <linux/types.h> is preferred over <asm/types.h>\n"
96		# Warn until headers are all fixed
97		#$ret = 1;
98	}
99}
100
101my $linux_types;
102sub check_sizetypes
103{
104	if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) {
105		return;
106	}
107	if ($lineno == 1) {
108		$linux_types = 0;
109	} elsif ($linux_types >= 1) {
110		return;
111	}
112	if ($line =~ m/^\s*#\s*include\s+<linux\/types.h>/) {
113		$linux_types = 1;
114		return;
115	}
116	if ($line =~ m/__[us](8|16|32|64)\b/) {
117		printf STDERR "$filename:$lineno: " .
118		              "found __[us]{8,16,32,64} type " .
119		              "without #include <linux/types.h>\n";
120		$linux_types = 2;
121		# Warn until headers are all fixed
122		#$ret = 1;
123	}
124}
125
126