github.com/cilium/cilium@v1.16.2/tools/legacyhguardcheck/main.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package main
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"os"
    10  	"path"
    11  	"regexp"
    12  	"slices"
    13  
    14  	"github.com/cilium/cilium/pkg/safeio"
    15  )
    16  
    17  func main() {
    18  	if len(os.Args) < 2 {
    19  		fmt.Fprintln(os.Stderr, "Usage: legacyhguardcheck <path>")
    20  		os.Exit(1)
    21  	}
    22  
    23  	found, err := checkDir(os.Args[1])
    24  	if err != nil {
    25  		fmt.Fprintln(os.Stderr, err)
    26  		os.Exit(1)
    27  	}
    28  	if found {
    29  		fmt.Fprintln(os.Stderr, "Found legacy header guards, please replace with #pragma once or "+
    30  			"add to the exclude list of a false positive found in 'tools/legacyhguardcheck/main.go'")
    31  		os.Exit(1)
    32  	}
    33  }
    34  
    35  func checkDir(dirPath string) (bool, error) {
    36  	var guardFound bool
    37  
    38  	dir, err := os.ReadDir(dirPath)
    39  	if err != nil {
    40  		return false, err
    41  	}
    42  
    43  	for _, entry := range dir {
    44  		entryName := path.Join(dirPath, entry.Name())
    45  		if entry.IsDir() {
    46  			foundGuard, err := checkDir(entryName)
    47  			if err != nil {
    48  				return false, err
    49  			}
    50  			if foundGuard {
    51  				guardFound = true
    52  			}
    53  			continue
    54  		}
    55  
    56  		foundGuard, err := checkFile(entryName)
    57  		if err != nil {
    58  			return false, err
    59  		}
    60  		if foundGuard {
    61  			guardFound = true
    62  		}
    63  	}
    64  
    65  	return guardFound, nil
    66  }
    67  
    68  var ifndefRegex = regexp.MustCompile(`#ifndef\s+([A-Za-z0-9_]+)\s*\n#define ([A-Za-z0-9_]+)`)
    69  
    70  var exclude = []string{
    71  	"bpf/node_config.h",
    72  	"bpf/lib/clustermesh.h",
    73  	"bpf/include/linux/byteorder/big_endian.h",
    74  	"bpf/include/linux/byteorder/little_endian.h",
    75  	"bpf/tests/common.h",
    76  	"bpf/tests/bpf_skb_255_tests.c",
    77  	"bpf/tests/bpf_skb_511_tests.c",
    78  }
    79  
    80  func checkFile(filePath string) (bool, error) {
    81  	if slices.Contains(exclude, filePath) {
    82  		return false, nil
    83  	}
    84  
    85  	f, err := os.Open(filePath)
    86  	if err != nil {
    87  		return false, err
    88  	}
    89  	defer f.Close()
    90  
    91  	const MB = 1 << 20
    92  	content, err := safeio.ReadAllLimit(f, 128*MB)
    93  	if err != nil {
    94  		return false, err
    95  	}
    96  
    97  	for _, match := range ifndefRegex.FindAllSubmatch(content, -1) {
    98  		if bytes.Equal(match[1], match[2]) && bytes.HasPrefix(match[1], []byte("_")) {
    99  			i := bytes.Index(content, match[0])
   100  			line := bytes.Count(content[:i], []byte("\n")) + 1
   101  			fmt.Printf("Found legacy header guard with %s macro at %s:%d\n", match[1], filePath, line)
   102  			return true, nil
   103  		}
   104  	}
   105  
   106  	return false, nil
   107  }