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