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)`
							 |