162306a36Sopenharmony_ci#!/usr/bin/env perl
262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0
362306a36Sopenharmony_ci#
462306a36Sopenharmony_ci# headers_check.pl execute a number of trivial consistency checks
562306a36Sopenharmony_ci#
662306a36Sopenharmony_ci# Usage: headers_check.pl dir arch [files...]
762306a36Sopenharmony_ci# dir:   dir to look for included files
862306a36Sopenharmony_ci# arch:  architecture
962306a36Sopenharmony_ci# files: list of files to check
1062306a36Sopenharmony_ci#
1162306a36Sopenharmony_ci# The script reads the supplied files line by line and:
1262306a36Sopenharmony_ci#
1362306a36Sopenharmony_ci# 1) for each include statement it checks if the
1462306a36Sopenharmony_ci#    included file actually exists.
1562306a36Sopenharmony_ci#    Only include files located in asm* and linux* are checked.
1662306a36Sopenharmony_ci#    The rest are assumed to be system include files.
1762306a36Sopenharmony_ci#
1862306a36Sopenharmony_ci# 2) It is checked that prototypes does not use "extern"
1962306a36Sopenharmony_ci#
2062306a36Sopenharmony_ci# 3) Check for leaked CONFIG_ symbols
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ciuse warnings;
2362306a36Sopenharmony_ciuse strict;
2462306a36Sopenharmony_ciuse File::Basename;
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cimy ($dir, $arch, @files) = @ARGV;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cimy $ret = 0;
2962306a36Sopenharmony_cimy $line;
3062306a36Sopenharmony_cimy $lineno = 0;
3162306a36Sopenharmony_cimy $filename;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ciforeach my $file (@files) {
3462306a36Sopenharmony_ci	$filename = $file;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	open(my $fh, '<', $filename)
3762306a36Sopenharmony_ci		or die "$filename: $!\n";
3862306a36Sopenharmony_ci	$lineno = 0;
3962306a36Sopenharmony_ci	while ($line = <$fh>) {
4062306a36Sopenharmony_ci		$lineno++;
4162306a36Sopenharmony_ci		&check_include();
4262306a36Sopenharmony_ci		&check_asm_types();
4362306a36Sopenharmony_ci		&check_sizetypes();
4462306a36Sopenharmony_ci		&check_declarations();
4562306a36Sopenharmony_ci		# Dropped for now. Too much noise &check_config();
4662306a36Sopenharmony_ci	}
4762306a36Sopenharmony_ci	close $fh;
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ciexit $ret;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cisub check_include
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	if ($line =~ m/^\s*#\s*include\s+<((asm|linux).*)>/) {
5462306a36Sopenharmony_ci		my $inc = $1;
5562306a36Sopenharmony_ci		my $found;
5662306a36Sopenharmony_ci		$found = stat($dir . "/" . $inc);
5762306a36Sopenharmony_ci		if (!$found) {
5862306a36Sopenharmony_ci			$inc =~ s#asm/#asm-$arch/#;
5962306a36Sopenharmony_ci			$found = stat($dir . "/" . $inc);
6062306a36Sopenharmony_ci		}
6162306a36Sopenharmony_ci		if (!$found) {
6262306a36Sopenharmony_ci			printf STDERR "$filename:$lineno: included file '$inc' is not exported\n";
6362306a36Sopenharmony_ci			$ret = 1;
6462306a36Sopenharmony_ci		}
6562306a36Sopenharmony_ci	}
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cisub check_declarations
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	# soundcard.h is what it is
7162306a36Sopenharmony_ci	if ($line =~ m/^void seqbuf_dump\(void\);/) {
7262306a36Sopenharmony_ci		return;
7362306a36Sopenharmony_ci	}
7462306a36Sopenharmony_ci	# drm headers are being C++ friendly
7562306a36Sopenharmony_ci	if ($line =~ m/^extern "C"/) {
7662306a36Sopenharmony_ci		return;
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci	if ($line =~ m/^(\s*extern|unsigned|char|short|int|long|void)\b/) {
7962306a36Sopenharmony_ci		printf STDERR "$filename:$lineno: " .
8062306a36Sopenharmony_ci			      "userspace cannot reference function or " .
8162306a36Sopenharmony_ci			      "variable defined in the kernel\n";
8262306a36Sopenharmony_ci	}
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cisub check_config
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	if ($line =~ m/[^a-zA-Z0-9_]+CONFIG_([a-zA-Z0-9_]+)[^a-zA-Z0-9_]/) {
8862306a36Sopenharmony_ci		printf STDERR "$filename:$lineno: leaks CONFIG_$1 to userspace where it is not valid\n";
8962306a36Sopenharmony_ci	}
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cimy $linux_asm_types;
9362306a36Sopenharmony_cisub check_asm_types
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) {
9662306a36Sopenharmony_ci		return;
9762306a36Sopenharmony_ci	}
9862306a36Sopenharmony_ci	if ($lineno == 1) {
9962306a36Sopenharmony_ci		$linux_asm_types = 0;
10062306a36Sopenharmony_ci	} elsif ($linux_asm_types >= 1) {
10162306a36Sopenharmony_ci		return;
10262306a36Sopenharmony_ci	}
10362306a36Sopenharmony_ci	if ($line =~ m/^\s*#\s*include\s+<asm\/types.h>/) {
10462306a36Sopenharmony_ci		$linux_asm_types = 1;
10562306a36Sopenharmony_ci		printf STDERR "$filename:$lineno: " .
10662306a36Sopenharmony_ci		"include of <linux/types.h> is preferred over <asm/types.h>\n"
10762306a36Sopenharmony_ci		# Warn until headers are all fixed
10862306a36Sopenharmony_ci		#$ret = 1;
10962306a36Sopenharmony_ci	}
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cimy $linux_types;
11362306a36Sopenharmony_cimy %import_stack = ();
11462306a36Sopenharmony_cisub check_include_typesh
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	my $path = $_[0];
11762306a36Sopenharmony_ci	my $import_path;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	my $fh;
12062306a36Sopenharmony_ci	my @file_paths = ($path, $dir . "/" .  $path, dirname($filename) . "/" . $path);
12162306a36Sopenharmony_ci	for my $possible ( @file_paths ) {
12262306a36Sopenharmony_ci	    if (not $import_stack{$possible} and open($fh, '<', $possible)) {
12362306a36Sopenharmony_ci		$import_path = $possible;
12462306a36Sopenharmony_ci		$import_stack{$import_path} = 1;
12562306a36Sopenharmony_ci		last;
12662306a36Sopenharmony_ci	    }
12762306a36Sopenharmony_ci	}
12862306a36Sopenharmony_ci	if (eof $fh) {
12962306a36Sopenharmony_ci	    return;
13062306a36Sopenharmony_ci	}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	my $line;
13362306a36Sopenharmony_ci	while ($line = <$fh>) {
13462306a36Sopenharmony_ci		if ($line =~ m/^\s*#\s*include\s+<linux\/types.h>/) {
13562306a36Sopenharmony_ci			$linux_types = 1;
13662306a36Sopenharmony_ci			last;
13762306a36Sopenharmony_ci		}
13862306a36Sopenharmony_ci		if (my $included = ($line =~ /^\s*#\s*include\s+[<"](\S+)[>"]/)[0]) {
13962306a36Sopenharmony_ci			check_include_typesh($included);
14062306a36Sopenharmony_ci		}
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci	close $fh;
14362306a36Sopenharmony_ci	delete $import_stack{$import_path};
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cisub check_sizetypes
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) {
14962306a36Sopenharmony_ci		return;
15062306a36Sopenharmony_ci	}
15162306a36Sopenharmony_ci	if ($lineno == 1) {
15262306a36Sopenharmony_ci		$linux_types = 0;
15362306a36Sopenharmony_ci	} elsif ($linux_types >= 1) {
15462306a36Sopenharmony_ci		return;
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci	if ($line =~ m/^\s*#\s*include\s+<linux\/types.h>/) {
15762306a36Sopenharmony_ci		$linux_types = 1;
15862306a36Sopenharmony_ci		return;
15962306a36Sopenharmony_ci	}
16062306a36Sopenharmony_ci	if (my $included = ($line =~ /^\s*#\s*include\s+[<"](\S+)[>"]/)[0]) {
16162306a36Sopenharmony_ci		check_include_typesh($included);
16262306a36Sopenharmony_ci	}
16362306a36Sopenharmony_ci	if ($line =~ m/__[us](8|16|32|64)\b/) {
16462306a36Sopenharmony_ci		printf STDERR "$filename:$lineno: " .
16562306a36Sopenharmony_ci		              "found __[us]{8,16,32,64} type " .
16662306a36Sopenharmony_ci		              "without #include <linux/types.h>\n";
16762306a36Sopenharmony_ci		$linux_types = 2;
16862306a36Sopenharmony_ci		# Warn until headers are all fixed
16962306a36Sopenharmony_ci		#$ret = 1;
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci}
172