golang.org/x/sys@v0.9.0/unix/linux/mksysnum.go (about)

     1  // Copyright 2018 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build ignore
     6  // +build ignore
     7  
     8  package main
     9  
    10  import (
    11  	"bufio"
    12  	"fmt"
    13  	"os"
    14  	"os/exec"
    15  	"regexp"
    16  	"strconv"
    17  	"strings"
    18  )
    19  
    20  var (
    21  	goos, goarch string
    22  )
    23  
    24  // cmdLine returns this programs's commandline arguments
    25  func cmdLine() string {
    26  	return "go run linux/mksysnum.go " + strings.Join(os.Args[1:], " ")
    27  }
    28  
    29  // goBuildTags returns build tags in the go:build format.
    30  func goBuildTags() string {
    31  	return fmt.Sprintf("%s && %s", goarch, goos)
    32  }
    33  
    34  // plusBuildTags returns build tags in the +build format.
    35  func plusBuildTags() string {
    36  	return fmt.Sprintf("%s,%s", goarch, goos)
    37  }
    38  
    39  func format(name string, num int, offset int) string {
    40  	if num > 999 {
    41  		// ignore deprecated syscalls that are no longer implemented
    42  		// https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/asm-generic/unistd.h?id=refs/heads/master#n716
    43  		return ""
    44  	}
    45  	name = strings.ToUpper(name)
    46  	num = num + offset
    47  	return fmt.Sprintf("	SYS_%s = %d;\n", name, num)
    48  }
    49  
    50  func checkErr(err error) {
    51  	if err != nil {
    52  		fmt.Fprintf(os.Stderr, "%v\n", err)
    53  		os.Exit(1)
    54  	}
    55  }
    56  
    57  // source string and substring slice for regexp
    58  type re struct {
    59  	str string   // source string
    60  	sub []string // matched sub-string
    61  }
    62  
    63  // Match performs regular expression match
    64  func (r *re) Match(exp string) bool {
    65  	r.sub = regexp.MustCompile(exp).FindStringSubmatch(r.str)
    66  	if r.sub != nil {
    67  		return true
    68  	}
    69  	return false
    70  }
    71  
    72  func main() {
    73  	// Get the OS and architecture (using GOARCH_TARGET if it exists)
    74  	goos = os.Getenv("GOOS")
    75  	goarch = os.Getenv("GOARCH_TARGET")
    76  	if goarch == "" {
    77  		goarch = os.Getenv("GOARCH")
    78  	}
    79  	// Check if GOOS and GOARCH environment variables are defined
    80  	if goarch == "" || goos == "" {
    81  		fmt.Fprintf(os.Stderr, "GOARCH or GOOS not defined in environment\n")
    82  		os.Exit(1)
    83  	}
    84  	// Check that we are using the new build system if we should
    85  	if os.Getenv("GOLANG_SYS_BUILD") != "docker" {
    86  		fmt.Fprintf(os.Stderr, "In the new build system, mksysnum should not be called directly.\n")
    87  		fmt.Fprintf(os.Stderr, "See README.md\n")
    88  		os.Exit(1)
    89  	}
    90  
    91  	cc := os.Getenv("CC")
    92  	if cc == "" {
    93  		fmt.Fprintf(os.Stderr, "CC is not defined in environment\n")
    94  		os.Exit(1)
    95  	}
    96  	args := os.Args[1:]
    97  	args = append([]string{"-E", "-dD"}, args...)
    98  	cmd, err := exec.Command(cc, args...).Output() // execute command and capture output
    99  	if err != nil {
   100  		fmt.Fprintf(os.Stderr, "can't run %s", cc)
   101  		os.Exit(1)
   102  	}
   103  	text := ""
   104  	s := bufio.NewScanner(strings.NewReader(string(cmd)))
   105  	var offset, prev int
   106  	for s.Scan() {
   107  		t := re{str: s.Text()}
   108  		if t.Match(`^#define __NR_Linux\s+([0-9]+)`) {
   109  			// mips/mips64: extract offset
   110  			offset, _ = strconv.Atoi(t.sub[1]) // Make offset=0 if empty or non-numeric
   111  		} else if t.Match(`^#define __NR(\w*)_SYSCALL_BASE\s+([0-9]+)`) {
   112  			// arm: extract offset
   113  			offset, _ = strconv.Atoi(t.sub[1]) // Make offset=0 if empty or non-numeric
   114  		} else if t.Match(`^#define __NR_syscalls\s+`) {
   115  			// ignore redefinitions of __NR_syscalls
   116  		} else if t.Match(`^#define __NR_(\w*)Linux_syscalls\s+`) {
   117  			// mips/mips64: ignore definitions about the number of syscalls
   118  		} else if t.Match(`^#define __NR_(\w+)\s+([0-9]+)`) {
   119  			prev, err = strconv.Atoi(t.sub[2])
   120  			checkErr(err)
   121  			text += format(t.sub[1], prev, offset)
   122  		} else if t.Match(`^#define __NR3264_(\w+)\s+([0-9]+)`) {
   123  			prev, err = strconv.Atoi(t.sub[2])
   124  			checkErr(err)
   125  			text += format(t.sub[1], prev, offset)
   126  		} else if t.Match(`^#define __NR_(\w+)\s+\(\w+\+\s*([0-9]+)\)`) {
   127  			r2, err := strconv.Atoi(t.sub[2])
   128  			checkErr(err)
   129  			text += format(t.sub[1], prev+r2, offset)
   130  		} else if t.Match(`^#define __NR_(\w+)\s+\(__NR_(?:SYSCALL_BASE|Linux) \+ ([0-9]+)`) {
   131  			r2, err := strconv.Atoi(t.sub[2])
   132  			checkErr(err)
   133  			text += format(t.sub[1], r2, offset)
   134  		}
   135  	}
   136  	err = s.Err()
   137  	checkErr(err)
   138  	fmt.Printf(template, cmdLine(), goBuildTags(), plusBuildTags(), text)
   139  }
   140  
   141  const template = `// %s
   142  // Code generated by the command above; see README.md. DO NOT EDIT.
   143  
   144  //go:build %s
   145  // +build %s
   146  
   147  package unix
   148  
   149  const(
   150  %s)`