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