1#!/usr/bin/env perl 2# SPDX-License-Identifier: GPL-2.0 3# 4# headers_check.pl execute a number of trivial consistency checks 5# 6# Usage: headers_check.pl dir [files...] 7# dir: dir to look for included files 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 warnings; 22use strict; 23use File::Basename; 24 25my ($dir, @files) = @ARGV; 26 27my $ret = 0; 28my $line; 29my $lineno = 0; 30my $filename; 31 32foreach my $file (@files) { 33 $filename = $file; 34 35 open(my $fh, '<', $filename) 36 or die "$filename: $!\n"; 37 $lineno = 0; 38 while ($line = <$fh>) { 39 $lineno++; 40 &check_include(); 41 &check_asm_types(); 42 &check_sizetypes(); 43 &check_declarations(); 44 # Dropped for now. Too much noise &check_config(); 45 } 46 close $fh; 47} 48exit $ret; 49 50sub check_include 51{ 52 if ($line =~ m/^\s*#\s*include\s+<((asm|linux).*)>/) { 53 my $inc = $1; 54 my $found; 55 $found = stat($dir . "/" . $inc); 56 if (!$found) { 57 printf STDERR "$filename:$lineno: included file '$inc' is not exported\n"; 58 $ret = 1; 59 } 60 } 61} 62 63sub check_declarations 64{ 65 # soundcard.h is what it is 66 if ($line =~ m/^void seqbuf_dump\(void\);/) { 67 return; 68 } 69 # drm headers are being C++ friendly 70 if ($line =~ m/^extern "C"/) { 71 return; 72 } 73 if ($line =~ m/^(\s*extern|unsigned|char|short|int|long|void)\b/) { 74 printf STDERR "$filename:$lineno: " . 75 "userspace cannot reference function or " . 76 "variable defined in the kernel\n"; 77 } 78} 79 80sub check_config 81{ 82 if ($line =~ m/[^a-zA-Z0-9_]+CONFIG_([a-zA-Z0-9_]+)[^a-zA-Z0-9_]/) { 83 printf STDERR "$filename:$lineno: leaks CONFIG_$1 to userspace where it is not valid\n"; 84 } 85} 86 87my $linux_asm_types; 88sub check_asm_types 89{ 90 if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) { 91 return; 92 } 93 if ($lineno == 1) { 94 $linux_asm_types = 0; 95 } elsif ($linux_asm_types >= 1) { 96 return; 97 } 98 if ($line =~ m/^\s*#\s*include\s+<asm\/types.h>/) { 99 $linux_asm_types = 1; 100 printf STDERR "$filename:$lineno: " . 101 "include of <linux/types.h> is preferred over <asm/types.h>\n" 102 # Warn until headers are all fixed 103 #$ret = 1; 104 } 105} 106 107my $linux_types; 108my %import_stack = (); 109sub check_include_typesh 110{ 111 my $path = $_[0]; 112 my $import_path; 113 114 my $fh; 115 my @file_paths = ($path, $dir . "/" . $path, dirname($filename) . "/" . $path); 116 for my $possible ( @file_paths ) { 117 if (not $import_stack{$possible} and open($fh, '<', $possible)) { 118 $import_path = $possible; 119 $import_stack{$import_path} = 1; 120 last; 121 } 122 } 123 if (eof $fh) { 124 return; 125 } 126 127 my $line; 128 while ($line = <$fh>) { 129 if ($line =~ m/^\s*#\s*include\s+<linux\/types.h>/) { 130 $linux_types = 1; 131 last; 132 } 133 if (my $included = ($line =~ /^\s*#\s*include\s+[<"](\S+)[>"]/)[0]) { 134 check_include_typesh($included); 135 } 136 } 137 close $fh; 138 delete $import_stack{$import_path}; 139} 140 141sub check_sizetypes 142{ 143 if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) { 144 return; 145 } 146 if ($lineno == 1) { 147 $linux_types = 0; 148 } elsif ($linux_types >= 1) { 149 return; 150 } 151 if ($line =~ m/^\s*#\s*include\s+<linux\/types.h>/) { 152 $linux_types = 1; 153 return; 154 } 155 if (my $included = ($line =~ /^\s*#\s*include\s+[<"](\S+)[>"]/)[0]) { 156 check_include_typesh($included); 157 } 158 if ($line =~ m/__[us](8|16|32|64)\b/) { 159 printf STDERR "$filename:$lineno: " . 160 "found __[us]{8,16,32,64} type " . 161 "without #include <linux/types.h>\n"; 162 $linux_types = 2; 163 # Warn until headers are all fixed 164 #$ret = 1; 165 } 166} 167