gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/seccomp/precompiledseccomp/precompile_gen.go (about)

     1  // Copyright 2023 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // precompile_gen generates a Go library that contains precompiled seccomp
    16  // programs.
    17  package main
    18  
    19  import (
    20  	_ "embed"
    21  	"fmt"
    22  	"os"
    23  	"sort"
    24  	"strings"
    25  
    26  	"gvisor.dev/gvisor/pkg/seccomp/precompiledseccomp"
    27  	"gvisor.dev/gvisor/runsc/flag"
    28  
    29  	// This import will be replaced by the one specified in the genrule,
    30  	// or removed if stubbed out in fastbuild mode.
    31  	"gvisor.dev/gvisor/pkg/seccomp/precompiledseccomp/example" // REPLACED_IMPORT_THIS_IS_A_LOAD_BEARING_COMMENT
    32  )
    33  
    34  //go:embed precompiled_lib.tmpl.go
    35  var precompiledLibTemplate []byte
    36  
    37  // Constants referring to how things are named in precompiled_lib.tmpl.go.
    38  const (
    39  	packageNameStandin            = "precompiled"
    40  	precompiledseccompPackageName = "precompiledseccomp"
    41  	registrationComment           = "PROGRAM_REGISTRATION_GOES_HERE_THIS_IS_A_LOAD_BEARING_COMMENT"
    42  	programsMapVarName            = "programs"
    43  )
    44  
    45  // Flags.
    46  var (
    47  	output      = flag.String("out", "/dev/stdout", "output file")
    48  	packageName = flag.String("package", "", "output package name")
    49  )
    50  
    51  // loadProgramsFn loads seccomp programs to be precompiled.
    52  // It may be nil when it is stubbed out in fastbuild mode.
    53  var loadProgramsFn = example.PrecompiledPrograms // PROGRAMS_FUNC_THIS_IS_A_LOAD_BEARING_COMMENT
    54  
    55  func main() {
    56  	flag.Parse()
    57  
    58  	// Get a sorted list of programs.
    59  	var programs []precompiledseccomp.Program
    60  	if loadProgramsFn != nil {
    61  		var err error
    62  		programs, err = loadProgramsFn()
    63  		if err != nil {
    64  			fmt.Fprintf(os.Stderr, "Cannot get list of programs to precompile: %v\n", err)
    65  			os.Exit(1)
    66  		}
    67  	}
    68  	programNames := make(map[string]struct{}, len(programs))
    69  	for _, program := range programs {
    70  		if _, alreadySeen := programNames[program.Name]; alreadySeen {
    71  			fmt.Fprintf(os.Stderr, "duplicate program name %q", program.Name)
    72  			os.Exit(1)
    73  		}
    74  		programNames[program.Name] = struct{}{}
    75  	}
    76  	sort.Slice(programs, func(i, j int) bool {
    77  		return programs[i].Name < programs[j].Name
    78  	})
    79  
    80  	// Open the output file.
    81  	outFile, err := os.Create(*output)
    82  	if err != nil {
    83  		fmt.Fprintf(os.Stderr, "Cannot open output file %q: %v\n", *output, err)
    84  		os.Exit(1)
    85  	}
    86  	defer outFile.Close()
    87  
    88  	// Write Go code to the output file.
    89  	processedPackageComment := false
    90  	packageStandinLine := fmt.Sprintf("package %s", packageNameStandin)
    91  	packageCommentPrefix := fmt.Sprintf("// Package %s ", packageNameStandin)
    92  	lines := strings.Split(string(precompiledLibTemplate), "\n")
    93  	for i := 0; i < len(lines); i++ {
    94  		line := lines[i]
    95  		switch {
    96  		case line == packageStandinLine:
    97  			fmt.Fprintf(outFile, "package %s\n", *packageName)
    98  		case !processedPackageComment && strings.HasPrefix(line, packageCommentPrefix):
    99  			// Do not output package comment, as this would conflict with
   100  			// other package comments from other files in the same package.
   101  			// Skip over all the next lines until we get to the "package" line.
   102  			for ; i+1 < len(lines) && !strings.HasPrefix(lines[i+1], "package "); i++ {
   103  			}
   104  			processedPackageComment = true
   105  		case strings.Contains(line, registrationComment):
   106  			var indent string
   107  			for {
   108  				var found bool
   109  				if line, found = strings.CutPrefix(line, "\t"); !found {
   110  					break
   111  				}
   112  				indent += "\t"
   113  			}
   114  			for _, program := range programs {
   115  				fmt.Fprint(outFile, program.Registration(indent, precompiledseccompPackageName, programsMapVarName))
   116  			}
   117  		default:
   118  			fmt.Fprintf(outFile, "%s\n", line)
   119  		}
   120  	}
   121  }