linux/scripts/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 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
  22use warnings;
  23use strict;
  24use File::Basename;
  25
  26my ($dir, $arch, @files) = @ARGV;
  27
  28my $ret = 0;
  29my $line;
  30my $lineno = 0;
  31my $filename;
  32
  33foreach 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}
  49exit $ret;
  50
  51sub 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
  68sub 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
  85sub 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
  92my $linux_asm_types;
  93sub 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
 112my $linux_types;
 113my %import_stack = ();
 114sub 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
 146sub 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}
 172