191 lines
4.5 KiB
Go
191 lines
4.5 KiB
Go
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style
|
||
|
// license that can be found in the LICENSE file.
|
||
|
|
||
|
// +build ignore
|
||
|
|
||
|
// Generate system call table for DragonFly, NetBSD,
|
||
|
// FreeBSD, OpenBSD or Darwin from master list
|
||
|
// (for example, /usr/src/sys/kern/syscalls.master or
|
||
|
// sys/syscall.h).
|
||
|
package main
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"io/ioutil"
|
||
|
"net/http"
|
||
|
"os"
|
||
|
"regexp"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
goos, goarch string
|
||
|
)
|
||
|
|
||
|
// cmdLine returns this programs's commandline arguments
|
||
|
func cmdLine() string {
|
||
|
return "go run mksysnum.go " + strings.Join(os.Args[1:], " ")
|
||
|
}
|
||
|
|
||
|
// buildTags returns build tags
|
||
|
func buildTags() string {
|
||
|
return fmt.Sprintf("%s,%s", goarch, goos)
|
||
|
}
|
||
|
|
||
|
func checkErr(err error) {
|
||
|
if err != nil {
|
||
|
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||
|
os.Exit(1)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// source string and substring slice for regexp
|
||
|
type re struct {
|
||
|
str string // source string
|
||
|
sub []string // matched sub-string
|
||
|
}
|
||
|
|
||
|
// Match performs regular expression match
|
||
|
func (r *re) Match(exp string) bool {
|
||
|
r.sub = regexp.MustCompile(exp).FindStringSubmatch(r.str)
|
||
|
if r.sub != nil {
|
||
|
return true
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
// fetchFile fetches a text file from URL
|
||
|
func fetchFile(URL string) io.Reader {
|
||
|
resp, err := http.Get(URL)
|
||
|
checkErr(err)
|
||
|
defer resp.Body.Close()
|
||
|
body, err := ioutil.ReadAll(resp.Body)
|
||
|
checkErr(err)
|
||
|
return strings.NewReader(string(body))
|
||
|
}
|
||
|
|
||
|
// readFile reads a text file from path
|
||
|
func readFile(path string) io.Reader {
|
||
|
file, err := os.Open(os.Args[1])
|
||
|
checkErr(err)
|
||
|
return file
|
||
|
}
|
||
|
|
||
|
func format(name, num, proto string) string {
|
||
|
name = strings.ToUpper(name)
|
||
|
// There are multiple entries for enosys and nosys, so comment them out.
|
||
|
nm := re{str: name}
|
||
|
if nm.Match(`^SYS_E?NOSYS$`) {
|
||
|
name = fmt.Sprintf("// %s", name)
|
||
|
}
|
||
|
if name == `SYS_SYS_EXIT` {
|
||
|
name = `SYS_EXIT`
|
||
|
}
|
||
|
return fmt.Sprintf(" %s = %s; // %s\n", name, num, proto)
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
// Get the OS (using GOOS_TARGET if it exist)
|
||
|
goos = os.Getenv("GOOS_TARGET")
|
||
|
if goos == "" {
|
||
|
goos = os.Getenv("GOOS")
|
||
|
}
|
||
|
// Get the architecture (using GOARCH_TARGET if it exists)
|
||
|
goarch = os.Getenv("GOARCH_TARGET")
|
||
|
if goarch == "" {
|
||
|
goarch = os.Getenv("GOARCH")
|
||
|
}
|
||
|
// Check if GOOS and GOARCH environment variables are defined
|
||
|
if goarch == "" || goos == "" {
|
||
|
fmt.Fprintf(os.Stderr, "GOARCH or GOOS not defined in environment\n")
|
||
|
os.Exit(1)
|
||
|
}
|
||
|
|
||
|
file := strings.TrimSpace(os.Args[1])
|
||
|
var syscalls io.Reader
|
||
|
if strings.HasPrefix(file, "https://") || strings.HasPrefix(file, "http://") {
|
||
|
// Download syscalls.master file
|
||
|
syscalls = fetchFile(file)
|
||
|
} else {
|
||
|
syscalls = readFile(file)
|
||
|
}
|
||
|
|
||
|
var text, line string
|
||
|
s := bufio.NewScanner(syscalls)
|
||
|
for s.Scan() {
|
||
|
t := re{str: line}
|
||
|
if t.Match(`^(.*)\\$`) {
|
||
|
// Handle continuation
|
||
|
line = t.sub[1]
|
||
|
line += strings.TrimLeft(s.Text(), " \t")
|
||
|
} else {
|
||
|
// New line
|
||
|
line = s.Text()
|
||
|
}
|
||
|
t = re{str: line}
|
||
|
if t.Match(`\\$`) {
|
||
|
continue
|
||
|
}
|
||
|
t = re{str: line}
|
||
|
|
||
|
switch goos {
|
||
|
case "dragonfly":
|
||
|
if t.Match(`^([0-9]+)\s+STD\s+({ \S+\s+(\w+).*)$`) {
|
||
|
num, proto := t.sub[1], t.sub[2]
|
||
|
name := fmt.Sprintf("SYS_%s", t.sub[3])
|
||
|
text += format(name, num, proto)
|
||
|
}
|
||
|
case "freebsd":
|
||
|
if t.Match(`^([0-9]+)\s+\S+\s+(?:(?:NO)?STD|COMPAT10)\s+({ \S+\s+(\w+).*)$`) {
|
||
|
num, proto := t.sub[1], t.sub[2]
|
||
|
name := fmt.Sprintf("SYS_%s", t.sub[3])
|
||
|
text += format(name, num, proto)
|
||
|
}
|
||
|
case "openbsd":
|
||
|
if t.Match(`^([0-9]+)\s+STD\s+(NOLOCK\s+)?({ \S+\s+\*?(\w+).*)$`) {
|
||
|
num, proto, name := t.sub[1], t.sub[3], t.sub[4]
|
||
|
text += format(name, num, proto)
|
||
|
}
|
||
|
case "netbsd":
|
||
|
if t.Match(`^([0-9]+)\s+((STD)|(NOERR))\s+(RUMP\s+)?({\s+\S+\s*\*?\s*\|(\S+)\|(\S*)\|(\w+).*\s+})(\s+(\S+))?$`) {
|
||
|
num, proto, compat := t.sub[1], t.sub[6], t.sub[8]
|
||
|
name := t.sub[7] + "_" + t.sub[9]
|
||
|
if t.sub[11] != "" {
|
||
|
name = t.sub[7] + "_" + t.sub[11]
|
||
|
}
|
||
|
name = strings.ToUpper(name)
|
||
|
if compat == "" || compat == "13" || compat == "30" || compat == "50" {
|
||
|
text += fmt.Sprintf(" %s = %s; // %s\n", name, num, proto)
|
||
|
}
|
||
|
}
|
||
|
case "darwin":
|
||
|
if t.Match(`^#define\s+SYS_(\w+)\s+([0-9]+)`) {
|
||
|
name, num := t.sub[1], t.sub[2]
|
||
|
name = strings.ToUpper(name)
|
||
|
text += fmt.Sprintf(" SYS_%s = %s;\n", name, num)
|
||
|
}
|
||
|
default:
|
||
|
fmt.Fprintf(os.Stderr, "unrecognized GOOS=%s\n", goos)
|
||
|
os.Exit(1)
|
||
|
|
||
|
}
|
||
|
}
|
||
|
err := s.Err()
|
||
|
checkErr(err)
|
||
|
|
||
|
fmt.Printf(template, cmdLine(), buildTags(), text)
|
||
|
}
|
||
|
|
||
|
const template = `// %s
|
||
|
// Code generated by the command above; see README.md. DO NOT EDIT.
|
||
|
|
||
|
// +build %s
|
||
|
|
||
|
package unix
|
||
|
|
||
|
const(
|
||
|
%s)`
|