linux/usr/include/headers_check.pl
<<
>>
Prefs
   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