mirror of
https://github.com/golang/sys.git
synced 2026-01-29 07:02:06 +03:00
go.sys: copy files from syscall package to go.sys/{plan9,windows,unix}
This CL copies to each package of go.sys the files from syscall it will need.
Different directories have different files, but these:
mkall.sh
str.go
syscall.go
mksyscall.pl
race.go
race0.go
syscall_test.go
are copied to all three.
No changes yet, these are just copies. They are not ready to use yet:
package names are wrong, for starters. But this clean copy will make
it easier to follow the changes as the packages are enabled.
LGTM=rsc
R=golang-codereviews, rsc
CC=golang-codereviews
https://golang.org/cl/126960043
This commit is contained in:
164
plan9/asm_plan9_386.s
Normal file
164
plan9/asm_plan9_386.s
Normal file
@@ -0,0 +1,164 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
|
||||
// so that go vet can check that they are correct.
|
||||
|
||||
#include "../../cmd/ld/textflag.h"
|
||||
|
||||
//
|
||||
// System call support for 386, Plan 9
|
||||
//
|
||||
|
||||
//func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err string)
|
||||
//func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err string)
|
||||
//func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
|
||||
//func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
|
||||
|
||||
// Trap # in AX, args on stack above caller pc.
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-32
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $64
|
||||
MOVL AX, r1+20(SP)
|
||||
MOVL $0, r2+24(SP)
|
||||
CMPL AX, $-1
|
||||
JNE ok3
|
||||
|
||||
SUBL $8, SP
|
||||
CALL runtime·errstr(SB)
|
||||
MOVL SP, SI
|
||||
ADDL $8, SP
|
||||
JMP copyresult3
|
||||
|
||||
ok3:
|
||||
LEAL runtime·emptystring(SB), SI
|
||||
|
||||
copyresult3:
|
||||
LEAL err+28(SP), DI
|
||||
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-44
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $64
|
||||
MOVL AX, r1+32(SP)
|
||||
MOVL $0, r2+36(SP)
|
||||
CMPL AX, $-1
|
||||
JNE ok4
|
||||
|
||||
SUBL $8, SP
|
||||
CALL runtime·errstr(SB)
|
||||
MOVL SP, SI
|
||||
ADDL $8, SP
|
||||
JMP copyresult4
|
||||
|
||||
ok4:
|
||||
LEAL runtime·emptystring(SB), SI
|
||||
|
||||
copyresult4:
|
||||
LEAL err+40(SP), DI
|
||||
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $64
|
||||
MOVL AX, r1+20(SP)
|
||||
MOVL AX, r2+24(SP)
|
||||
MOVL AX, err+28(SP)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $64
|
||||
MOVL AX, r1+32(SP)
|
||||
MOVL AX, r2+36(SP)
|
||||
MOVL AX, err+40(SP)
|
||||
RET
|
||||
|
||||
#define SYS_SEEK 39 /* from zsysnum_plan9_386.go */
|
||||
|
||||
//func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
|
||||
TEXT ·seek(SB),NOSPLIT,$0-36
|
||||
LEAL newoffset+24(SP), AX
|
||||
MOVL AX, placeholder+4(SP)
|
||||
|
||||
MOVL $SYS_SEEK, AX // syscall entry
|
||||
INT $64
|
||||
|
||||
CMPL AX, $-1
|
||||
JNE ok6
|
||||
MOVL AX, 24(SP) // newoffset low
|
||||
MOVL AX, 28(SP) // newoffset high
|
||||
|
||||
SUBL $8, SP
|
||||
CALL syscall·errstr(SB)
|
||||
MOVL SP, SI
|
||||
ADDL $8, SP
|
||||
JMP copyresult6
|
||||
|
||||
ok6:
|
||||
LEAL runtime·emptystring(SB), SI
|
||||
|
||||
copyresult6:
|
||||
LEAL err+32(SP), DI
|
||||
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
RET
|
||||
|
||||
//func exit(code int)
|
||||
// Import runtime·exit for cleanly exiting.
|
||||
TEXT ·exit(SB),NOSPLIT,$4-4
|
||||
MOVL code+0(FP), AX
|
||||
MOVL AX, 0(SP)
|
||||
CALL runtime·exit(SB)
|
||||
RET
|
||||
162
plan9/asm_plan9_amd64.s
Normal file
162
plan9/asm_plan9_amd64.s
Normal file
@@ -0,0 +1,162 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
|
||||
// so that go vet can check that they are correct.
|
||||
|
||||
#include "../../cmd/ld/textflag.h"
|
||||
|
||||
//
|
||||
// System call support for Plan 9
|
||||
//
|
||||
|
||||
//func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err string)
|
||||
//func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err string)
|
||||
//func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
|
||||
//func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-64
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVQ 8(SP), BP // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAQ 16(SP), SI
|
||||
LEAQ 8(SP), DI
|
||||
CLD
|
||||
MOVSQ
|
||||
MOVSQ
|
||||
MOVSQ
|
||||
SYSCALL
|
||||
MOVQ AX, r1+40(SP)
|
||||
MOVQ $0, r2+48(SP)
|
||||
CMPL AX, $-1
|
||||
JNE ok3
|
||||
|
||||
SUBQ $16, SP
|
||||
CALL runtime·errstr(SB)
|
||||
MOVQ SP, SI
|
||||
ADDQ $16, SP
|
||||
JMP copyresult3
|
||||
|
||||
ok3:
|
||||
LEAQ runtime·emptystring(SB), SI
|
||||
|
||||
copyresult3:
|
||||
LEAQ err+56(SP), DI
|
||||
|
||||
CLD
|
||||
MOVSQ
|
||||
MOVSQ
|
||||
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-88
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVQ 8(SP), BP // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAQ 16(SP), SI
|
||||
LEAQ 8(SP), DI
|
||||
CLD
|
||||
MOVSQ
|
||||
MOVSQ
|
||||
MOVSQ
|
||||
MOVSQ
|
||||
MOVSQ
|
||||
MOVSQ
|
||||
SYSCALL
|
||||
MOVQ AX, r1+64(SP)
|
||||
MOVQ $0, r2+72(SP)
|
||||
CMPL AX, $-1
|
||||
JNE ok4
|
||||
|
||||
SUBQ $16, SP
|
||||
CALL runtime·errstr(SB)
|
||||
MOVQ SP, SI
|
||||
ADDQ $16, SP
|
||||
JMP copyresult4
|
||||
|
||||
ok4:
|
||||
LEAQ runtime·emptystring(SB), SI
|
||||
|
||||
copyresult4:
|
||||
LEAQ err+80(SP), DI
|
||||
|
||||
CLD
|
||||
MOVSQ
|
||||
MOVSQ
|
||||
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||
MOVQ 8(SP), BP // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAQ 16(SP), SI
|
||||
LEAQ 8(SP), DI
|
||||
CLD
|
||||
MOVSQ
|
||||
MOVSQ
|
||||
MOVSQ
|
||||
SYSCALL
|
||||
MOVQ AX, r1+40(SP)
|
||||
MOVQ AX, r2+48(SP)
|
||||
MOVQ AX, err+56(SP)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||
MOVQ 8(SP), BP // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAQ 16(SP), SI
|
||||
LEAQ 8(SP), DI
|
||||
CLD
|
||||
MOVSQ
|
||||
MOVSQ
|
||||
MOVSQ
|
||||
MOVSQ
|
||||
MOVSQ
|
||||
MOVSQ
|
||||
SYSCALL
|
||||
MOVQ AX, r1+64(SP)
|
||||
MOVQ AX, r2+72(SP)
|
||||
MOVQ AX, err+80(SP)
|
||||
RET
|
||||
|
||||
#define SYS_SEEK 39 /* from zsysnum_plan9_amd64.go */
|
||||
|
||||
//func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
|
||||
TEXT ·seek(SB),NOSPLIT,$0-56
|
||||
LEAQ newoffset+40(SP), AX
|
||||
MOVQ AX, placeholder+8(SP)
|
||||
|
||||
MOVQ $SYS_SEEK, BP // syscall entry
|
||||
SYSCALL
|
||||
|
||||
CMPL AX, $-1
|
||||
JNE ok6
|
||||
MOVQ $-1, newoffset+40(SP)
|
||||
|
||||
SUBQ $16, SP
|
||||
CALL syscall·errstr(SB)
|
||||
MOVQ SP, SI
|
||||
ADDQ $16, SP
|
||||
JMP copyresult6
|
||||
|
||||
ok6:
|
||||
LEAQ runtime·emptystring(SB), SI
|
||||
|
||||
copyresult6:
|
||||
LEAQ err+48(SP), DI
|
||||
|
||||
CLD
|
||||
MOVSQ
|
||||
MOVSQ
|
||||
RET
|
||||
|
||||
//func exit(code int)
|
||||
// Import runtime·exit for cleanly exiting.
|
||||
TEXT ·exit(SB),NOSPLIT,$8-8
|
||||
MOVQ code+0(FP), AX
|
||||
MOVQ AX, 0(SP)
|
||||
CALL runtime·exit(SB)
|
||||
RET
|
||||
212
plan9/dir_plan9.go
Normal file
212
plan9/dir_plan9.go
Normal file
@@ -0,0 +1,212 @@
|
||||
// Copyright 2012 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.
|
||||
|
||||
// Plan 9 directory marshalling. See intro(5).
|
||||
|
||||
package syscall
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrShortStat = errors.New("stat buffer too short")
|
||||
ErrBadStat = errors.New("malformed stat buffer")
|
||||
ErrBadName = errors.New("bad character in file name")
|
||||
)
|
||||
|
||||
// A Qid represents a 9P server's unique identification for a file.
|
||||
type Qid struct {
|
||||
Path uint64 // the file server's unique identification for the file
|
||||
Vers uint32 // version number for given Path
|
||||
Type uint8 // the type of the file (syscall.QTDIR for example)
|
||||
}
|
||||
|
||||
// A Dir contains the metadata for a file.
|
||||
type Dir struct {
|
||||
// system-modified data
|
||||
Type uint16 // server type
|
||||
Dev uint32 // server subtype
|
||||
|
||||
// file data
|
||||
Qid Qid // unique id from server
|
||||
Mode uint32 // permissions
|
||||
Atime uint32 // last read time
|
||||
Mtime uint32 // last write time
|
||||
Length int64 // file length
|
||||
Name string // last element of path
|
||||
Uid string // owner name
|
||||
Gid string // group name
|
||||
Muid string // last modifier name
|
||||
}
|
||||
|
||||
var nullDir = Dir{
|
||||
Type: ^uint16(0),
|
||||
Dev: ^uint32(0),
|
||||
Qid: Qid{
|
||||
Path: ^uint64(0),
|
||||
Vers: ^uint32(0),
|
||||
Type: ^uint8(0),
|
||||
},
|
||||
Mode: ^uint32(0),
|
||||
Atime: ^uint32(0),
|
||||
Mtime: ^uint32(0),
|
||||
Length: ^int64(0),
|
||||
}
|
||||
|
||||
// Null assigns special "don't touch" values to members of d to
|
||||
// avoid modifying them during syscall.Wstat.
|
||||
func (d *Dir) Null() { *d = nullDir }
|
||||
|
||||
// Marshal encodes a 9P stat message corresponding to d into b
|
||||
//
|
||||
// If there isn't enough space in b for a stat message, ErrShortStat is returned.
|
||||
func (d *Dir) Marshal(b []byte) (n int, err error) {
|
||||
n = STATFIXLEN + len(d.Name) + len(d.Uid) + len(d.Gid) + len(d.Muid)
|
||||
if n > len(b) {
|
||||
return n, ErrShortStat
|
||||
}
|
||||
|
||||
for _, c := range d.Name {
|
||||
if c == '/' {
|
||||
return n, ErrBadName
|
||||
}
|
||||
}
|
||||
|
||||
b = pbit16(b, uint16(n)-2)
|
||||
b = pbit16(b, d.Type)
|
||||
b = pbit32(b, d.Dev)
|
||||
b = pbit8(b, d.Qid.Type)
|
||||
b = pbit32(b, d.Qid.Vers)
|
||||
b = pbit64(b, d.Qid.Path)
|
||||
b = pbit32(b, d.Mode)
|
||||
b = pbit32(b, d.Atime)
|
||||
b = pbit32(b, d.Mtime)
|
||||
b = pbit64(b, uint64(d.Length))
|
||||
b = pstring(b, d.Name)
|
||||
b = pstring(b, d.Uid)
|
||||
b = pstring(b, d.Gid)
|
||||
b = pstring(b, d.Muid)
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// UnmarshalDir decodes a single 9P stat message from b and returns the resulting Dir.
|
||||
//
|
||||
// If b is too small to hold a valid stat message, ErrShortStat is returned.
|
||||
//
|
||||
// If the stat message itself is invalid, ErrBadStat is returned.
|
||||
func UnmarshalDir(b []byte) (*Dir, error) {
|
||||
if len(b) < STATFIXLEN {
|
||||
return nil, ErrShortStat
|
||||
}
|
||||
size, buf := gbit16(b)
|
||||
if len(b) != int(size)+2 {
|
||||
return nil, ErrBadStat
|
||||
}
|
||||
b = buf
|
||||
|
||||
var d Dir
|
||||
d.Type, b = gbit16(b)
|
||||
d.Dev, b = gbit32(b)
|
||||
d.Qid.Type, b = gbit8(b)
|
||||
d.Qid.Vers, b = gbit32(b)
|
||||
d.Qid.Path, b = gbit64(b)
|
||||
d.Mode, b = gbit32(b)
|
||||
d.Atime, b = gbit32(b)
|
||||
d.Mtime, b = gbit32(b)
|
||||
|
||||
n, b := gbit64(b)
|
||||
d.Length = int64(n)
|
||||
|
||||
var ok bool
|
||||
if d.Name, b, ok = gstring(b); !ok {
|
||||
return nil, ErrBadStat
|
||||
}
|
||||
if d.Uid, b, ok = gstring(b); !ok {
|
||||
return nil, ErrBadStat
|
||||
}
|
||||
if d.Gid, b, ok = gstring(b); !ok {
|
||||
return nil, ErrBadStat
|
||||
}
|
||||
if d.Muid, b, ok = gstring(b); !ok {
|
||||
return nil, ErrBadStat
|
||||
}
|
||||
|
||||
return &d, nil
|
||||
}
|
||||
|
||||
// pbit8 copies the 8-bit number v to b and returns the remaining slice of b.
|
||||
func pbit8(b []byte, v uint8) []byte {
|
||||
b[0] = byte(v)
|
||||
return b[1:]
|
||||
}
|
||||
|
||||
// pbit16 copies the 16-bit number v to b in little-endian order and returns the remaining slice of b.
|
||||
func pbit16(b []byte, v uint16) []byte {
|
||||
b[0] = byte(v)
|
||||
b[1] = byte(v >> 8)
|
||||
return b[2:]
|
||||
}
|
||||
|
||||
// pbit32 copies the 32-bit number v to b in little-endian order and returns the remaining slice of b.
|
||||
func pbit32(b []byte, v uint32) []byte {
|
||||
b[0] = byte(v)
|
||||
b[1] = byte(v >> 8)
|
||||
b[2] = byte(v >> 16)
|
||||
b[3] = byte(v >> 24)
|
||||
return b[4:]
|
||||
}
|
||||
|
||||
// pbit64 copies the 64-bit number v to b in little-endian order and returns the remaining slice of b.
|
||||
func pbit64(b []byte, v uint64) []byte {
|
||||
b[0] = byte(v)
|
||||
b[1] = byte(v >> 8)
|
||||
b[2] = byte(v >> 16)
|
||||
b[3] = byte(v >> 24)
|
||||
b[4] = byte(v >> 32)
|
||||
b[5] = byte(v >> 40)
|
||||
b[6] = byte(v >> 48)
|
||||
b[7] = byte(v >> 56)
|
||||
return b[8:]
|
||||
}
|
||||
|
||||
// pstring copies the string s to b, prepending it with a 16-bit length in little-endian order, and
|
||||
// returning the remaining slice of b..
|
||||
func pstring(b []byte, s string) []byte {
|
||||
b = pbit16(b, uint16(len(s)))
|
||||
n := copy(b, s)
|
||||
return b[n:]
|
||||
}
|
||||
|
||||
// gbit8 reads an 8-bit number from b and returns it with the remaining slice of b.
|
||||
func gbit8(b []byte) (uint8, []byte) {
|
||||
return uint8(b[0]), b[1:]
|
||||
}
|
||||
|
||||
// gbit16 reads a 16-bit number in little-endian order from b and returns it with the remaining slice of b.
|
||||
func gbit16(b []byte) (uint16, []byte) {
|
||||
return uint16(b[0]) | uint16(b[1])<<8, b[2:]
|
||||
}
|
||||
|
||||
// gbit32 reads a 32-bit number in little-endian order from b and returns it with the remaining slice of b.
|
||||
func gbit32(b []byte) (uint32, []byte) {
|
||||
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, b[4:]
|
||||
}
|
||||
|
||||
// gbit64 reads a 64-bit number in little-endian order from b and returns it with the remaining slice of b.
|
||||
func gbit64(b []byte) (uint64, []byte) {
|
||||
lo := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
|
||||
hi := uint32(b[4]) | uint32(b[5])<<8 | uint32(b[6])<<16 | uint32(b[7])<<24
|
||||
return uint64(lo) | uint64(hi)<<32, b[8:]
|
||||
}
|
||||
|
||||
// gstring reads a string from b, prefixed with a 16-bit length in little-endian order.
|
||||
// It returns the string with the remaining slice of b and a boolean. If the length is
|
||||
// greater than the number of bytes in b, the boolean will be false.
|
||||
func gstring(b []byte) (string, []byte, bool) {
|
||||
n, b := gbit16(b)
|
||||
if int(n) > len(b) {
|
||||
return "", b, false
|
||||
}
|
||||
return string(b[:n]), b[n:], true
|
||||
}
|
||||
142
plan9/env_plan9.go
Normal file
142
plan9/env_plan9.go
Normal file
@@ -0,0 +1,142 @@
|
||||
// Copyright 2011 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.
|
||||
|
||||
// Plan 9 environment variables.
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
// envOnce guards copyenv, which populates env.
|
||||
envOnce sync.Once
|
||||
|
||||
// envLock guards env and envs.
|
||||
envLock sync.RWMutex
|
||||
|
||||
// env maps from an environment variable to its value.
|
||||
env = make(map[string]string)
|
||||
|
||||
// envs contains elements of env in the form "key=value".
|
||||
envs []string
|
||||
|
||||
errZeroLengthKey = errors.New("zero length key")
|
||||
errShortWrite = errors.New("i/o count too small")
|
||||
)
|
||||
|
||||
func readenv(key string) (string, error) {
|
||||
fd, err := Open("/env/"+key, O_RDONLY)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer Close(fd)
|
||||
l, _ := Seek(fd, 0, 2)
|
||||
Seek(fd, 0, 0)
|
||||
buf := make([]byte, l)
|
||||
n, err := Read(fd, buf)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if n > 0 && buf[n-1] == 0 {
|
||||
buf = buf[:n-1]
|
||||
}
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
func writeenv(key, value string) error {
|
||||
fd, err := Create("/env/"+key, O_RDWR, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer Close(fd)
|
||||
b := []byte(value)
|
||||
n, err := Write(fd, b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n != len(b) {
|
||||
return errShortWrite
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyenv() {
|
||||
fd, err := Open("/env", O_RDONLY)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer Close(fd)
|
||||
files, err := readdirnames(fd)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
envs = make([]string, len(files))
|
||||
i := 0
|
||||
for _, key := range files {
|
||||
v, err := readenv(key)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
env[key] = v
|
||||
envs[i] = key + "=" + v
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
func Getenv(key string) (value string, found bool) {
|
||||
if len(key) == 0 {
|
||||
return "", false
|
||||
}
|
||||
|
||||
envLock.RLock()
|
||||
defer envLock.RUnlock()
|
||||
|
||||
if v, ok := env[key]; ok {
|
||||
return v, true
|
||||
}
|
||||
v, err := readenv(key)
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
env[key] = v
|
||||
envs = append(envs, key+"="+v)
|
||||
return v, true
|
||||
}
|
||||
|
||||
func Setenv(key, value string) error {
|
||||
if len(key) == 0 {
|
||||
return errZeroLengthKey
|
||||
}
|
||||
|
||||
envLock.Lock()
|
||||
defer envLock.Unlock()
|
||||
|
||||
err := writeenv(key, value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
env[key] = value
|
||||
envs = append(envs, key+"="+value)
|
||||
return nil
|
||||
}
|
||||
|
||||
func Clearenv() {
|
||||
envLock.Lock()
|
||||
defer envLock.Unlock()
|
||||
|
||||
env = make(map[string]string)
|
||||
envs = []string{}
|
||||
RawSyscall(SYS_RFORK, RFCENVG, 0, 0)
|
||||
}
|
||||
|
||||
func Environ() []string {
|
||||
envLock.RLock()
|
||||
defer envLock.RUnlock()
|
||||
|
||||
envOnce.Do(copyenv)
|
||||
return append([]string(nil), envs...)
|
||||
}
|
||||
650
plan9/exec_plan9.go
Normal file
650
plan9/exec_plan9.go
Normal file
@@ -0,0 +1,650 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
// Fork, exec, wait, etc.
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Lock synchronizing creation of new file descriptors with fork.
|
||||
//
|
||||
// We want the child in a fork/exec sequence to inherit only the
|
||||
// file descriptors we intend. To do that, we mark all file
|
||||
// descriptors close-on-exec and then, in the child, explicitly
|
||||
// unmark the ones we want the exec'ed program to keep.
|
||||
// Unix doesn't make this easy: there is, in general, no way to
|
||||
// allocate a new file descriptor close-on-exec. Instead you
|
||||
// have to allocate the descriptor and then mark it close-on-exec.
|
||||
// If a fork happens between those two events, the child's exec
|
||||
// will inherit an unwanted file descriptor.
|
||||
//
|
||||
// This lock solves that race: the create new fd/mark close-on-exec
|
||||
// operation is done holding ForkLock for reading, and the fork itself
|
||||
// is done holding ForkLock for writing. At least, that's the idea.
|
||||
// There are some complications.
|
||||
//
|
||||
// Some system calls that create new file descriptors can block
|
||||
// for arbitrarily long times: open on a hung NFS server or named
|
||||
// pipe, accept on a socket, and so on. We can't reasonably grab
|
||||
// the lock across those operations.
|
||||
//
|
||||
// It is worse to inherit some file descriptors than others.
|
||||
// If a non-malicious child accidentally inherits an open ordinary file,
|
||||
// that's not a big deal. On the other hand, if a long-lived child
|
||||
// accidentally inherits the write end of a pipe, then the reader
|
||||
// of that pipe will not see EOF until that child exits, potentially
|
||||
// causing the parent program to hang. This is a common problem
|
||||
// in threaded C programs that use popen.
|
||||
//
|
||||
// Luckily, the file descriptors that are most important not to
|
||||
// inherit are not the ones that can take an arbitrarily long time
|
||||
// to create: pipe returns instantly, and the net package uses
|
||||
// non-blocking I/O to accept on a listening socket.
|
||||
// The rules for which file descriptor-creating operations use the
|
||||
// ForkLock are as follows:
|
||||
//
|
||||
// 1) Pipe. Does not block. Use the ForkLock.
|
||||
// 2) Socket. Does not block. Use the ForkLock.
|
||||
// 3) Accept. If using non-blocking mode, use the ForkLock.
|
||||
// Otherwise, live with the race.
|
||||
// 4) Open. Can block. Use O_CLOEXEC if available (Linux).
|
||||
// Otherwise, live with the race.
|
||||
// 5) Dup. Does not block. Use the ForkLock.
|
||||
// On Linux, could use fcntl F_DUPFD_CLOEXEC
|
||||
// instead of the ForkLock, but only for dup(fd, -1).
|
||||
|
||||
var ForkLock sync.RWMutex
|
||||
|
||||
// StringSlicePtr is deprecated. Use SlicePtrFromStrings instead.
|
||||
// If any string contains a NUL byte this function panics instead
|
||||
// of returning an error.
|
||||
func StringSlicePtr(ss []string) []*byte {
|
||||
bb := make([]*byte, len(ss)+1)
|
||||
for i := 0; i < len(ss); i++ {
|
||||
bb[i] = StringBytePtr(ss[i])
|
||||
}
|
||||
bb[len(ss)] = nil
|
||||
return bb
|
||||
}
|
||||
|
||||
// SlicePtrFromStrings converts a slice of strings to a slice of
|
||||
// pointers to NUL-terminated byte slices. If any string contains
|
||||
// a NUL byte, it returns (nil, EINVAL).
|
||||
func SlicePtrFromStrings(ss []string) ([]*byte, error) {
|
||||
var err error
|
||||
bb := make([]*byte, len(ss)+1)
|
||||
for i := 0; i < len(ss); i++ {
|
||||
bb[i], err = BytePtrFromString(ss[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
bb[len(ss)] = nil
|
||||
return bb, nil
|
||||
}
|
||||
|
||||
// readdirnames returns the names of files inside the directory represented by dirfd.
|
||||
func readdirnames(dirfd int) (names []string, err error) {
|
||||
names = make([]string, 0, 100)
|
||||
var buf [STATMAX]byte
|
||||
|
||||
for {
|
||||
n, e := Read(dirfd, buf[:])
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
if n == 0 {
|
||||
break
|
||||
}
|
||||
for i := 0; i < n; {
|
||||
m, _ := gbit16(buf[i:])
|
||||
m += 2
|
||||
|
||||
if m < STATFIXLEN {
|
||||
return nil, ErrBadStat
|
||||
}
|
||||
|
||||
s, _, ok := gstring(buf[i+41:])
|
||||
if !ok {
|
||||
return nil, ErrBadStat
|
||||
}
|
||||
names = append(names, s)
|
||||
i += int(m)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// readdupdevice returns a list of currently opened fds (excluding stdin, stdout, stderr) from the dup device #d.
|
||||
// ForkLock should be write locked before calling, so that no new fds would be created while the fd list is being read.
|
||||
func readdupdevice() (fds []int, err error) {
|
||||
dupdevfd, err := Open("#d", O_RDONLY)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer Close(dupdevfd)
|
||||
|
||||
names, err := readdirnames(dupdevfd)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fds = make([]int, 0, len(names)/2)
|
||||
for _, name := range names {
|
||||
if n := len(name); n > 3 && name[n-3:n] == "ctl" {
|
||||
continue
|
||||
}
|
||||
fd := int(atoi([]byte(name)))
|
||||
switch fd {
|
||||
case 0, 1, 2, dupdevfd:
|
||||
continue
|
||||
}
|
||||
fds = append(fds, fd)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var startupFds []int
|
||||
|
||||
// Plan 9 does not allow clearing the OCEXEC flag
|
||||
// from the underlying channel backing an open file descriptor,
|
||||
// therefore we store a list of already opened file descriptors
|
||||
// inside startupFds and skip them when manually closing descriptors
|
||||
// not meant to be passed to a child exec.
|
||||
func init() {
|
||||
startupFds, _ = readdupdevice()
|
||||
}
|
||||
|
||||
// forkAndExecInChild forks the process, calling dup onto 0..len(fd)
|
||||
// and finally invoking exec(argv0, argvv, envv) in the child.
|
||||
// If a dup or exec fails, it writes the error string to pipe.
|
||||
// (The pipe write end is close-on-exec so if exec succeeds, it will be closed.)
|
||||
//
|
||||
// In the child, this function must not acquire any locks, because
|
||||
// they might have been locked at the time of the fork. This means
|
||||
// no rescheduling, no malloc calls, and no new stack segments.
|
||||
// The calls to RawSyscall are okay because they are assembly
|
||||
// functions that do not grow the stack.
|
||||
func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, attr *ProcAttr, fdsToClose []int, pipe int, rflag int) (pid int, err error) {
|
||||
// Declare all variables at top in case any
|
||||
// declarations require heap allocation (e.g., errbuf).
|
||||
var (
|
||||
r1 uintptr
|
||||
nextfd int
|
||||
i int
|
||||
clearenv int
|
||||
envfd int
|
||||
errbuf [ERRMAX]byte
|
||||
)
|
||||
|
||||
// Guard against side effects of shuffling fds below.
|
||||
// Make sure that nextfd is beyond any currently open files so
|
||||
// that we can't run the risk of overwriting any of them.
|
||||
fd := make([]int, len(attr.Files))
|
||||
nextfd = len(attr.Files)
|
||||
for i, ufd := range attr.Files {
|
||||
if nextfd < int(ufd) {
|
||||
nextfd = int(ufd)
|
||||
}
|
||||
fd[i] = int(ufd)
|
||||
}
|
||||
nextfd++
|
||||
|
||||
if envv != nil {
|
||||
clearenv = RFCENVG
|
||||
}
|
||||
|
||||
// About to call fork.
|
||||
// No more allocation or calls of non-assembly functions.
|
||||
r1, _, _ = RawSyscall(SYS_RFORK, uintptr(RFPROC|RFFDG|RFREND|clearenv|rflag), 0, 0)
|
||||
|
||||
if r1 != 0 {
|
||||
if int32(r1) == -1 {
|
||||
return 0, NewError(errstr())
|
||||
}
|
||||
// parent; return PID
|
||||
return int(r1), nil
|
||||
}
|
||||
|
||||
// Fork succeeded, now in child.
|
||||
|
||||
// Close fds we don't need.
|
||||
for i = 0; i < len(fdsToClose); i++ {
|
||||
r1, _, _ = RawSyscall(SYS_CLOSE, uintptr(fdsToClose[i]), 0, 0)
|
||||
if int32(r1) == -1 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
if envv != nil {
|
||||
// Write new environment variables.
|
||||
for i = 0; i < len(envv); i++ {
|
||||
r1, _, _ = RawSyscall(SYS_CREATE, uintptr(unsafe.Pointer(envv[i].name)), uintptr(O_WRONLY), uintptr(0666))
|
||||
|
||||
if int32(r1) == -1 {
|
||||
goto childerror
|
||||
}
|
||||
|
||||
envfd = int(r1)
|
||||
|
||||
r1, _, _ = RawSyscall6(SYS_PWRITE, uintptr(envfd), uintptr(unsafe.Pointer(envv[i].value)), uintptr(envv[i].nvalue),
|
||||
^uintptr(0), ^uintptr(0), 0)
|
||||
|
||||
if int32(r1) == -1 || int(r1) != envv[i].nvalue {
|
||||
goto childerror
|
||||
}
|
||||
|
||||
r1, _, _ = RawSyscall(SYS_CLOSE, uintptr(envfd), 0, 0)
|
||||
|
||||
if int32(r1) == -1 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Chdir
|
||||
if dir != nil {
|
||||
r1, _, _ = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)), 0, 0)
|
||||
if int32(r1) == -1 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// Pass 1: look for fd[i] < i and move those up above len(fd)
|
||||
// so that pass 2 won't stomp on an fd it needs later.
|
||||
if pipe < nextfd {
|
||||
r1, _, _ = RawSyscall(SYS_DUP, uintptr(pipe), uintptr(nextfd), 0)
|
||||
if int32(r1) == -1 {
|
||||
goto childerror
|
||||
}
|
||||
pipe = nextfd
|
||||
nextfd++
|
||||
}
|
||||
for i = 0; i < len(fd); i++ {
|
||||
if fd[i] >= 0 && fd[i] < int(i) {
|
||||
r1, _, _ = RawSyscall(SYS_DUP, uintptr(fd[i]), uintptr(nextfd), 0)
|
||||
if int32(r1) == -1 {
|
||||
goto childerror
|
||||
}
|
||||
|
||||
fd[i] = nextfd
|
||||
nextfd++
|
||||
if nextfd == pipe { // don't stomp on pipe
|
||||
nextfd++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pass 2: dup fd[i] down onto i.
|
||||
for i = 0; i < len(fd); i++ {
|
||||
if fd[i] == -1 {
|
||||
RawSyscall(SYS_CLOSE, uintptr(i), 0, 0)
|
||||
continue
|
||||
}
|
||||
if fd[i] == int(i) {
|
||||
continue
|
||||
}
|
||||
r1, _, _ = RawSyscall(SYS_DUP, uintptr(fd[i]), uintptr(i), 0)
|
||||
if int32(r1) == -1 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// Pass 3: close fd[i] if it was moved in the previous pass.
|
||||
for i = 0; i < len(fd); i++ {
|
||||
if fd[i] >= 0 && fd[i] != int(i) {
|
||||
RawSyscall(SYS_CLOSE, uintptr(fd[i]), 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
// Time to exec.
|
||||
r1, _, _ = RawSyscall(SYS_EXEC,
|
||||
uintptr(unsafe.Pointer(argv0)),
|
||||
uintptr(unsafe.Pointer(&argv[0])), 0)
|
||||
|
||||
childerror:
|
||||
// send error string on pipe
|
||||
RawSyscall(SYS_ERRSTR, uintptr(unsafe.Pointer(&errbuf[0])), uintptr(len(errbuf)), 0)
|
||||
errbuf[len(errbuf)-1] = 0
|
||||
i = 0
|
||||
for i < len(errbuf) && errbuf[i] != 0 {
|
||||
i++
|
||||
}
|
||||
|
||||
RawSyscall6(SYS_PWRITE, uintptr(pipe), uintptr(unsafe.Pointer(&errbuf[0])), uintptr(i),
|
||||
^uintptr(0), ^uintptr(0), 0)
|
||||
|
||||
for {
|
||||
RawSyscall(SYS_EXITS, 0, 0, 0)
|
||||
}
|
||||
|
||||
// Calling panic is not actually safe,
|
||||
// but the for loop above won't break
|
||||
// and this shuts up the compiler.
|
||||
panic("unreached")
|
||||
}
|
||||
|
||||
func cexecPipe(p []int) error {
|
||||
e := Pipe(p)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
fd, e := Open("#d/"+itoa(p[1]), O_CLOEXEC)
|
||||
if e != nil {
|
||||
Close(p[0])
|
||||
Close(p[1])
|
||||
return e
|
||||
}
|
||||
|
||||
Close(fd)
|
||||
return nil
|
||||
}
|
||||
|
||||
type envItem struct {
|
||||
name *byte
|
||||
value *byte
|
||||
nvalue int
|
||||
}
|
||||
|
||||
type ProcAttr struct {
|
||||
Dir string // Current working directory.
|
||||
Env []string // Environment.
|
||||
Files []uintptr // File descriptors.
|
||||
Sys *SysProcAttr
|
||||
}
|
||||
|
||||
type SysProcAttr struct {
|
||||
Rfork int // additional flags to pass to rfork
|
||||
}
|
||||
|
||||
var zeroProcAttr ProcAttr
|
||||
var zeroSysProcAttr SysProcAttr
|
||||
|
||||
func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
|
||||
var (
|
||||
p [2]int
|
||||
n int
|
||||
errbuf [ERRMAX]byte
|
||||
wmsg Waitmsg
|
||||
)
|
||||
|
||||
if attr == nil {
|
||||
attr = &zeroProcAttr
|
||||
}
|
||||
sys := attr.Sys
|
||||
if sys == nil {
|
||||
sys = &zeroSysProcAttr
|
||||
}
|
||||
|
||||
p[0] = -1
|
||||
p[1] = -1
|
||||
|
||||
// Convert args to C form.
|
||||
argv0p, err := BytePtrFromString(argv0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
argvp, err := SlicePtrFromStrings(argv)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
var dir *byte
|
||||
if attr.Dir != "" {
|
||||
dir, err = BytePtrFromString(attr.Dir)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
var envvParsed []envItem
|
||||
if attr.Env != nil {
|
||||
envvParsed = make([]envItem, 0, len(attr.Env))
|
||||
for _, v := range attr.Env {
|
||||
i := 0
|
||||
for i < len(v) && v[i] != '=' {
|
||||
i++
|
||||
}
|
||||
|
||||
envname, err := BytePtrFromString("/env/" + v[:i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
envvalue := make([]byte, len(v)-i)
|
||||
copy(envvalue, v[i+1:])
|
||||
envvParsed = append(envvParsed, envItem{envname, &envvalue[0], len(v) - i})
|
||||
}
|
||||
}
|
||||
|
||||
// Acquire the fork lock to prevent other threads from creating new fds before we fork.
|
||||
ForkLock.Lock()
|
||||
|
||||
// get a list of open fds, excluding stdin,stdout and stderr that need to be closed in the child.
|
||||
// no new fds can be created while we hold the ForkLock for writing.
|
||||
openFds, e := readdupdevice()
|
||||
if e != nil {
|
||||
ForkLock.Unlock()
|
||||
return 0, e
|
||||
}
|
||||
|
||||
fdsToClose := make([]int, 0, len(openFds))
|
||||
for _, fd := range openFds {
|
||||
doClose := true
|
||||
|
||||
// exclude files opened at startup.
|
||||
for _, sfd := range startupFds {
|
||||
if fd == sfd {
|
||||
doClose = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// exclude files explicitly requested by the caller.
|
||||
for _, rfd := range attr.Files {
|
||||
if fd == int(rfd) {
|
||||
doClose = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if doClose {
|
||||
fdsToClose = append(fdsToClose, fd)
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate child status pipe close on exec.
|
||||
e = cexecPipe(p[:])
|
||||
|
||||
if e != nil {
|
||||
return 0, e
|
||||
}
|
||||
fdsToClose = append(fdsToClose, p[0])
|
||||
|
||||
// Kick off child.
|
||||
pid, err = forkAndExecInChild(argv0p, argvp, envvParsed, dir, attr, fdsToClose, p[1], sys.Rfork)
|
||||
|
||||
if err != nil {
|
||||
if p[0] >= 0 {
|
||||
Close(p[0])
|
||||
Close(p[1])
|
||||
}
|
||||
ForkLock.Unlock()
|
||||
return 0, err
|
||||
}
|
||||
ForkLock.Unlock()
|
||||
|
||||
// Read child error status from pipe.
|
||||
Close(p[1])
|
||||
n, err = Read(p[0], errbuf[:])
|
||||
Close(p[0])
|
||||
|
||||
if err != nil || n != 0 {
|
||||
if n != 0 {
|
||||
err = NewError(string(errbuf[:n]))
|
||||
}
|
||||
|
||||
// Child failed; wait for it to exit, to make sure
|
||||
// the zombies don't accumulate.
|
||||
for wmsg.Pid != pid {
|
||||
Await(&wmsg)
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Read got EOF, so pipe closed on exec, so exec succeeded.
|
||||
return pid, nil
|
||||
}
|
||||
|
||||
type waitErr struct {
|
||||
Waitmsg
|
||||
err error
|
||||
}
|
||||
|
||||
var procs struct {
|
||||
sync.Mutex
|
||||
waits map[int]chan *waitErr
|
||||
}
|
||||
|
||||
// startProcess starts a new goroutine, tied to the OS
|
||||
// thread, which runs the process and subsequently waits
|
||||
// for it to finish, communicating the process stats back
|
||||
// to any goroutines that may have been waiting on it.
|
||||
//
|
||||
// Such a dedicated goroutine is needed because on
|
||||
// Plan 9, only the parent thread can wait for a child,
|
||||
// whereas goroutines tend to jump OS threads (e.g.,
|
||||
// between starting a process and running Wait(), the
|
||||
// goroutine may have been rescheduled).
|
||||
func startProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
|
||||
type forkRet struct {
|
||||
pid int
|
||||
err error
|
||||
}
|
||||
|
||||
forkc := make(chan forkRet, 1)
|
||||
go func() {
|
||||
runtime.LockOSThread()
|
||||
var ret forkRet
|
||||
|
||||
ret.pid, ret.err = forkExec(argv0, argv, attr)
|
||||
// If fork fails there is nothing to wait for.
|
||||
if ret.err != nil || ret.pid == 0 {
|
||||
forkc <- ret
|
||||
return
|
||||
}
|
||||
|
||||
waitc := make(chan *waitErr, 1)
|
||||
|
||||
// Mark that the process is running.
|
||||
procs.Lock()
|
||||
if procs.waits == nil {
|
||||
procs.waits = make(map[int]chan *waitErr)
|
||||
}
|
||||
procs.waits[ret.pid] = waitc
|
||||
procs.Unlock()
|
||||
|
||||
forkc <- ret
|
||||
|
||||
var w waitErr
|
||||
for w.err == nil && w.Pid != ret.pid {
|
||||
w.err = Await(&w.Waitmsg)
|
||||
}
|
||||
waitc <- &w
|
||||
close(waitc)
|
||||
}()
|
||||
ret := <-forkc
|
||||
return ret.pid, ret.err
|
||||
}
|
||||
|
||||
// Combination of fork and exec, careful to be thread safe.
|
||||
func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
|
||||
return startProcess(argv0, argv, attr)
|
||||
}
|
||||
|
||||
// StartProcess wraps ForkExec for package os.
|
||||
func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
|
||||
pid, err = startProcess(argv0, argv, attr)
|
||||
return pid, 0, err
|
||||
}
|
||||
|
||||
// Ordinary exec.
|
||||
func Exec(argv0 string, argv []string, envv []string) (err error) {
|
||||
if envv != nil {
|
||||
r1, _, _ := RawSyscall(SYS_RFORK, RFCENVG, 0, 0)
|
||||
if int32(r1) == -1 {
|
||||
return NewError(errstr())
|
||||
}
|
||||
|
||||
for _, v := range envv {
|
||||
i := 0
|
||||
for i < len(v) && v[i] != '=' {
|
||||
i++
|
||||
}
|
||||
|
||||
fd, e := Create("/env/"+v[:i], O_WRONLY, 0666)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
_, e = Write(fd, []byte(v[i+1:]))
|
||||
if e != nil {
|
||||
Close(fd)
|
||||
return e
|
||||
}
|
||||
Close(fd)
|
||||
}
|
||||
}
|
||||
|
||||
argv0p, err := BytePtrFromString(argv0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
argvp, err := SlicePtrFromStrings(argv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, _, e1 := Syscall(SYS_EXEC,
|
||||
uintptr(unsafe.Pointer(argv0p)),
|
||||
uintptr(unsafe.Pointer(&argvp[0])),
|
||||
0)
|
||||
|
||||
return e1
|
||||
}
|
||||
|
||||
// WaitProcess waits until the pid of a
|
||||
// running process is found in the queue of
|
||||
// wait messages. It is used in conjunction
|
||||
// with ForkExec/StartProcess to wait for a
|
||||
// running process to exit.
|
||||
func WaitProcess(pid int, w *Waitmsg) (err error) {
|
||||
procs.Lock()
|
||||
ch := procs.waits[pid]
|
||||
procs.Unlock()
|
||||
|
||||
var wmsg *waitErr
|
||||
if ch != nil {
|
||||
wmsg = <-ch
|
||||
procs.Lock()
|
||||
if procs.waits[pid] == ch {
|
||||
delete(procs.waits, pid)
|
||||
}
|
||||
procs.Unlock()
|
||||
}
|
||||
if wmsg == nil {
|
||||
// ch was missing or ch is closed
|
||||
return NewError("process not found")
|
||||
}
|
||||
if wmsg.err != nil {
|
||||
return wmsg.err
|
||||
}
|
||||
if w != nil {
|
||||
*w = wmsg.Waitmsg
|
||||
}
|
||||
return nil
|
||||
}
|
||||
263
plan9/mkall.sh
Executable file
263
plan9/mkall.sh
Executable file
@@ -0,0 +1,263 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright 2009 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.
|
||||
|
||||
# The syscall package provides access to the raw system call
|
||||
# interface of the underlying operating system. Porting Go to
|
||||
# a new architecture/operating system combination requires
|
||||
# some manual effort, though there are tools that automate
|
||||
# much of the process. The auto-generated files have names
|
||||
# beginning with z.
|
||||
#
|
||||
# This script runs or (given -n) prints suggested commands to generate z files
|
||||
# for the current system. Running those commands is not automatic.
|
||||
# This script is documentation more than anything else.
|
||||
#
|
||||
# * asm_${GOOS}_${GOARCH}.s
|
||||
#
|
||||
# This hand-written assembly file implements system call dispatch.
|
||||
# There are three entry points:
|
||||
#
|
||||
# func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr);
|
||||
# func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
|
||||
# func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr);
|
||||
#
|
||||
# The first and second are the standard ones; they differ only in
|
||||
# how many arguments can be passed to the kernel.
|
||||
# The third is for low-level use by the ForkExec wrapper;
|
||||
# unlike the first two, it does not call into the scheduler to
|
||||
# let it know that a system call is running.
|
||||
#
|
||||
# * syscall_${GOOS}.go
|
||||
#
|
||||
# This hand-written Go file implements system calls that need
|
||||
# special handling and lists "//sys" comments giving prototypes
|
||||
# for ones that can be auto-generated. Mksyscall reads those
|
||||
# comments to generate the stubs.
|
||||
#
|
||||
# * syscall_${GOOS}_${GOARCH}.go
|
||||
#
|
||||
# Same as syscall_${GOOS}.go except that it contains code specific
|
||||
# to ${GOOS} on one particular architecture.
|
||||
#
|
||||
# * types_${GOOS}.c
|
||||
#
|
||||
# This hand-written C file includes standard C headers and then
|
||||
# creates typedef or enum names beginning with a dollar sign
|
||||
# (use of $ in variable names is a gcc extension). The hardest
|
||||
# part about preparing this file is figuring out which headers to
|
||||
# include and which symbols need to be #defined to get the
|
||||
# actual data structures that pass through to the kernel system calls.
|
||||
# Some C libraries present alternate versions for binary compatibility
|
||||
# and translate them on the way in and out of system calls, but
|
||||
# there is almost always a #define that can get the real ones.
|
||||
# See types_darwin.c and types_linux.c for examples.
|
||||
#
|
||||
# * zerror_${GOOS}_${GOARCH}.go
|
||||
#
|
||||
# This machine-generated file defines the system's error numbers,
|
||||
# error strings, and signal numbers. The generator is "mkerrors.sh".
|
||||
# Usually no arguments are needed, but mkerrors.sh will pass its
|
||||
# arguments on to godefs.
|
||||
#
|
||||
# * zsyscall_${GOOS}_${GOARCH}.go
|
||||
#
|
||||
# Generated by mksyscall.pl; see syscall_${GOOS}.go above.
|
||||
#
|
||||
# * zsysnum_${GOOS}_${GOARCH}.go
|
||||
#
|
||||
# Generated by mksysnum_${GOOS}.
|
||||
#
|
||||
# * ztypes_${GOOS}_${GOARCH}.go
|
||||
#
|
||||
# Generated by godefs; see types_${GOOS}.c above.
|
||||
|
||||
GOOSARCH="${GOOS}_${GOARCH}"
|
||||
|
||||
# defaults
|
||||
mksyscall="./mksyscall.pl"
|
||||
mkerrors="./mkerrors.sh"
|
||||
zerrors="zerrors_$GOOSARCH.go"
|
||||
mksysctl=""
|
||||
zsysctl="zsysctl_$GOOSARCH.go"
|
||||
mksysnum=
|
||||
mktypes=
|
||||
run="sh"
|
||||
|
||||
case "$1" in
|
||||
-syscalls)
|
||||
for i in zsyscall*go
|
||||
do
|
||||
sed 1q $i | sed 's;^// ;;' | sh > _$i && gofmt < _$i > $i
|
||||
rm _$i
|
||||
done
|
||||
exit 0
|
||||
;;
|
||||
-n)
|
||||
run="cat"
|
||||
shift
|
||||
esac
|
||||
|
||||
case "$#" in
|
||||
0)
|
||||
;;
|
||||
*)
|
||||
echo 'usage: mkall.sh [-n]' 1>&2
|
||||
exit 2
|
||||
esac
|
||||
|
||||
case "$GOOSARCH" in
|
||||
_* | *_ | _)
|
||||
echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
darwin_386)
|
||||
mkerrors="$mkerrors -m32"
|
||||
mksyscall="./mksyscall.pl -l32"
|
||||
mksysnum="./mksysnum_darwin.pl /usr/include/sys/syscall.h"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
darwin_amd64)
|
||||
mkerrors="$mkerrors -m64"
|
||||
mksysnum="./mksysnum_darwin.pl /usr/include/sys/syscall.h"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
dragonfly_386)
|
||||
mkerrors="$mkerrors -m32"
|
||||
mksyscall="./mksyscall.pl -l32 -dragonfly"
|
||||
mksysnum="curl -s 'http://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/sys/kern/syscalls.master' | ./mksysnum_dragonfly.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
dragonfly_amd64)
|
||||
mkerrors="$mkerrors -m64"
|
||||
mksyscall="./mksyscall.pl -dragonfly"
|
||||
mksysnum="curl -s 'http://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/sys/kern/syscalls.master' | ./mksysnum_dragonfly.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
freebsd_386)
|
||||
mkerrors="$mkerrors -m32"
|
||||
mksyscall="./mksyscall.pl -l32"
|
||||
mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
freebsd_amd64)
|
||||
mkerrors="$mkerrors -m64"
|
||||
mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
freebsd_arm)
|
||||
mkerrors="$mkerrors"
|
||||
mksyscall="./mksyscall.pl -l32 -arm"
|
||||
mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
|
||||
# Let the type of C char be singed for making the bare syscall
|
||||
# API consistent across over platforms.
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
|
||||
;;
|
||||
linux_386)
|
||||
mkerrors="$mkerrors -m32"
|
||||
mksyscall="./mksyscall.pl -l32"
|
||||
mksysnum="./mksysnum_linux.pl /usr/include/asm/unistd_32.h"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
linux_amd64)
|
||||
unistd_h=$(ls -1 /usr/include/asm/unistd_64.h /usr/include/x86_64-linux-gnu/asm/unistd_64.h 2>/dev/null | head -1)
|
||||
if [ "$unistd_h" = "" ]; then
|
||||
echo >&2 cannot find unistd_64.h
|
||||
exit 1
|
||||
fi
|
||||
mkerrors="$mkerrors -m64"
|
||||
mksysnum="./mksysnum_linux.pl $unistd_h"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
linux_arm)
|
||||
mkerrors="$mkerrors"
|
||||
mksyscall="./mksyscall.pl -l32 -arm"
|
||||
mksysnum="curl -s 'http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/plain/arch/arm/include/uapi/asm/unistd.h' | ./mksysnum_linux.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
nacl_386)
|
||||
mkerrors=""
|
||||
mksyscall="./mksyscall.pl -l32 -nacl"
|
||||
mksysnum=""
|
||||
mktypes=""
|
||||
;;
|
||||
nacl_amd64p32)
|
||||
mkerrors=""
|
||||
mksyscall="./mksyscall.pl -nacl"
|
||||
mksysnum=""
|
||||
mktypes=""
|
||||
;;
|
||||
netbsd_386)
|
||||
mkerrors="$mkerrors -m32"
|
||||
mksyscall="./mksyscall.pl -l32 -netbsd"
|
||||
mksysnum="curl -s 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_netbsd.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
netbsd_amd64)
|
||||
mkerrors="$mkerrors -m64"
|
||||
mksyscall="./mksyscall.pl -netbsd"
|
||||
mksysnum="curl -s 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_netbsd.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
openbsd_386)
|
||||
mkerrors="$mkerrors -m32"
|
||||
mksyscall="./mksyscall.pl -l32 -openbsd"
|
||||
mksysctl="./mksysctl_openbsd.pl"
|
||||
zsysctl="zsysctl_openbsd.go"
|
||||
mksysnum="curl -s 'http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
openbsd_amd64)
|
||||
mkerrors="$mkerrors -m64"
|
||||
mksyscall="./mksyscall.pl -openbsd"
|
||||
mksysctl="./mksysctl_openbsd.pl"
|
||||
zsysctl="zsysctl_openbsd.go"
|
||||
mksysnum="curl -s 'http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
plan9_386)
|
||||
mkerrors=
|
||||
mksyscall="./mksyscall.pl -l32 -plan9"
|
||||
mksysnum="./mksysnum_plan9.sh /n/sources/plan9/sys/src/libc/9syscall/sys.h"
|
||||
mktypes="XXX"
|
||||
;;
|
||||
solaris_amd64)
|
||||
mksyscall="./mksyscall_solaris.pl"
|
||||
mkerrors="$mkerrors -m64"
|
||||
mksysnum=
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
windows_*)
|
||||
mksyscall=
|
||||
mkerrors=
|
||||
zerrors=
|
||||
;;
|
||||
*)
|
||||
echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
(
|
||||
if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >$zerrors"; fi
|
||||
case "$GOOS" in
|
||||
windows)
|
||||
echo "GOOS= GOARCH= go build mksyscall_windows.go"
|
||||
echo "./mksyscall_windows syscall_windows.go security_windows.go syscall_$GOOSARCH.go |gofmt >zsyscall_$GOOSARCH.go"
|
||||
echo "rm -f ./mksyscall_windows"
|
||||
;;
|
||||
*)
|
||||
syscall_goos="syscall_$GOOS.go"
|
||||
case "$GOOS" in
|
||||
darwin | dragonfly | freebsd | netbsd | openbsd)
|
||||
syscall_goos="syscall_bsd.go $syscall_goos"
|
||||
;;
|
||||
esac
|
||||
if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos syscall_$GOOSARCH.go |gofmt >zsyscall_$GOOSARCH.go"; fi
|
||||
;;
|
||||
esac
|
||||
if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
|
||||
if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
|
||||
if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go |gofmt >ztypes_$GOOSARCH.go"; fi
|
||||
) | $run
|
||||
433
plan9/mkerrors.sh
Executable file
433
plan9/mkerrors.sh
Executable file
@@ -0,0 +1,433 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright 2009 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.
|
||||
|
||||
# Generate Go code listing errors and other #defined constant
|
||||
# values (ENAMETOOLONG etc.), by asking the preprocessor
|
||||
# about the definitions.
|
||||
|
||||
unset LANG
|
||||
export LC_ALL=C
|
||||
export LC_CTYPE=C
|
||||
|
||||
CC=${CC:-gcc}
|
||||
|
||||
uname=$(uname)
|
||||
|
||||
includes_Darwin='
|
||||
#define _DARWIN_C_SOURCE
|
||||
#define KERNEL
|
||||
#define _DARWIN_USE_64_BIT_INODE
|
||||
#include <sys/types.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/wait.h>
|
||||
#include <net/bpf.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_mroute.h>
|
||||
#include <termios.h>
|
||||
'
|
||||
|
||||
includes_DragonFly='
|
||||
#include <sys/types.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/bpf.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
#include <termios.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <net/ip_mroute/ip_mroute.h>
|
||||
'
|
||||
|
||||
includes_FreeBSD='
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/bpf.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
#include <termios.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_mroute.h>
|
||||
|
||||
#if __FreeBSD__ >= 10
|
||||
#define IFT_CARP 0xf8 // IFT_CARP is deprecated in FreeBSD 10
|
||||
#undef SIOCAIFADDR
|
||||
#define SIOCAIFADDR _IOW(105, 26, struct oifaliasreq) // ifaliasreq contains if_data
|
||||
#undef SIOCSIFPHYADDR
|
||||
#define SIOCSIFPHYADDR _IOW(105, 70, struct oifaliasreq) // ifaliasreq contains if_data
|
||||
#endif
|
||||
'
|
||||
|
||||
includes_Linux='
|
||||
#define _LARGEFILE_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <bits/sockaddr.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if_tun.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <linux/if_addr.h>
|
||||
#include <linux/filter.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/icmpv6.h>
|
||||
#include <net/route.h>
|
||||
#include <termios.h>
|
||||
|
||||
#ifndef MSG_FASTOPEN
|
||||
#define MSG_FASTOPEN 0x20000000
|
||||
#endif
|
||||
'
|
||||
|
||||
includes_NetBSD='
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/termios.h>
|
||||
#include <sys/ttycom.h>
|
||||
#include <sys/wait.h>
|
||||
#include <net/bpf.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_mroute.h>
|
||||
#include <netinet/if_ether.h>
|
||||
|
||||
// Needed since <sys/param.h> refers to it...
|
||||
#define schedppq 1
|
||||
'
|
||||
|
||||
includes_OpenBSD='
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/termios.h>
|
||||
#include <sys/ttycom.h>
|
||||
#include <sys/wait.h>
|
||||
#include <net/bpf.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/if_var.h>
|
||||
#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_mroute.h>
|
||||
#include <netinet/if_ether.h>
|
||||
#include <net/if_bridge.h>
|
||||
|
||||
// We keep some constants not supported in OpenBSD 5.5 and beyond for
|
||||
// the promise of compatibility.
|
||||
#define EMUL_ENABLED 0x1
|
||||
#define EMUL_NATIVE 0x2
|
||||
#define IPV6_FAITH 0x1d
|
||||
#define IPV6_OPTIONS 0x1
|
||||
#define IPV6_RTHDR_STRICT 0x1
|
||||
#define IPV6_SOCKOPT_RESERVED1 0x3
|
||||
#define SIOCGIFGENERIC 0xc020693a
|
||||
#define SIOCSIFGENERIC 0x80206939
|
||||
#define WALTSIG 0x4
|
||||
'
|
||||
|
||||
includes_SunOS='
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/bpf.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
#include <termios.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_mroute.h>
|
||||
'
|
||||
|
||||
includes='
|
||||
#include <sys/types.h>
|
||||
#include <sys/file.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <errno.h>
|
||||
#include <sys/signal.h>
|
||||
#include <signal.h>
|
||||
#include <sys/resource.h>
|
||||
'
|
||||
|
||||
ccflags="$@"
|
||||
|
||||
# Write go tool cgo -godefs input.
|
||||
(
|
||||
echo package syscall
|
||||
echo
|
||||
echo '/*'
|
||||
indirect="includes_$(uname)"
|
||||
echo "${!indirect} $includes"
|
||||
echo '*/'
|
||||
echo 'import "C"'
|
||||
echo
|
||||
echo 'const ('
|
||||
|
||||
# The gcc command line prints all the #defines
|
||||
# it encounters while processing the input
|
||||
echo "${!indirect} $includes" | $CC -x c - -E -dM $ccflags |
|
||||
awk '
|
||||
$1 != "#define" || $2 ~ /\(/ || $3 == "" {next}
|
||||
|
||||
$2 ~ /^E([ABCD]X|[BIS]P|[SD]I|S|FL)$/ {next} # 386 registers
|
||||
$2 ~ /^(SIGEV_|SIGSTKSZ|SIGRT(MIN|MAX))/ {next}
|
||||
$2 ~ /^(SCM_SRCRT)$/ {next}
|
||||
$2 ~ /^(MAP_FAILED)$/ {next}
|
||||
|
||||
$2 !~ /^ETH_/ &&
|
||||
$2 !~ /^EPROC_/ &&
|
||||
$2 !~ /^EQUIV_/ &&
|
||||
$2 !~ /^EXPR_/ &&
|
||||
$2 ~ /^E[A-Z0-9_]+$/ ||
|
||||
$2 ~ /^B[0-9_]+$/ ||
|
||||
$2 ~ /^V[A-Z0-9]+$/ ||
|
||||
$2 ~ /^CS[A-Z0-9]/ ||
|
||||
$2 ~ /^I(SIG|CANON|CRNL|EXTEN|MAXBEL|STRIP|UTF8)$/ ||
|
||||
$2 ~ /^IGN/ ||
|
||||
$2 ~ /^IX(ON|ANY|OFF)$/ ||
|
||||
$2 ~ /^IN(LCR|PCK)$/ ||
|
||||
$2 ~ /(^FLU?SH)|(FLU?SH$)/ ||
|
||||
$2 ~ /^C(LOCAL|READ)$/ ||
|
||||
$2 == "BRKINT" ||
|
||||
$2 == "HUPCL" ||
|
||||
$2 == "PENDIN" ||
|
||||
$2 == "TOSTOP" ||
|
||||
$2 ~ /^PAR/ ||
|
||||
$2 ~ /^SIG[^_]/ ||
|
||||
$2 ~ /^O[CNPFP][A-Z]+[^_][A-Z]+$/ ||
|
||||
$2 ~ /^IN_/ ||
|
||||
$2 ~ /^LOCK_(SH|EX|NB|UN)$/ ||
|
||||
$2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|ICMP6|TCP|EVFILT|NOTE|EV|SHUT|PROT|MAP|PACKET|MSG|SCM|MCL|DT|MADV|PR)_/ ||
|
||||
$2 == "ICMPV6_FILTER" ||
|
||||
$2 == "SOMAXCONN" ||
|
||||
$2 == "NAME_MAX" ||
|
||||
$2 == "IFNAMSIZ" ||
|
||||
$2 ~ /^CTL_(MAXNAME|NET|QUERY)$/ ||
|
||||
$2 ~ /^SYSCTL_VERS/ ||
|
||||
$2 ~ /^(MS|MNT)_/ ||
|
||||
$2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ ||
|
||||
$2 ~ /^(O|F|FD|NAME|S|PTRACE|PT)_/ ||
|
||||
$2 ~ /^LINUX_REBOOT_CMD_/ ||
|
||||
$2 ~ /^LINUX_REBOOT_MAGIC[12]$/ ||
|
||||
$2 !~ "NLA_TYPE_MASK" &&
|
||||
$2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P)_/ ||
|
||||
$2 ~ /^SIOC/ ||
|
||||
$2 ~ /^TIOC/ ||
|
||||
$2 !~ "RTF_BITS" &&
|
||||
$2 ~ /^(IFF|IFT|NET_RT|RTM|RTF|RTV|RTA|RTAX)_/ ||
|
||||
$2 ~ /^BIOC/ ||
|
||||
$2 ~ /^RUSAGE_(SELF|CHILDREN|THREAD)/ ||
|
||||
$2 ~ /^RLIMIT_(AS|CORE|CPU|DATA|FSIZE|NOFILE|STACK)|RLIM_INFINITY/ ||
|
||||
$2 ~ /^PRIO_(PROCESS|PGRP|USER)/ ||
|
||||
$2 ~ /^CLONE_[A-Z_]+/ ||
|
||||
$2 !~ /^(BPF_TIMEVAL)$/ &&
|
||||
$2 ~ /^(BPF|DLT)_/ ||
|
||||
$2 !~ "WMESGLEN" &&
|
||||
$2 ~ /^W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", $2, $2)}
|
||||
$2 ~ /^__WCOREFLAG$/ {next}
|
||||
$2 ~ /^__W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", substr($2,3), $2)}
|
||||
|
||||
{next}
|
||||
' | sort
|
||||
|
||||
echo ')'
|
||||
) >_const.go
|
||||
|
||||
# Pull out the error names for later.
|
||||
errors=$(
|
||||
echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags |
|
||||
awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print $2 }' |
|
||||
sort
|
||||
)
|
||||
|
||||
# Pull out the signal names for later.
|
||||
signals=$(
|
||||
echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
|
||||
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' |
|
||||
egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' |
|
||||
sort
|
||||
)
|
||||
|
||||
# Again, writing regexps to a file.
|
||||
echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags |
|
||||
awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print "^\t" $2 "[ \t]*=" }' |
|
||||
sort >_error.grep
|
||||
echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
|
||||
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' |
|
||||
egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' |
|
||||
sort >_signal.grep
|
||||
|
||||
echo '// mkerrors.sh' "$@"
|
||||
echo '// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT'
|
||||
echo
|
||||
go tool cgo -godefs -- "$@" _const.go >_error.out
|
||||
cat _error.out | grep -vf _error.grep | grep -vf _signal.grep
|
||||
echo
|
||||
echo '// Errors'
|
||||
echo 'const ('
|
||||
cat _error.out | grep -f _error.grep | sed 's/=\(.*\)/= Errno(\1)/'
|
||||
echo ')'
|
||||
|
||||
echo
|
||||
echo '// Signals'
|
||||
echo 'const ('
|
||||
cat _error.out | grep -f _signal.grep | sed 's/=\(.*\)/= Signal(\1)/'
|
||||
echo ')'
|
||||
|
||||
# Run C program to print error and syscall strings.
|
||||
(
|
||||
echo -E "
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define nelem(x) (sizeof(x)/sizeof((x)[0]))
|
||||
|
||||
enum { A = 'A', Z = 'Z', a = 'a', z = 'z' }; // avoid need for single quotes below
|
||||
|
||||
int errors[] = {
|
||||
"
|
||||
for i in $errors
|
||||
do
|
||||
echo -E ' '$i,
|
||||
done
|
||||
|
||||
echo -E "
|
||||
};
|
||||
|
||||
int signals[] = {
|
||||
"
|
||||
for i in $signals
|
||||
do
|
||||
echo -E ' '$i,
|
||||
done
|
||||
|
||||
# Use -E because on some systems bash builtin interprets \n itself.
|
||||
echo -E '
|
||||
};
|
||||
|
||||
static int
|
||||
intcmp(const void *a, const void *b)
|
||||
{
|
||||
return *(int*)a - *(int*)b;
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int i, j, e;
|
||||
char buf[1024], *p;
|
||||
|
||||
printf("\n\n// Error table\n");
|
||||
printf("var errors = [...]string {\n");
|
||||
qsort(errors, nelem(errors), sizeof errors[0], intcmp);
|
||||
for(i=0; i<nelem(errors); i++) {
|
||||
e = errors[i];
|
||||
if(i > 0 && errors[i-1] == e)
|
||||
continue;
|
||||
strcpy(buf, strerror(e));
|
||||
// lowercase first letter: Bad -> bad, but STREAM -> STREAM.
|
||||
if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
|
||||
buf[0] += a - A;
|
||||
printf("\t%d: \"%s\",\n", e, buf);
|
||||
}
|
||||
printf("}\n\n");
|
||||
|
||||
printf("\n\n// Signal table\n");
|
||||
printf("var signals = [...]string {\n");
|
||||
qsort(signals, nelem(signals), sizeof signals[0], intcmp);
|
||||
for(i=0; i<nelem(signals); i++) {
|
||||
e = signals[i];
|
||||
if(i > 0 && signals[i-1] == e)
|
||||
continue;
|
||||
strcpy(buf, strsignal(e));
|
||||
// lowercase first letter: Bad -> bad, but STREAM -> STREAM.
|
||||
if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
|
||||
buf[0] += a - A;
|
||||
// cut trailing : number.
|
||||
p = strrchr(buf, ":"[0]);
|
||||
if(p)
|
||||
*p = '\0';
|
||||
printf("\t%d: \"%s\",\n", e, buf);
|
||||
}
|
||||
printf("}\n\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
'
|
||||
) >_errors.c
|
||||
|
||||
$CC $ccflags -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors _const.go _error.grep _signal.grep _error.out
|
||||
313
plan9/mksyscall.pl
Executable file
313
plan9/mksyscall.pl
Executable file
@@ -0,0 +1,313 @@
|
||||
#!/usr/bin/env perl
|
||||
# Copyright 2009 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.
|
||||
|
||||
# This program reads a file containing function prototypes
|
||||
# (like syscall_darwin.go) and generates system call bodies.
|
||||
# The prototypes are marked by lines beginning with "//sys"
|
||||
# and read like func declarations if //sys is replaced by func, but:
|
||||
# * The parameter lists must give a name for each argument.
|
||||
# This includes return parameters.
|
||||
# * The parameter lists must give a type for each argument:
|
||||
# the (x, y, z int) shorthand is not allowed.
|
||||
# * If the return parameter is an error number, it must be named errno.
|
||||
|
||||
# A line beginning with //sysnb is like //sys, except that the
|
||||
# goroutine will not be suspended during the execution of the system
|
||||
# call. This must only be used for system calls which can never
|
||||
# block, as otherwise the system call could cause all goroutines to
|
||||
# hang.
|
||||
|
||||
use strict;
|
||||
|
||||
my $cmdline = "mksyscall.pl " . join(' ', @ARGV);
|
||||
my $errors = 0;
|
||||
my $_32bit = "";
|
||||
my $plan9 = 0;
|
||||
my $openbsd = 0;
|
||||
my $netbsd = 0;
|
||||
my $dragonfly = 0;
|
||||
my $nacl = 0;
|
||||
my $arm = 0; # 64-bit value should use (even, odd)-pair
|
||||
|
||||
if($ARGV[0] eq "-b32") {
|
||||
$_32bit = "big-endian";
|
||||
shift;
|
||||
} elsif($ARGV[0] eq "-l32") {
|
||||
$_32bit = "little-endian";
|
||||
shift;
|
||||
}
|
||||
if($ARGV[0] eq "-plan9") {
|
||||
$plan9 = 1;
|
||||
shift;
|
||||
}
|
||||
if($ARGV[0] eq "-openbsd") {
|
||||
$openbsd = 1;
|
||||
shift;
|
||||
}
|
||||
if($ARGV[0] eq "-netbsd") {
|
||||
$netbsd = 1;
|
||||
shift;
|
||||
}
|
||||
if($ARGV[0] eq "-dragonfly") {
|
||||
$dragonfly = 1;
|
||||
shift;
|
||||
}
|
||||
if($ARGV[0] eq "-nacl") {
|
||||
$nacl = 1;
|
||||
shift;
|
||||
}
|
||||
if($ARGV[0] eq "-arm") {
|
||||
$arm = 1;
|
||||
shift;
|
||||
}
|
||||
|
||||
if($ARGV[0] =~ /^-/) {
|
||||
print STDERR "usage: mksyscall.pl [-b32 | -l32] [file ...]\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
sub parseparamlist($) {
|
||||
my ($list) = @_;
|
||||
$list =~ s/^\s*//;
|
||||
$list =~ s/\s*$//;
|
||||
if($list eq "") {
|
||||
return ();
|
||||
}
|
||||
return split(/\s*,\s*/, $list);
|
||||
}
|
||||
|
||||
sub parseparam($) {
|
||||
my ($p) = @_;
|
||||
if($p !~ /^(\S*) (\S*)$/) {
|
||||
print STDERR "$ARGV:$.: malformed parameter: $p\n";
|
||||
$errors = 1;
|
||||
return ("xx", "int");
|
||||
}
|
||||
return ($1, $2);
|
||||
}
|
||||
|
||||
my $text = "";
|
||||
while(<>) {
|
||||
chomp;
|
||||
s/\s+/ /g;
|
||||
s/^\s+//;
|
||||
s/\s+$//;
|
||||
my $nonblock = /^\/\/sysnb /;
|
||||
next if !/^\/\/sys / && !$nonblock;
|
||||
|
||||
# Line must be of the form
|
||||
# func Open(path string, mode int, perm int) (fd int, errno error)
|
||||
# Split into name, in params, out params.
|
||||
if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*((?i)SYS_[A-Z0-9_]+))?$/) {
|
||||
print STDERR "$ARGV:$.: malformed //sys declaration\n";
|
||||
$errors = 1;
|
||||
next;
|
||||
}
|
||||
my ($func, $in, $out, $sysname) = ($2, $3, $4, $5);
|
||||
|
||||
# Split argument lists on comma.
|
||||
my @in = parseparamlist($in);
|
||||
my @out = parseparamlist($out);
|
||||
|
||||
# Try in vain to keep people from editing this file.
|
||||
# The theory is that they jump into the middle of the file
|
||||
# without reading the header.
|
||||
$text .= "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n";
|
||||
|
||||
# Go function header.
|
||||
my $out_decl = @out ? sprintf(" (%s)", join(', ', @out)) : "";
|
||||
$text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out_decl;
|
||||
|
||||
# Check if err return available
|
||||
my $errvar = "";
|
||||
foreach my $p (@out) {
|
||||
my ($name, $type) = parseparam($p);
|
||||
if($type eq "error") {
|
||||
$errvar = $name;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
# Prepare arguments to Syscall.
|
||||
my @args = ();
|
||||
my $n = 0;
|
||||
foreach my $p (@in) {
|
||||
my ($name, $type) = parseparam($p);
|
||||
if($type =~ /^\*/) {
|
||||
push @args, "uintptr(unsafe.Pointer($name))";
|
||||
} elsif($type eq "string" && $errvar ne "") {
|
||||
$text .= "\tvar _p$n *byte\n";
|
||||
$text .= "\t_p$n, $errvar = BytePtrFromString($name)\n";
|
||||
$text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n";
|
||||
push @args, "uintptr(unsafe.Pointer(_p$n))";
|
||||
$n++;
|
||||
} elsif($type eq "string") {
|
||||
print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n";
|
||||
$text .= "\tvar _p$n *byte\n";
|
||||
$text .= "\t_p$n, _ = BytePtrFromString($name)\n";
|
||||
push @args, "uintptr(unsafe.Pointer(_p$n))";
|
||||
$n++;
|
||||
} elsif($type =~ /^\[\](.*)/) {
|
||||
# Convert slice into pointer, length.
|
||||
# Have to be careful not to take address of &a[0] if len == 0:
|
||||
# pass dummy pointer in that case.
|
||||
# Used to pass nil, but some OSes or simulators reject write(fd, nil, 0).
|
||||
$text .= "\tvar _p$n unsafe.Pointer\n";
|
||||
$text .= "\tif len($name) > 0 {\n\t\t_p$n = unsafe.Pointer(\&${name}[0])\n\t}";
|
||||
$text .= " else {\n\t\t_p$n = unsafe.Pointer(&_zero)\n\t}";
|
||||
$text .= "\n";
|
||||
push @args, "uintptr(_p$n)", "uintptr(len($name))";
|
||||
$n++;
|
||||
} elsif($type eq "int64" && ($openbsd || $netbsd)) {
|
||||
push @args, "0";
|
||||
if($_32bit eq "big-endian") {
|
||||
push @args, "uintptr($name>>32)", "uintptr($name)";
|
||||
} elsif($_32bit eq "little-endian") {
|
||||
push @args, "uintptr($name)", "uintptr($name>>32)";
|
||||
} else {
|
||||
push @args, "uintptr($name)";
|
||||
}
|
||||
} elsif($type eq "int64" && $dragonfly) {
|
||||
if ($func !~ /^extp(read|write)/i) {
|
||||
push @args, "0";
|
||||
}
|
||||
if($_32bit eq "big-endian") {
|
||||
push @args, "uintptr($name>>32)", "uintptr($name)";
|
||||
} elsif($_32bit eq "little-endian") {
|
||||
push @args, "uintptr($name)", "uintptr($name>>32)";
|
||||
} else {
|
||||
push @args, "uintptr($name)";
|
||||
}
|
||||
} elsif($type eq "int64" && $_32bit ne "") {
|
||||
if(@args % 2 && $arm) {
|
||||
# arm abi specifies 64-bit argument uses
|
||||
# (even, odd) pair
|
||||
push @args, "0"
|
||||
}
|
||||
if($_32bit eq "big-endian") {
|
||||
push @args, "uintptr($name>>32)", "uintptr($name)";
|
||||
} else {
|
||||
push @args, "uintptr($name)", "uintptr($name>>32)";
|
||||
}
|
||||
} else {
|
||||
push @args, "uintptr($name)";
|
||||
}
|
||||
}
|
||||
|
||||
# Determine which form to use; pad args with zeros.
|
||||
my $asm = "Syscall";
|
||||
if ($nonblock) {
|
||||
$asm = "RawSyscall";
|
||||
}
|
||||
if(@args <= 3) {
|
||||
while(@args < 3) {
|
||||
push @args, "0";
|
||||
}
|
||||
} elsif(@args <= 6) {
|
||||
$asm .= "6";
|
||||
while(@args < 6) {
|
||||
push @args, "0";
|
||||
}
|
||||
} elsif(@args <= 9) {
|
||||
$asm .= "9";
|
||||
while(@args < 9) {
|
||||
push @args, "0";
|
||||
}
|
||||
} else {
|
||||
print STDERR "$ARGV:$.: too many arguments to system call\n";
|
||||
}
|
||||
|
||||
# System call number.
|
||||
if($sysname eq "") {
|
||||
$sysname = "SYS_$func";
|
||||
$sysname =~ s/([a-z])([A-Z])/${1}_$2/g; # turn FooBar into Foo_Bar
|
||||
$sysname =~ y/a-z/A-Z/;
|
||||
if($nacl) {
|
||||
$sysname =~ y/A-Z/a-z/;
|
||||
}
|
||||
}
|
||||
|
||||
# Actual call.
|
||||
my $args = join(', ', @args);
|
||||
my $call = "$asm($sysname, $args)";
|
||||
|
||||
# Assign return values.
|
||||
my $body = "";
|
||||
my @ret = ("_", "_", "_");
|
||||
my $do_errno = 0;
|
||||
for(my $i=0; $i<@out; $i++) {
|
||||
my $p = $out[$i];
|
||||
my ($name, $type) = parseparam($p);
|
||||
my $reg = "";
|
||||
if($name eq "err" && !$plan9) {
|
||||
$reg = "e1";
|
||||
$ret[2] = $reg;
|
||||
$do_errno = 1;
|
||||
} elsif($name eq "err" && $plan9) {
|
||||
$ret[0] = "r0";
|
||||
$ret[2] = "e1";
|
||||
next;
|
||||
} else {
|
||||
$reg = sprintf("r%d", $i);
|
||||
$ret[$i] = $reg;
|
||||
}
|
||||
if($type eq "bool") {
|
||||
$reg = "$reg != 0";
|
||||
}
|
||||
if($type eq "int64" && $_32bit ne "") {
|
||||
# 64-bit number in r1:r0 or r0:r1.
|
||||
if($i+2 > @out) {
|
||||
print STDERR "$ARGV:$.: not enough registers for int64 return\n";
|
||||
}
|
||||
if($_32bit eq "big-endian") {
|
||||
$reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i, $i+1);
|
||||
} else {
|
||||
$reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i+1, $i);
|
||||
}
|
||||
$ret[$i] = sprintf("r%d", $i);
|
||||
$ret[$i+1] = sprintf("r%d", $i+1);
|
||||
}
|
||||
if($reg ne "e1" || $plan9) {
|
||||
$body .= "\t$name = $type($reg)\n";
|
||||
}
|
||||
}
|
||||
if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") {
|
||||
$text .= "\t$call\n";
|
||||
} else {
|
||||
$text .= "\t$ret[0], $ret[1], $ret[2] := $call\n";
|
||||
}
|
||||
$text .= $body;
|
||||
|
||||
if ($plan9 && $ret[2] eq "e1") {
|
||||
$text .= "\tif int32(r0) == -1 {\n";
|
||||
$text .= "\t\terr = e1\n";
|
||||
$text .= "\t}\n";
|
||||
} elsif ($do_errno) {
|
||||
$text .= "\tif e1 != 0 {\n";
|
||||
$text .= "\t\terr = e1\n";
|
||||
$text .= "\t}\n";
|
||||
}
|
||||
$text .= "\treturn\n";
|
||||
$text .= "}\n\n";
|
||||
}
|
||||
|
||||
chomp $text;
|
||||
chomp $text;
|
||||
|
||||
if($errors) {
|
||||
exit 1;
|
||||
}
|
||||
|
||||
print <<EOF;
|
||||
// $cmdline
|
||||
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
$text
|
||||
EOF
|
||||
exit 0;
|
||||
25
plan9/mksysnum_plan9.sh
Executable file
25
plan9/mksysnum_plan9.sh
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/bin/sh
|
||||
# Copyright 2009 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.# Copyright 2009 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.
|
||||
|
||||
COMMAND="mksysnum_plan9.sh $@"
|
||||
|
||||
cat <<EOF
|
||||
// $COMMAND
|
||||
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
|
||||
|
||||
package syscall
|
||||
|
||||
const(
|
||||
EOF
|
||||
|
||||
SP='[ ]' # space or tab
|
||||
sed "s/^#define${SP}\\([A-Z0-9_][A-Z0-9_]*\\)${SP}${SP}*\\([0-9][0-9]*\\)/SYS_\\1=\\2/g" \
|
||||
< $1 | grep -v SYS__
|
||||
|
||||
cat <<EOF
|
||||
)
|
||||
EOF
|
||||
30
plan9/race.go
Normal file
30
plan9/race.go
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright 2012 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 race
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const raceenabled = true
|
||||
|
||||
func raceAcquire(addr unsafe.Pointer) {
|
||||
runtime.RaceAcquire(addr)
|
||||
}
|
||||
|
||||
func raceReleaseMerge(addr unsafe.Pointer) {
|
||||
runtime.RaceReleaseMerge(addr)
|
||||
}
|
||||
|
||||
func raceReadRange(addr unsafe.Pointer, len int) {
|
||||
runtime.RaceReadRange(addr, len)
|
||||
}
|
||||
|
||||
func raceWriteRange(addr unsafe.Pointer, len int) {
|
||||
runtime.RaceWriteRange(addr, len)
|
||||
}
|
||||
25
plan9/race0.go
Normal file
25
plan9/race0.go
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2012 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 !race
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const raceenabled = false
|
||||
|
||||
func raceAcquire(addr unsafe.Pointer) {
|
||||
}
|
||||
|
||||
func raceReleaseMerge(addr unsafe.Pointer) {
|
||||
}
|
||||
|
||||
func raceReadRange(addr unsafe.Pointer, len int) {
|
||||
}
|
||||
|
||||
func raceWriteRange(addr unsafe.Pointer, len int) {
|
||||
}
|
||||
20
plan9/str.go
Normal file
20
plan9/str.go
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
package syscall
|
||||
|
||||
func itoa(val int) string { // do it here rather than with fmt to avoid dependency
|
||||
if val < 0 {
|
||||
return "-" + itoa(-val)
|
||||
}
|
||||
var buf [32]byte // big enough for int64
|
||||
i := len(buf) - 1
|
||||
for val >= 10 {
|
||||
buf[i] = byte(val%10 + '0')
|
||||
i--
|
||||
val /= 10
|
||||
}
|
||||
buf[i] = byte(val + '0')
|
||||
return string(buf[i:])
|
||||
}
|
||||
81
plan9/syscall.go
Normal file
81
plan9/syscall.go
Normal file
@@ -0,0 +1,81 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
// Package syscall contains an interface to the low-level operating system
|
||||
// primitives. The details vary depending on the underlying system, and
|
||||
// by default, godoc will display the syscall documentation for the current
|
||||
// system. If you want godoc to display syscall documentation for another
|
||||
// system, set $GOOS and $GOARCH to the desired system. For example, if
|
||||
// you want to view documentation for freebsd/arm on linux/amd64, set $GOOS
|
||||
// to freebsd and $GOARCH to arm.
|
||||
// The primary use of syscall is inside other packages that provide a more
|
||||
// portable interface to the system, such as "os", "time" and "net". Use
|
||||
// those packages rather than this one if you can.
|
||||
// For details of the functions and data types in this package consult
|
||||
// the manuals for the appropriate operating system.
|
||||
// These calls return err == nil to indicate success; otherwise
|
||||
// err is an operating system error describing the failure.
|
||||
// On most systems, that error has type syscall.Errno.
|
||||
package syscall
|
||||
|
||||
// StringByteSlice is deprecated. Use ByteSliceFromString instead.
|
||||
// If s contains a NUL byte this function panics instead of
|
||||
// returning an error.
|
||||
func StringByteSlice(s string) []byte {
|
||||
a, err := ByteSliceFromString(s)
|
||||
if err != nil {
|
||||
panic("syscall: string with NUL passed to StringByteSlice")
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// ByteSliceFromString returns a NUL-terminated slice of bytes
|
||||
// containing the text of s. If s contains a NUL byte at any
|
||||
// location, it returns (nil, EINVAL).
|
||||
func ByteSliceFromString(s string) ([]byte, error) {
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] == 0 {
|
||||
return nil, EINVAL
|
||||
}
|
||||
}
|
||||
a := make([]byte, len(s)+1)
|
||||
copy(a, s)
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// StringBytePtr is deprecated. Use BytePtrFromString instead.
|
||||
// If s contains a NUL byte this function panics instead of
|
||||
// returning an error.
|
||||
func StringBytePtr(s string) *byte { return &StringByteSlice(s)[0] }
|
||||
|
||||
// BytePtrFromString returns a pointer to a NUL-terminated array of
|
||||
// bytes containing the text of s. If s contains a NUL byte at any
|
||||
// location, it returns (nil, EINVAL).
|
||||
func BytePtrFromString(s string) (*byte, error) {
|
||||
a, err := ByteSliceFromString(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &a[0], nil
|
||||
}
|
||||
|
||||
// Single-word zero for use when we need a valid pointer to 0 bytes.
|
||||
// See mksyscall.pl.
|
||||
var _zero uintptr
|
||||
|
||||
func (ts *Timespec) Unix() (sec int64, nsec int64) {
|
||||
return int64(ts.Sec), int64(ts.Nsec)
|
||||
}
|
||||
|
||||
func (tv *Timeval) Unix() (sec int64, nsec int64) {
|
||||
return int64(tv.Sec), int64(tv.Usec) * 1000
|
||||
}
|
||||
|
||||
func (ts *Timespec) Nano() int64 {
|
||||
return int64(ts.Sec)*1e9 + int64(ts.Nsec)
|
||||
}
|
||||
|
||||
func (tv *Timeval) Nano() int64 {
|
||||
return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000
|
||||
}
|
||||
339
plan9/syscall_plan9.go
Normal file
339
plan9/syscall_plan9.go
Normal file
@@ -0,0 +1,339 @@
|
||||
// Copyright 2011 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.
|
||||
|
||||
// Plan 9 system calls.
|
||||
// This file is compiled as ordinary Go code,
|
||||
// but it is also input to mksyscall,
|
||||
// which parses the //sys lines and generates system call stubs.
|
||||
// Note that sometimes we use a lowercase //sys name and
|
||||
// wrap it in our own nicer implementation.
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
const ImplementsGetwd = true
|
||||
|
||||
// ErrorString implements Error's String method by returning itself.
|
||||
type ErrorString string
|
||||
|
||||
func (e ErrorString) Error() string { return string(e) }
|
||||
|
||||
// NewError converts s to an ErrorString, which satisfies the Error interface.
|
||||
func NewError(s string) error { return ErrorString(s) }
|
||||
|
||||
func (e ErrorString) Temporary() bool {
|
||||
return e == EINTR || e == EMFILE || e.Timeout()
|
||||
}
|
||||
|
||||
func (e ErrorString) Timeout() bool {
|
||||
return e == EBUSY || e == ETIMEDOUT
|
||||
}
|
||||
|
||||
// A Note is a string describing a process note.
|
||||
// It implements the os.Signal interface.
|
||||
type Note string
|
||||
|
||||
func (n Note) Signal() {}
|
||||
|
||||
func (n Note) String() string {
|
||||
return string(n)
|
||||
}
|
||||
|
||||
var (
|
||||
Stdin = 0
|
||||
Stdout = 1
|
||||
Stderr = 2
|
||||
)
|
||||
|
||||
// For testing: clients can set this flag to force
|
||||
// creation of IPv6 sockets to return EAFNOSUPPORT.
|
||||
var SocketDisableIPv6 bool
|
||||
|
||||
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err ErrorString)
|
||||
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err ErrorString)
|
||||
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
|
||||
func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
|
||||
|
||||
func atoi(b []byte) (n uint) {
|
||||
n = 0
|
||||
for i := 0; i < len(b); i++ {
|
||||
n = n*10 + uint(b[i]-'0')
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func cstring(s []byte) string {
|
||||
for i := range s {
|
||||
if s[i] == 0 {
|
||||
return string(s[0:i])
|
||||
}
|
||||
}
|
||||
return string(s)
|
||||
}
|
||||
|
||||
func errstr() string {
|
||||
var buf [ERRMAX]byte
|
||||
|
||||
RawSyscall(SYS_ERRSTR, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)), 0)
|
||||
|
||||
buf[len(buf)-1] = 0
|
||||
return cstring(buf[:])
|
||||
}
|
||||
|
||||
// Implemented in assembly to import from runtime.
|
||||
func exit(code int)
|
||||
|
||||
func Exit(code int) { exit(code) }
|
||||
|
||||
func readnum(path string) (uint, error) {
|
||||
var b [12]byte
|
||||
|
||||
fd, e := Open(path, O_RDONLY)
|
||||
if e != nil {
|
||||
return 0, e
|
||||
}
|
||||
defer Close(fd)
|
||||
|
||||
n, e := Pread(fd, b[:], 0)
|
||||
|
||||
if e != nil {
|
||||
return 0, e
|
||||
}
|
||||
|
||||
m := 0
|
||||
for ; m < n && b[m] == ' '; m++ {
|
||||
}
|
||||
|
||||
return atoi(b[m : n-1]), nil
|
||||
}
|
||||
|
||||
func Getpid() (pid int) {
|
||||
n, _ := readnum("#c/pid")
|
||||
return int(n)
|
||||
}
|
||||
|
||||
func Getppid() (ppid int) {
|
||||
n, _ := readnum("#c/ppid")
|
||||
return int(n)
|
||||
}
|
||||
|
||||
func Read(fd int, p []byte) (n int, err error) {
|
||||
return Pread(fd, p, -1)
|
||||
}
|
||||
|
||||
func Write(fd int, p []byte) (n int, err error) {
|
||||
return Pwrite(fd, p, -1)
|
||||
}
|
||||
|
||||
var ioSync int64
|
||||
|
||||
func Getwd() (wd string, err error) {
|
||||
fd, e := Open(".", O_RDONLY)
|
||||
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
defer Close(fd)
|
||||
|
||||
return Fd2path(fd)
|
||||
}
|
||||
|
||||
//sys fd2path(fd int, buf []byte) (err error)
|
||||
func Fd2path(fd int) (path string, err error) {
|
||||
var buf [512]byte
|
||||
|
||||
e := fd2path(fd, buf[:])
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
return cstring(buf[:]), nil
|
||||
}
|
||||
|
||||
//sys pipe(p *[2]_C_int) (err error)
|
||||
func Pipe(p []int) (err error) {
|
||||
if len(p) != 2 {
|
||||
return NewError("bad arg in system call")
|
||||
}
|
||||
var pp [2]_C_int
|
||||
err = pipe(&pp)
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
return
|
||||
}
|
||||
|
||||
// Underlying system call writes to newoffset via pointer.
|
||||
// Implemented in assembly to avoid allocation.
|
||||
func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
|
||||
|
||||
func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
|
||||
newoffset, e := seek(0, fd, offset, whence)
|
||||
|
||||
if newoffset == -1 {
|
||||
err = NewError(e)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Mkdir(path string, mode uint32) (err error) {
|
||||
fd, err := Create(path, O_RDONLY, DMDIR|mode)
|
||||
|
||||
if fd != -1 {
|
||||
Close(fd)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type Waitmsg struct {
|
||||
Pid int
|
||||
Time [3]uint32
|
||||
Msg string
|
||||
}
|
||||
|
||||
func (w Waitmsg) Exited() bool { return true }
|
||||
func (w Waitmsg) Signaled() bool { return false }
|
||||
|
||||
func (w Waitmsg) ExitStatus() int {
|
||||
if len(w.Msg) == 0 {
|
||||
// a normal exit returns no message
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
//sys await(s []byte) (n int, err error)
|
||||
func Await(w *Waitmsg) (err error) {
|
||||
var buf [512]byte
|
||||
var f [5][]byte
|
||||
|
||||
n, err := await(buf[:])
|
||||
|
||||
if err != nil || w == nil {
|
||||
return
|
||||
}
|
||||
|
||||
nf := 0
|
||||
p := 0
|
||||
for i := 0; i < n && nf < len(f)-1; i++ {
|
||||
if buf[i] == ' ' {
|
||||
f[nf] = buf[p:i]
|
||||
p = i + 1
|
||||
nf++
|
||||
}
|
||||
}
|
||||
f[nf] = buf[p:]
|
||||
nf++
|
||||
|
||||
if nf != len(f) {
|
||||
return NewError("invalid wait message")
|
||||
}
|
||||
w.Pid = int(atoi(f[0]))
|
||||
w.Time[0] = uint32(atoi(f[1]))
|
||||
w.Time[1] = uint32(atoi(f[2]))
|
||||
w.Time[2] = uint32(atoi(f[3]))
|
||||
w.Msg = cstring(f[4])
|
||||
if w.Msg == "''" {
|
||||
// await() returns '' for no error
|
||||
w.Msg = ""
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Unmount(name, old string) (err error) {
|
||||
oldp, err := BytePtrFromString(old)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oldptr := uintptr(unsafe.Pointer(oldp))
|
||||
|
||||
var r0 uintptr
|
||||
var e ErrorString
|
||||
|
||||
// bind(2) man page: If name is zero, everything bound or mounted upon old is unbound or unmounted.
|
||||
if name == "" {
|
||||
r0, _, e = Syscall(SYS_UNMOUNT, _zero, oldptr, 0)
|
||||
} else {
|
||||
namep, err := BytePtrFromString(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r0, _, e = Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(namep)), oldptr, 0)
|
||||
}
|
||||
|
||||
if int32(r0) == -1 {
|
||||
err = e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Fchdir(fd int) (err error) {
|
||||
path, err := Fd2path(fd)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return Chdir(path)
|
||||
}
|
||||
|
||||
type Timespec struct {
|
||||
Sec int32
|
||||
Nsec int32
|
||||
}
|
||||
|
||||
type Timeval struct {
|
||||
Sec int32
|
||||
Usec int32
|
||||
}
|
||||
|
||||
func NsecToTimeval(nsec int64) (tv Timeval) {
|
||||
nsec += 999 // round up to microsecond
|
||||
tv.Usec = int32(nsec % 1e9 / 1e3)
|
||||
tv.Sec = int32(nsec / 1e9)
|
||||
return
|
||||
}
|
||||
|
||||
func nsec() int64 {
|
||||
var scratch int64
|
||||
|
||||
r0, _, _ := Syscall(SYS_NSEC, uintptr(unsafe.Pointer(&scratch)), 0, 0)
|
||||
// TODO(aram): remove hack after I fix _nsec in the pc64 kernel.
|
||||
if r0 == 0 {
|
||||
return scratch
|
||||
}
|
||||
return int64(r0)
|
||||
}
|
||||
|
||||
func Gettimeofday(tv *Timeval) error {
|
||||
nsec := nsec()
|
||||
*tv = NsecToTimeval(nsec)
|
||||
return nil
|
||||
}
|
||||
|
||||
func Getpagesize() int { return 0x1000 }
|
||||
|
||||
func Getegid() (egid int) { return -1 }
|
||||
func Geteuid() (euid int) { return -1 }
|
||||
func Getgid() (gid int) { return -1 }
|
||||
func Getuid() (uid int) { return -1 }
|
||||
|
||||
func Getgroups() (gids []int, err error) {
|
||||
return make([]int, 0), nil
|
||||
}
|
||||
|
||||
//sys Dup(oldfd int, newfd int) (fd int, err error)
|
||||
//sys Open(path string, mode int) (fd int, err error)
|
||||
//sys Create(path string, mode int, perm uint32) (fd int, err error)
|
||||
//sys Remove(path string) (err error)
|
||||
//sys Pread(fd int, p []byte, offset int64) (n int, err error)
|
||||
//sys Pwrite(fd int, p []byte, offset int64) (n int, err error)
|
||||
//sys Close(fd int) (err error)
|
||||
//sys Chdir(path string) (err error)
|
||||
//sys Bind(name string, old string, flag int) (err error)
|
||||
//sys Mount(fd int, afd int, old string, flag int, aname string) (err error)
|
||||
//sys Stat(path string, edir []byte) (n int, err error)
|
||||
//sys Fstat(fd int, edir []byte) (n int, err error)
|
||||
//sys Wstat(path string, edir []byte) (err error)
|
||||
//sys Fwstat(fd int, edir []byte) (err error)
|
||||
30
plan9/syscall_test.go
Normal file
30
plan9/syscall_test.go
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
package syscall_test
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testSetGetenv(t *testing.T, key, value string) {
|
||||
err := syscall.Setenv(key, value)
|
||||
if err != nil {
|
||||
t.Fatalf("Setenv failed to set %q: %v", value, err)
|
||||
}
|
||||
newvalue, found := syscall.Getenv(key)
|
||||
if !found {
|
||||
t.Fatalf("Getenv failed to find %v variable (want value %q)", key, value)
|
||||
}
|
||||
if newvalue != value {
|
||||
t.Fatalf("Getenv(%v) = %q; want %q", key, newvalue, value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnv(t *testing.T) {
|
||||
testSetGetenv(t, "TESTENV", "AVALUE")
|
||||
// make sure TESTENV gets set to "", not deleted
|
||||
testSetGetenv(t, "TESTENV", "")
|
||||
}
|
||||
115
plan9/types_plan9.c
Normal file
115
plan9/types_plan9.c
Normal file
@@ -0,0 +1,115 @@
|
||||
// Copyright 2009 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
|
||||
|
||||
/*
|
||||
Input to godefs. See also mkerrors.sh and mkall.sh
|
||||
*/
|
||||
|
||||
typedef unsigned short ushort;
|
||||
typedef unsigned char uchar;
|
||||
typedef unsigned long ulong;
|
||||
typedef unsigned int uint;
|
||||
typedef long long vlong;
|
||||
typedef unsigned long long uvlong;
|
||||
|
||||
typedef int $_C_int;
|
||||
|
||||
enum {
|
||||
OREAD = 0, // open for read
|
||||
OWRITE = 1, // write
|
||||
ORDWR = 2, // read and write
|
||||
OEXEC = 3, // execute, == read but check execute permission
|
||||
OTRUNC = 16, // or'ed in (except for exec), truncate file first
|
||||
OCEXEC = 32, // or'ed in, close on exec
|
||||
ORCLOSE = 64, // or'ed in, remove on close
|
||||
OEXCL = 0x1000, // or'ed in, exclusive use (create only)
|
||||
|
||||
$O_RDONLY = OREAD,
|
||||
$O_WRONLY = OWRITE,
|
||||
$O_RDWR = ORDWR,
|
||||
$O_TRUNC = OTRUNC,
|
||||
$O_CLOEXEC = OCEXEC,
|
||||
$O_EXCL = OEXCL,
|
||||
|
||||
$STATMAX = 65535U,
|
||||
$ERRMAX = 128,
|
||||
|
||||
$MORDER = 0x0003, // mask for bits defining order of mounting
|
||||
$MREPL = 0x0000, // mount replaces object
|
||||
$MBEFORE = 0x0001, // mount goes before others in union directory
|
||||
$MAFTER = 0x0002, // mount goes after others in union directory
|
||||
$MCREATE = 0x0004, // permit creation in mounted directory
|
||||
$MCACHE = 0x0010, // cache some data
|
||||
$MMASK = 0x0017, // all bits on
|
||||
|
||||
$RFNAMEG = (1<<0),
|
||||
$RFENVG = (1<<1),
|
||||
$RFFDG = (1<<2),
|
||||
$RFNOTEG = (1<<3),
|
||||
$RFPROC = (1<<4),
|
||||
$RFMEM = (1<<5),
|
||||
$RFNOWAIT = (1<<6),
|
||||
$RFCNAMEG = (1<<10),
|
||||
$RFCENVG = (1<<11),
|
||||
$RFCFDG = (1<<12),
|
||||
$RFREND = (1<<13),
|
||||
$RFNOMNT = (1<<14),
|
||||
|
||||
// bits in Qid.type
|
||||
$QTDIR = 0x80, // type bit for directories
|
||||
$QTAPPEND = 0x40, // type bit for append only files
|
||||
$QTEXCL = 0x20, // type bit for exclusive use files
|
||||
$QTMOUNT = 0x10, // type bit for mounted channel
|
||||
$QTAUTH = 0x08, // type bit for authentication file
|
||||
$QTTMP = 0x04, // type bit for not-backed-up file
|
||||
$QTFILE = 0x00, // plain file
|
||||
|
||||
|
||||
// bits in Dir.mode
|
||||
$DMDIR = 0x80000000, // mode bit for directories
|
||||
$DMAPPEND = 0x40000000, // mode bit for append only files
|
||||
$DMEXCL = 0x20000000, // mode bit for exclusive use files
|
||||
$DMMOUNT = 0x10000000, // mode bit for mounted channel
|
||||
$DMAUTH = 0x08000000, // mode bit for authentication file
|
||||
$DMTMP = 0x04000000, // mode bit for non-backed-up files
|
||||
$DMREAD = 0x4, // mode bit for read permission
|
||||
$DMWRITE = 0x2, // mode bit for write permission
|
||||
$DMEXEC = 0x1, // mode bit for execute permission
|
||||
|
||||
BIT8SZ = 1,
|
||||
BIT16SZ = 2,
|
||||
BIT32SZ = 4,
|
||||
BIT64SZ = 8,
|
||||
QIDSZ = BIT8SZ+BIT32SZ+BIT64SZ,
|
||||
|
||||
// STATFIXLEN includes leading 16-bit count
|
||||
// The count, however, excludes itself; total size is BIT16SZ+count
|
||||
$STATFIXLEN = BIT16SZ+QIDSZ+5*BIT16SZ+4*BIT32SZ+1*BIT64SZ, // amount of fixed length data in a stat buffer
|
||||
};
|
||||
|
||||
|
||||
struct Prof // Per process profiling
|
||||
{
|
||||
struct Plink *pp; // known to be 0(ptr)
|
||||
struct Plink *next; // known to be 4(ptr)
|
||||
struct Plink *last;
|
||||
struct Plink *first;
|
||||
ulong pid;
|
||||
ulong what;
|
||||
};
|
||||
|
||||
struct Tos {
|
||||
struct Prof prof;
|
||||
uvlong cyclefreq; // cycle clock frequency if there is one, 0 otherwise
|
||||
vlong kcycles; // cycles spent in kernel
|
||||
vlong pcycles; // cycles spent in process (kernel + user)
|
||||
ulong pid; // might as well put the pid here
|
||||
ulong clock;
|
||||
// top of stack is here
|
||||
};
|
||||
|
||||
typedef struct Prof $Prof;
|
||||
typedef struct Tos $Tos;
|
||||
48
plan9/zerrors_plan9_386.go
Normal file
48
plan9/zerrors_plan9_386.go
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright 2011 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.
|
||||
|
||||
package syscall
|
||||
|
||||
// Constants
|
||||
const (
|
||||
// Invented values to support what package os expects.
|
||||
O_CREAT = 0x02000
|
||||
O_APPEND = 0x00400
|
||||
O_NOCTTY = 0x00000
|
||||
O_NONBLOCK = 0x00000
|
||||
O_SYNC = 0x00000
|
||||
O_ASYNC = 0x00000
|
||||
|
||||
S_IFMT = 0x1f000
|
||||
S_IFIFO = 0x1000
|
||||
S_IFCHR = 0x2000
|
||||
S_IFDIR = 0x4000
|
||||
S_IFBLK = 0x6000
|
||||
S_IFREG = 0x8000
|
||||
S_IFLNK = 0xa000
|
||||
S_IFSOCK = 0xc000
|
||||
)
|
||||
|
||||
// Errors
|
||||
var (
|
||||
EINVAL = NewError("bad arg in system call")
|
||||
ENOTDIR = NewError("not a directory")
|
||||
EISDIR = NewError("file is a directory")
|
||||
ENOENT = NewError("file does not exist")
|
||||
EEXIST = NewError("file already exists")
|
||||
EMFILE = NewError("no free file descriptors")
|
||||
EIO = NewError("i/o error")
|
||||
ENAMETOOLONG = NewError("file name too long")
|
||||
EINTR = NewError("interrupted")
|
||||
EPERM = NewError("permission denied")
|
||||
EBUSY = NewError("no free devices")
|
||||
ETIMEDOUT = NewError("connection timed out")
|
||||
EPLAN9 = NewError("not supported by plan 9")
|
||||
|
||||
// The following errors do not correspond to any
|
||||
// Plan 9 system messages. Invented to support
|
||||
// what package os and others expect.
|
||||
EACCES = NewError("access permission denied")
|
||||
EAFNOSUPPORT = NewError("address family not supported by protocol")
|
||||
)
|
||||
48
plan9/zerrors_plan9_amd64.go
Normal file
48
plan9/zerrors_plan9_amd64.go
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright 2011 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.
|
||||
|
||||
package syscall
|
||||
|
||||
// Constants
|
||||
const (
|
||||
// Invented values to support what package os expects.
|
||||
O_CREAT = 0x02000
|
||||
O_APPEND = 0x00400
|
||||
O_NOCTTY = 0x00000
|
||||
O_NONBLOCK = 0x00000
|
||||
O_SYNC = 0x00000
|
||||
O_ASYNC = 0x00000
|
||||
|
||||
S_IFMT = 0x1f000
|
||||
S_IFIFO = 0x1000
|
||||
S_IFCHR = 0x2000
|
||||
S_IFDIR = 0x4000
|
||||
S_IFBLK = 0x6000
|
||||
S_IFREG = 0x8000
|
||||
S_IFLNK = 0xa000
|
||||
S_IFSOCK = 0xc000
|
||||
)
|
||||
|
||||
// Errors
|
||||
var (
|
||||
EINVAL = NewError("bad arg in system call")
|
||||
ENOTDIR = NewError("not a directory")
|
||||
EISDIR = NewError("file is a directory")
|
||||
ENOENT = NewError("file does not exist")
|
||||
EEXIST = NewError("file already exists")
|
||||
EMFILE = NewError("no free file descriptors")
|
||||
EIO = NewError("i/o error")
|
||||
ENAMETOOLONG = NewError("file name too long")
|
||||
EINTR = NewError("interrupted")
|
||||
EPERM = NewError("permission denied")
|
||||
EBUSY = NewError("no free devices")
|
||||
ETIMEDOUT = NewError("connection timed out")
|
||||
EPLAN9 = NewError("not supported by plan 9")
|
||||
|
||||
// The following errors do not correspond to any
|
||||
// Plan 9 system messages. Invented to support
|
||||
// what package os and others expect.
|
||||
EACCES = NewError("access permission denied")
|
||||
EAFNOSUPPORT = NewError("address family not supported by protocol")
|
||||
)
|
||||
282
plan9/zsyscall_plan9_386.go
Normal file
282
plan9/zsyscall_plan9_386.go
Normal file
@@ -0,0 +1,282 @@
|
||||
// mksyscall.pl -l32 -plan9 syscall_plan9.go syscall_plan9_386.go
|
||||
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func fd2path(fd int, buf []byte) (err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(buf) > 0 {
|
||||
_p0 = unsafe.Pointer(&buf[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_FD2PATH, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
|
||||
if int(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func pipe(p *[2]_C_int) (err error) {
|
||||
r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
|
||||
if int(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func await(s []byte) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(s) > 0 {
|
||||
_p0 = unsafe.Pointer(&s[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_AWAIT, uintptr(_p0), uintptr(len(s)), 0)
|
||||
n = int(r0)
|
||||
if int(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Dup(oldfd int, newfd int) (fd int, err error) {
|
||||
r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0)
|
||||
fd = int(r0)
|
||||
if int(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Open(path string, mode int) (fd int, err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
|
||||
fd = int(r0)
|
||||
if int(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Create(path string, mode int, perm uint32) (fd int, err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
|
||||
fd = int(r0)
|
||||
if int(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Remove(path string) (err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(_p0)), 0, 0)
|
||||
if int(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Pread(fd int, p []byte, offset int64) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(p) > 0 {
|
||||
_p0 = unsafe.Pointer(&p[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
|
||||
n = int(r0)
|
||||
if int(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(p) > 0 {
|
||||
_p0 = unsafe.Pointer(&p[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
|
||||
n = int(r0)
|
||||
if int(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Close(fd int) (err error) {
|
||||
r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
|
||||
if int(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Chdir(path string) (err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
|
||||
if int(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Bind(name string, old string, flag int) (err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var _p1 *byte
|
||||
_p1, err = BytePtrFromString(old)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag))
|
||||
if int(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Mount(fd int, afd int, old string, flag int, aname string) (err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(old)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var _p1 *byte
|
||||
_p1, err = BytePtrFromString(aname)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(_p0)), uintptr(flag), uintptr(unsafe.Pointer(_p1)), 0)
|
||||
if int(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Stat(path string, edir []byte) (n int, err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var _p1 unsafe.Pointer
|
||||
if len(edir) > 0 {
|
||||
_p1 = unsafe.Pointer(&edir[0])
|
||||
} else {
|
||||
_p1 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
|
||||
n = int(r0)
|
||||
if int(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Fstat(fd int, edir []byte) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(edir) > 0 {
|
||||
_p0 = unsafe.Pointer(&edir[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
|
||||
n = int(r0)
|
||||
if int(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Wstat(path string, edir []byte) (err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var _p1 unsafe.Pointer
|
||||
if len(edir) > 0 {
|
||||
_p1 = unsafe.Pointer(&edir[0])
|
||||
} else {
|
||||
_p1 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
|
||||
if int(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Fwstat(fd int, edir []byte) (err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(edir) > 0 {
|
||||
_p0 = unsafe.Pointer(&edir[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_FWSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
|
||||
if int(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
282
plan9/zsyscall_plan9_amd64.go
Normal file
282
plan9/zsyscall_plan9_amd64.go
Normal file
@@ -0,0 +1,282 @@
|
||||
// mksyscall.pl -l32 -plan9 syscall_plan9.go syscall_plan9_amd64.go
|
||||
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func fd2path(fd int, buf []byte) (err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(buf) > 0 {
|
||||
_p0 = unsafe.Pointer(&buf[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_FD2PATH, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
|
||||
if int32(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func pipe(p *[2]_C_int) (err error) {
|
||||
r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
|
||||
if int32(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func await(s []byte) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(s) > 0 {
|
||||
_p0 = unsafe.Pointer(&s[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_AWAIT, uintptr(_p0), uintptr(len(s)), 0)
|
||||
n = int(r0)
|
||||
if int32(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Dup(oldfd int, newfd int) (fd int, err error) {
|
||||
r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0)
|
||||
fd = int(r0)
|
||||
if int32(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Open(path string, mode int) (fd int, err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
|
||||
fd = int(r0)
|
||||
if int32(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Create(path string, mode int, perm uint32) (fd int, err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
|
||||
fd = int(r0)
|
||||
if int32(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Remove(path string) (err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(_p0)), 0, 0)
|
||||
if int32(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Pread(fd int, p []byte, offset int64) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(p) > 0 {
|
||||
_p0 = unsafe.Pointer(&p[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
|
||||
n = int(r0)
|
||||
if int32(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(p) > 0 {
|
||||
_p0 = unsafe.Pointer(&p[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
|
||||
n = int(r0)
|
||||
if int32(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Close(fd int) (err error) {
|
||||
r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
|
||||
if int32(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Chdir(path string) (err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
|
||||
if int32(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Bind(name string, old string, flag int) (err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var _p1 *byte
|
||||
_p1, err = BytePtrFromString(old)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag))
|
||||
if int32(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Mount(fd int, afd int, old string, flag int, aname string) (err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(old)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var _p1 *byte
|
||||
_p1, err = BytePtrFromString(aname)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(_p0)), uintptr(flag), uintptr(unsafe.Pointer(_p1)), 0)
|
||||
if int32(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Stat(path string, edir []byte) (n int, err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var _p1 unsafe.Pointer
|
||||
if len(edir) > 0 {
|
||||
_p1 = unsafe.Pointer(&edir[0])
|
||||
} else {
|
||||
_p1 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
|
||||
n = int(r0)
|
||||
if int32(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Fstat(fd int, edir []byte) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(edir) > 0 {
|
||||
_p0 = unsafe.Pointer(&edir[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
|
||||
n = int(r0)
|
||||
if int32(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Wstat(path string, edir []byte) (err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var _p1 unsafe.Pointer
|
||||
if len(edir) > 0 {
|
||||
_p1 = unsafe.Pointer(&edir[0])
|
||||
} else {
|
||||
_p1 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
|
||||
if int32(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Fwstat(fd int, edir []byte) (err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(edir) > 0 {
|
||||
_p0 = unsafe.Pointer(&edir[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_FWSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
|
||||
if int32(r0) == -1 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
49
plan9/zsysnum_plan9_386.go
Normal file
49
plan9/zsysnum_plan9_386.go
Normal file
@@ -0,0 +1,49 @@
|
||||
// mksysnum_plan9.sh /media/sys/src/libc/9syscall/sys.h
|
||||
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
|
||||
|
||||
package syscall
|
||||
|
||||
const (
|
||||
SYS_SYSR1 = 0
|
||||
SYS_BIND = 2
|
||||
SYS_CHDIR = 3
|
||||
SYS_CLOSE = 4
|
||||
SYS_DUP = 5
|
||||
SYS_ALARM = 6
|
||||
SYS_EXEC = 7
|
||||
SYS_EXITS = 8
|
||||
SYS_FAUTH = 10
|
||||
SYS_SEGBRK = 12
|
||||
SYS_OPEN = 14
|
||||
SYS_OSEEK = 16
|
||||
SYS_SLEEP = 17
|
||||
SYS_RFORK = 19
|
||||
SYS_PIPE = 21
|
||||
SYS_CREATE = 22
|
||||
SYS_FD2PATH = 23
|
||||
SYS_BRK_ = 24
|
||||
SYS_REMOVE = 25
|
||||
SYS_NOTIFY = 28
|
||||
SYS_NOTED = 29
|
||||
SYS_SEGATTACH = 30
|
||||
SYS_SEGDETACH = 31
|
||||
SYS_SEGFREE = 32
|
||||
SYS_SEGFLUSH = 33
|
||||
SYS_RENDEZVOUS = 34
|
||||
SYS_UNMOUNT = 35
|
||||
SYS_SEMACQUIRE = 37
|
||||
SYS_SEMRELEASE = 38
|
||||
SYS_SEEK = 39
|
||||
SYS_FVERSION = 40
|
||||
SYS_ERRSTR = 41
|
||||
SYS_STAT = 42
|
||||
SYS_FSTAT = 43
|
||||
SYS_WSTAT = 44
|
||||
SYS_FWSTAT = 45
|
||||
SYS_MOUNT = 46
|
||||
SYS_AWAIT = 47
|
||||
SYS_PREAD = 50
|
||||
SYS_PWRITE = 51
|
||||
SYS_TSEMACQUIRE = 52
|
||||
SYS_NSEC = 53
|
||||
)
|
||||
49
plan9/zsysnum_plan9_amd64.go
Normal file
49
plan9/zsysnum_plan9_amd64.go
Normal file
@@ -0,0 +1,49 @@
|
||||
// mksysnum_plan9.sh /media/sys/src/libc/9syscall/sys.h
|
||||
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
|
||||
|
||||
package syscall
|
||||
|
||||
const (
|
||||
SYS_SYSR1 = 0
|
||||
SYS_BIND = 2
|
||||
SYS_CHDIR = 3
|
||||
SYS_CLOSE = 4
|
||||
SYS_DUP = 5
|
||||
SYS_ALARM = 6
|
||||
SYS_EXEC = 7
|
||||
SYS_EXITS = 8
|
||||
SYS_FAUTH = 10
|
||||
SYS_SEGBRK = 12
|
||||
SYS_OPEN = 14
|
||||
SYS_OSEEK = 16
|
||||
SYS_SLEEP = 17
|
||||
SYS_RFORK = 19
|
||||
SYS_PIPE = 21
|
||||
SYS_CREATE = 22
|
||||
SYS_FD2PATH = 23
|
||||
SYS_BRK_ = 24
|
||||
SYS_REMOVE = 25
|
||||
SYS_NOTIFY = 28
|
||||
SYS_NOTED = 29
|
||||
SYS_SEGATTACH = 30
|
||||
SYS_SEGDETACH = 31
|
||||
SYS_SEGFREE = 32
|
||||
SYS_SEGFLUSH = 33
|
||||
SYS_RENDEZVOUS = 34
|
||||
SYS_UNMOUNT = 35
|
||||
SYS_SEMACQUIRE = 37
|
||||
SYS_SEMRELEASE = 38
|
||||
SYS_SEEK = 39
|
||||
SYS_FVERSION = 40
|
||||
SYS_ERRSTR = 41
|
||||
SYS_STAT = 42
|
||||
SYS_FSTAT = 43
|
||||
SYS_WSTAT = 44
|
||||
SYS_FWSTAT = 45
|
||||
SYS_MOUNT = 46
|
||||
SYS_AWAIT = 47
|
||||
SYS_PREAD = 50
|
||||
SYS_PWRITE = 51
|
||||
SYS_TSEMACQUIRE = 52
|
||||
SYS_NSEC = 53
|
||||
)
|
||||
75
plan9/ztypes_plan9_386.go
Normal file
75
plan9/ztypes_plan9_386.go
Normal file
@@ -0,0 +1,75 @@
|
||||
// godefs -gsyscall -f -m32 types_plan9.c
|
||||
|
||||
// MACHINE GENERATED - DO NOT EDIT.
|
||||
|
||||
package syscall
|
||||
|
||||
// Constants
|
||||
const (
|
||||
O_RDONLY = 0
|
||||
O_WRONLY = 0x1
|
||||
O_RDWR = 0x2
|
||||
O_TRUNC = 0x10
|
||||
O_CLOEXEC = 0x20
|
||||
O_EXCL = 0x1000
|
||||
STATMAX = 0xffff
|
||||
ERRMAX = 0x80
|
||||
MORDER = 0x3
|
||||
MREPL = 0
|
||||
MBEFORE = 0x1
|
||||
MAFTER = 0x2
|
||||
MCREATE = 0x4
|
||||
MCACHE = 0x10
|
||||
MMASK = 0x17
|
||||
RFNAMEG = 0x1
|
||||
RFENVG = 0x2
|
||||
RFFDG = 0x4
|
||||
RFNOTEG = 0x8
|
||||
RFPROC = 0x10
|
||||
RFMEM = 0x20
|
||||
RFNOWAIT = 0x40
|
||||
RFCNAMEG = 0x400
|
||||
RFCENVG = 0x800
|
||||
RFCFDG = 0x1000
|
||||
RFREND = 0x2000
|
||||
RFNOMNT = 0x4000
|
||||
QTDIR = 0x80
|
||||
QTAPPEND = 0x40
|
||||
QTEXCL = 0x20
|
||||
QTMOUNT = 0x10
|
||||
QTAUTH = 0x8
|
||||
QTTMP = 0x4
|
||||
QTFILE = 0
|
||||
DMDIR = 0x80000000
|
||||
DMAPPEND = 0x40000000
|
||||
DMEXCL = 0x20000000
|
||||
DMMOUNT = 0x10000000
|
||||
DMAUTH = 0x8000000
|
||||
DMTMP = 0x4000000
|
||||
DMREAD = 0x4
|
||||
DMWRITE = 0x2
|
||||
DMEXEC = 0x1
|
||||
STATFIXLEN = 0x31
|
||||
)
|
||||
|
||||
// Types
|
||||
|
||||
type _C_int int32
|
||||
|
||||
type Prof struct {
|
||||
Pp *[0]byte /* sPlink */
|
||||
Next *[0]byte /* sPlink */
|
||||
Last *[0]byte /* sPlink */
|
||||
First *[0]byte /* sPlink */
|
||||
Pid uint32
|
||||
What uint32
|
||||
}
|
||||
|
||||
type Tos struct {
|
||||
Prof Prof
|
||||
Cyclefreq uint64
|
||||
Kcycles int64
|
||||
Pcycles int64
|
||||
Pid uint32
|
||||
Clock uint32
|
||||
}
|
||||
75
plan9/ztypes_plan9_amd64.go
Normal file
75
plan9/ztypes_plan9_amd64.go
Normal file
@@ -0,0 +1,75 @@
|
||||
// godefs -gsyscall -f -m32 types_plan9.c
|
||||
|
||||
// MACHINE GENERATED - DO NOT EDIT.
|
||||
|
||||
package syscall
|
||||
|
||||
// Constants
|
||||
const (
|
||||
O_RDONLY = 0
|
||||
O_WRONLY = 0x1
|
||||
O_RDWR = 0x2
|
||||
O_TRUNC = 0x10
|
||||
O_CLOEXEC = 0x20
|
||||
O_EXCL = 0x1000
|
||||
STATMAX = 0xffff
|
||||
ERRMAX = 0x80
|
||||
MORDER = 0x3
|
||||
MREPL = 0
|
||||
MBEFORE = 0x1
|
||||
MAFTER = 0x2
|
||||
MCREATE = 0x4
|
||||
MCACHE = 0x10
|
||||
MMASK = 0x17
|
||||
RFNAMEG = 0x1
|
||||
RFENVG = 0x2
|
||||
RFFDG = 0x4
|
||||
RFNOTEG = 0x8
|
||||
RFPROC = 0x10
|
||||
RFMEM = 0x20
|
||||
RFNOWAIT = 0x40
|
||||
RFCNAMEG = 0x400
|
||||
RFCENVG = 0x800
|
||||
RFCFDG = 0x1000
|
||||
RFREND = 0x2000
|
||||
RFNOMNT = 0x4000
|
||||
QTDIR = 0x80
|
||||
QTAPPEND = 0x40
|
||||
QTEXCL = 0x20
|
||||
QTMOUNT = 0x10
|
||||
QTAUTH = 0x8
|
||||
QTTMP = 0x4
|
||||
QTFILE = 0
|
||||
DMDIR = 0x80000000
|
||||
DMAPPEND = 0x40000000
|
||||
DMEXCL = 0x20000000
|
||||
DMMOUNT = 0x10000000
|
||||
DMAUTH = 0x8000000
|
||||
DMTMP = 0x4000000
|
||||
DMREAD = 0x4
|
||||
DMWRITE = 0x2
|
||||
DMEXEC = 0x1
|
||||
STATFIXLEN = 0x31
|
||||
)
|
||||
|
||||
// Types
|
||||
|
||||
type _C_int int32
|
||||
|
||||
type Prof struct {
|
||||
Pp *[0]byte /* sPlink */
|
||||
Next *[0]byte /* sPlink */
|
||||
Last *[0]byte /* sPlink */
|
||||
First *[0]byte /* sPlink */
|
||||
Pid uint32
|
||||
What uint32
|
||||
}
|
||||
|
||||
type Tos struct {
|
||||
Prof Prof
|
||||
Cyclefreq uint64
|
||||
Kcycles int64
|
||||
Pcycles int64
|
||||
Pid uint32
|
||||
Clock uint32
|
||||
}
|
||||
142
unix/asm_darwin_386.s
Normal file
142
unix/asm_darwin_386.s
Normal file
@@ -0,0 +1,142 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
|
||||
// so that go vet can check that they are correct.
|
||||
|
||||
#include "../../cmd/ld/textflag.h"
|
||||
|
||||
//
|
||||
// System call support for 386, Darwin
|
||||
//
|
||||
|
||||
// func Syscall(trap int32, a1, a2, a3 int32) (r1, r2, err int32);
|
||||
// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
|
||||
// Trap # in AX, args on stack above caller pc.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-28
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $0x80
|
||||
JAE ok
|
||||
MOVL $-1, 20(SP) // r1
|
||||
MOVL $-1, 24(SP) // r2
|
||||
MOVL AX, 28(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok:
|
||||
MOVL AX, 20(SP) // r1
|
||||
MOVL DX, 24(SP) // r2
|
||||
MOVL $0, 28(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $0x80
|
||||
JAE ok6
|
||||
MOVL $-1, 32(SP) // r1
|
||||
MOVL $-1, 36(SP) // r2
|
||||
MOVL AX, 40(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok6:
|
||||
MOVL AX, 32(SP) // r1
|
||||
MOVL DX, 36(SP) // r2
|
||||
MOVL $0, 40(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-52
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $0x80
|
||||
JAE ok9
|
||||
MOVL $-1, 44(SP) // r1
|
||||
MOVL $-1, 48(SP) // r2
|
||||
MOVL AX, 52(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok9:
|
||||
MOVL AX, 44(SP) // r1
|
||||
MOVL DX, 48(SP) // r2
|
||||
MOVL $0, 52(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $0x80
|
||||
JAE ok1
|
||||
MOVL $-1, 20(SP) // r1
|
||||
MOVL $-1, 24(SP) // r2
|
||||
MOVL AX, 28(SP) // errno
|
||||
RET
|
||||
ok1:
|
||||
MOVL AX, 20(SP) // r1
|
||||
MOVL DX, 24(SP) // r2
|
||||
MOVL $0, 28(SP) // errno
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $0x80
|
||||
JAE ok2
|
||||
MOVL $-1, 32(SP) // r1
|
||||
MOVL $-1, 36(SP) // r2
|
||||
MOVL AX, 40(SP) // errno
|
||||
RET
|
||||
ok2:
|
||||
MOVL AX, 32(SP) // r1
|
||||
MOVL DX, 36(SP) // r2
|
||||
MOVL $0, 40(SP) // errno
|
||||
RET
|
||||
106
unix/asm_darwin_amd64.s
Normal file
106
unix/asm_darwin_amd64.s
Normal file
@@ -0,0 +1,106 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
|
||||
// so that go vet can check that they are correct.
|
||||
|
||||
#include "../../cmd/ld/textflag.h"
|
||||
|
||||
//
|
||||
// System call support for AMD64, Darwin
|
||||
//
|
||||
|
||||
// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
|
||||
// func Syscall6(trap int64, a1, a2, a3, a4, a5, a6 int64) (r1, r2, err int64);
|
||||
// Trap # in AX, args in DI SI DX, return in AX DX
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ $0, R10
|
||||
MOVQ $0, R8
|
||||
MOVQ $0, R9
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
ADDQ $0x2000000, AX
|
||||
SYSCALL
|
||||
JCC ok
|
||||
MOVQ $-1, 40(SP) // r1
|
||||
MOVQ $0, 48(SP) // r2
|
||||
MOVQ AX, 56(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok:
|
||||
MOVQ AX, 40(SP) // r1
|
||||
MOVQ DX, 48(SP) // r2
|
||||
MOVQ $0, 56(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ 40(SP), R10
|
||||
MOVQ 48(SP), R8
|
||||
MOVQ 56(SP), R9
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
ADDQ $0x2000000, AX
|
||||
SYSCALL
|
||||
JCC ok6
|
||||
MOVQ $-1, 64(SP) // r1
|
||||
MOVQ $0, 72(SP) // r2
|
||||
MOVQ AX, 80(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok6:
|
||||
MOVQ AX, 64(SP) // r1
|
||||
MOVQ DX, 72(SP) // r2
|
||||
MOVQ $0, 80(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ $0, R10
|
||||
MOVQ $0, R8
|
||||
MOVQ $0, R9
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
ADDQ $0x2000000, AX
|
||||
SYSCALL
|
||||
JCC ok1
|
||||
MOVQ $-1, 40(SP) // r1
|
||||
MOVQ $0, 48(SP) // r2
|
||||
MOVQ AX, 56(SP) // errno
|
||||
RET
|
||||
ok1:
|
||||
MOVQ AX, 40(SP) // r1
|
||||
MOVQ DX, 48(SP) // r2
|
||||
MOVQ $0, 56(SP) // errno
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ 40(SP), R10
|
||||
MOVQ 48(SP), R8
|
||||
MOVQ 56(SP), R9
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
ADDQ $0x2000000, AX
|
||||
SYSCALL
|
||||
JCC ok2
|
||||
MOVQ $-1, 64(SP) // r1
|
||||
MOVQ $0, 72(SP) // r2
|
||||
MOVQ AX, 80(SP) // errno
|
||||
RET
|
||||
ok2:
|
||||
MOVQ AX, 64(SP) // r1
|
||||
MOVQ DX, 72(SP) // r2
|
||||
MOVQ $0, 80(SP) // errno
|
||||
RET
|
||||
139
unix/asm_dragonfly_386.s
Normal file
139
unix/asm_dragonfly_386.s
Normal file
@@ -0,0 +1,139 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
#include "../../cmd/ld/textflag.h"
|
||||
|
||||
//
|
||||
// System call support for 386, FreeBSD
|
||||
//
|
||||
|
||||
// func Syscall(trap int32, a1, a2, a3 int32) (r1, r2, err int32);
|
||||
// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
|
||||
// Trap # in AX, args on stack above caller pc.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-32
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $0x80
|
||||
JAE ok
|
||||
MOVL $-1, 20(SP) // r1
|
||||
MOVL $-1, 24(SP) // r2
|
||||
MOVL AX, 28(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok:
|
||||
MOVL AX, 20(SP) // r1
|
||||
MOVL DX, 24(SP) // r2
|
||||
MOVL $0, 28(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-44
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $0x80
|
||||
JAE ok6
|
||||
MOVL $-1, 32(SP) // r1
|
||||
MOVL $-1, 36(SP) // r2
|
||||
MOVL AX, 40(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok6:
|
||||
MOVL AX, 32(SP) // r1
|
||||
MOVL DX, 36(SP) // r2
|
||||
MOVL $0, 40(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-56
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $0x80
|
||||
JAE ok9
|
||||
MOVL $-1, 44(SP) // r1
|
||||
MOVL $-1, 48(SP) // r2
|
||||
MOVL AX, 52(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok9:
|
||||
MOVL AX, 44(SP) // r1
|
||||
MOVL DX, 48(SP) // r2
|
||||
MOVL $0, 52(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-32
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $0x80
|
||||
JAE ok1
|
||||
MOVL $-1, 20(SP) // r1
|
||||
MOVL $-1, 24(SP) // r2
|
||||
MOVL AX, 28(SP) // errno
|
||||
RET
|
||||
ok1:
|
||||
MOVL AX, 20(SP) // r1
|
||||
MOVL DX, 24(SP) // r2
|
||||
MOVL $0, 28(SP) // errno
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-44
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $0x80
|
||||
JAE ok2
|
||||
MOVL $-1, 32(SP) // r1
|
||||
MOVL $-1, 36(SP) // r2
|
||||
MOVL AX, 40(SP) // errno
|
||||
RET
|
||||
ok2:
|
||||
MOVL AX, 32(SP) // r1
|
||||
MOVL DX, 36(SP) // r2
|
||||
MOVL $0, 40(SP) // errno
|
||||
RET
|
||||
133
unix/asm_dragonfly_amd64.s
Normal file
133
unix/asm_dragonfly_amd64.s
Normal file
@@ -0,0 +1,133 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
#include "../../cmd/ld/textflag.h"
|
||||
|
||||
//
|
||||
// System call support for AMD64, DragonFly
|
||||
//
|
||||
|
||||
// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
|
||||
// func Syscall6(trap int64, a1, a2, a3, a4, a5, a6 int64) (r1, r2, err int64);
|
||||
// func Syscall9(trap int64, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int64)
|
||||
// Trap # in AX, args in DI SI DX, return in AX DX
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-64
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ $0, R10
|
||||
MOVQ $0, R8
|
||||
MOVQ $0, R9
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
SYSCALL
|
||||
JCC ok
|
||||
MOVQ $-1, 40(SP) // r1
|
||||
MOVQ $0, 48(SP) // r2
|
||||
MOVQ AX, 56(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok:
|
||||
MOVQ AX, 40(SP) // r1
|
||||
MOVQ DX, 48(SP) // r2
|
||||
MOVQ $0, 56(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-88
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ 40(SP), R10
|
||||
MOVQ 48(SP), R8
|
||||
MOVQ 56(SP), R9
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
SYSCALL
|
||||
JCC ok6
|
||||
MOVQ $-1, 64(SP) // r1
|
||||
MOVQ $0, 72(SP) // r2
|
||||
MOVQ AX, 80(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok6:
|
||||
MOVQ AX, 64(SP) // r1
|
||||
MOVQ DX, 72(SP) // r2
|
||||
MOVQ $0, 80(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-112
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVQ 8(SP), AX
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ 40(SP), R10
|
||||
MOVQ 48(SP), R8
|
||||
MOVQ 56(SP), R9
|
||||
|
||||
// shift around the last three arguments so they're at the
|
||||
// top of the stack when the syscall is called.
|
||||
MOVQ 64(SP), R11 // arg 7
|
||||
MOVQ R11, 8(SP)
|
||||
MOVQ 72(SP), R11 // arg 8
|
||||
MOVQ R11, 16(SP)
|
||||
MOVQ 80(SP), R11 // arg 9
|
||||
MOVQ R11, 24(SP)
|
||||
|
||||
SYSCALL
|
||||
JCC ok9
|
||||
MOVQ $-1, 88(SP) // r1
|
||||
MOVQ $0, 96(SP) // r2
|
||||
MOVQ AX, 104(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok9:
|
||||
MOVQ AX, 88(SP) // r1
|
||||
MOVQ DX, 96(SP) // r2
|
||||
MOVQ $0, 104(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-64
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ $0, R10
|
||||
MOVQ $0, R8
|
||||
MOVQ $0, R9
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
SYSCALL
|
||||
JCC ok1
|
||||
MOVQ $-1, 40(SP) // r1
|
||||
MOVQ $0, 48(SP) // r2
|
||||
MOVQ AX, 56(SP) // errno
|
||||
RET
|
||||
ok1:
|
||||
MOVQ AX, 40(SP) // r1
|
||||
MOVQ DX, 48(SP) // r2
|
||||
MOVQ $0, 56(SP) // errno
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-88
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ 40(SP), R10
|
||||
MOVQ 48(SP), R8
|
||||
MOVQ 56(SP), R9
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
SYSCALL
|
||||
JCC ok2
|
||||
MOVQ $-1, 64(SP) // r1
|
||||
MOVQ $0, 72(SP) // r2
|
||||
MOVQ AX, 80(SP) // errno
|
||||
RET
|
||||
ok2:
|
||||
MOVQ AX, 64(SP) // r1
|
||||
MOVQ DX, 72(SP) // r2
|
||||
MOVQ $0, 80(SP) // errno
|
||||
RET
|
||||
142
unix/asm_freebsd_386.s
Normal file
142
unix/asm_freebsd_386.s
Normal file
@@ -0,0 +1,142 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
|
||||
// so that go vet can check that they are correct.
|
||||
|
||||
#include "../../cmd/ld/textflag.h"
|
||||
|
||||
//
|
||||
// System call support for 386, FreeBSD
|
||||
//
|
||||
|
||||
// func Syscall(trap int32, a1, a2, a3 int32) (r1, r2, err int32);
|
||||
// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
|
||||
// Trap # in AX, args on stack above caller pc.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-28
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $0x80
|
||||
JAE ok
|
||||
MOVL $-1, 20(SP) // r1
|
||||
MOVL $-1, 24(SP) // r2
|
||||
MOVL AX, 28(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok:
|
||||
MOVL AX, 20(SP) // r1
|
||||
MOVL DX, 24(SP) // r2
|
||||
MOVL $0, 28(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $0x80
|
||||
JAE ok6
|
||||
MOVL $-1, 32(SP) // r1
|
||||
MOVL $-1, 36(SP) // r2
|
||||
MOVL AX, 40(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok6:
|
||||
MOVL AX, 32(SP) // r1
|
||||
MOVL DX, 36(SP) // r2
|
||||
MOVL $0, 40(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-52
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $0x80
|
||||
JAE ok9
|
||||
MOVL $-1, 44(SP) // r1
|
||||
MOVL $-1, 48(SP) // r2
|
||||
MOVL AX, 52(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok9:
|
||||
MOVL AX, 44(SP) // r1
|
||||
MOVL DX, 48(SP) // r2
|
||||
MOVL $0, 52(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $0x80
|
||||
JAE ok1
|
||||
MOVL $-1, 20(SP) // r1
|
||||
MOVL $-1, 24(SP) // r2
|
||||
MOVL AX, 28(SP) // errno
|
||||
RET
|
||||
ok1:
|
||||
MOVL AX, 20(SP) // r1
|
||||
MOVL DX, 24(SP) // r2
|
||||
MOVL $0, 28(SP) // errno
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $0x80
|
||||
JAE ok2
|
||||
MOVL $-1, 32(SP) // r1
|
||||
MOVL $-1, 36(SP) // r2
|
||||
MOVL AX, 40(SP) // errno
|
||||
RET
|
||||
ok2:
|
||||
MOVL AX, 32(SP) // r1
|
||||
MOVL DX, 36(SP) // r2
|
||||
MOVL $0, 40(SP) // errno
|
||||
RET
|
||||
141
unix/asm_freebsd_amd64.s
Normal file
141
unix/asm_freebsd_amd64.s
Normal file
@@ -0,0 +1,141 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
|
||||
// so that go vet can check that they are correct.
|
||||
|
||||
#include "../../cmd/ld/textflag.h"
|
||||
|
||||
//
|
||||
// System call support for AMD64, FreeBSD
|
||||
//
|
||||
|
||||
// The SYSCALL variant for invoking system calls is broken in FreeBSD.
|
||||
// See comment at top of ../runtime/sys_freebsd_amd64.c and
|
||||
// golang.org/issue/6372.
|
||||
#define SYSCALL MOVQ R10, CX; INT $0x80
|
||||
|
||||
// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
|
||||
// func Syscall6(trap int64, a1, a2, a3, a4, a5, a6 int64) (r1, r2, err int64);
|
||||
// func Syscall9(trap int64, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int64)
|
||||
// Trap # in AX, args in DI SI DX, return in AX DX
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ $0, R10
|
||||
MOVQ $0, R8
|
||||
MOVQ $0, R9
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
SYSCALL
|
||||
JCC ok
|
||||
MOVQ $-1, 40(SP) // r1
|
||||
MOVQ $0, 48(SP) // r2
|
||||
MOVQ AX, 56(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok:
|
||||
MOVQ AX, 40(SP) // r1
|
||||
MOVQ DX, 48(SP) // r2
|
||||
MOVQ $0, 56(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ 40(SP), R10
|
||||
MOVQ 48(SP), R8
|
||||
MOVQ 56(SP), R9
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
SYSCALL
|
||||
JCC ok6
|
||||
MOVQ $-1, 64(SP) // r1
|
||||
MOVQ $0, 72(SP) // r2
|
||||
MOVQ AX, 80(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok6:
|
||||
MOVQ AX, 64(SP) // r1
|
||||
MOVQ DX, 72(SP) // r2
|
||||
MOVQ $0, 80(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-104
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVQ 8(SP), AX
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ 40(SP), R10
|
||||
MOVQ 48(SP), R8
|
||||
MOVQ 56(SP), R9
|
||||
|
||||
// shift around the last three arguments so they're at the
|
||||
// top of the stack when the syscall is called.
|
||||
MOVQ 64(SP), R11 // arg 7
|
||||
MOVQ R11, 8(SP)
|
||||
MOVQ 72(SP), R11 // arg 8
|
||||
MOVQ R11, 16(SP)
|
||||
MOVQ 80(SP), R11 // arg 9
|
||||
MOVQ R11, 24(SP)
|
||||
|
||||
SYSCALL
|
||||
JCC ok9
|
||||
MOVQ $-1, 88(SP) // r1
|
||||
MOVQ $0, 96(SP) // r2
|
||||
MOVQ AX, 104(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok9:
|
||||
MOVQ AX, 88(SP) // r1
|
||||
MOVQ DX, 96(SP) // r2
|
||||
MOVQ $0, 104(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ $0, R10
|
||||
MOVQ $0, R8
|
||||
MOVQ $0, R9
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
SYSCALL
|
||||
JCC ok1
|
||||
MOVQ $-1, 40(SP) // r1
|
||||
MOVQ $0, 48(SP) // r2
|
||||
MOVQ AX, 56(SP) // errno
|
||||
RET
|
||||
ok1:
|
||||
MOVQ AX, 40(SP) // r1
|
||||
MOVQ DX, 48(SP) // r2
|
||||
MOVQ $0, 56(SP) // errno
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ 40(SP), R10
|
||||
MOVQ 48(SP), R8
|
||||
MOVQ 56(SP), R9
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
SYSCALL
|
||||
JCC ok2
|
||||
MOVQ $-1, 64(SP) // r1
|
||||
MOVQ $0, 72(SP) // r2
|
||||
MOVQ AX, 80(SP) // errno
|
||||
RET
|
||||
ok2:
|
||||
MOVQ AX, 64(SP) // r1
|
||||
MOVQ DX, 72(SP) // r2
|
||||
MOVQ $0, 80(SP) // errno
|
||||
RET
|
||||
129
unix/asm_freebsd_arm.s
Normal file
129
unix/asm_freebsd_arm.s
Normal file
@@ -0,0 +1,129 @@
|
||||
// Copyright 2012 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.
|
||||
|
||||
#include "../../cmd/ld/textflag.h"
|
||||
|
||||
//
|
||||
// System call support for ARM, FreeBSD
|
||||
//
|
||||
|
||||
// func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, errno uintptr);
|
||||
// func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, errno uintptr);
|
||||
// func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, errno uintptr)
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-28
|
||||
BL runtime·entersyscall(SB)
|
||||
MOVW 0(FP), R7 // syscall number
|
||||
MOVW 4(FP), R0 // a1
|
||||
MOVW 8(FP), R1 // a2
|
||||
MOVW 12(FP), R2 // a3
|
||||
SWI $0 // syscall
|
||||
MOVW $0, R2
|
||||
BCS error
|
||||
MOVW R0, 16(FP) // r1
|
||||
MOVW R1, 20(FP) // r2
|
||||
MOVW R2, 24(FP) // errno
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
error:
|
||||
MOVW $-1, R3
|
||||
MOVW R3, 16(FP) // r1
|
||||
MOVW R2, 20(FP) // r2
|
||||
MOVW R0, 24(FP) // errno
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
||||
BL runtime·entersyscall(SB)
|
||||
MOVW 0(FP), R7 // syscall number
|
||||
MOVW 4(FP), R0 // a1
|
||||
MOVW 8(FP), R1 // a2
|
||||
MOVW 12(FP), R2 // a3
|
||||
MOVW 16(FP), R3 // a4
|
||||
MOVW R13, R4
|
||||
MOVW $20(FP), R13 // a5 to a6 are passed on stack
|
||||
SWI $0 // syscall
|
||||
MOVW R4, R13
|
||||
MOVW $0, R2
|
||||
BCS error6
|
||||
MOVW R0, 28(FP) // r1
|
||||
MOVW R1, 32(FP) // r2
|
||||
MOVW R2, 36(FP) // errno
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
error6:
|
||||
MOVW $-1, R3
|
||||
MOVW R3, 28(FP) // r1
|
||||
MOVW R2, 32(FP) // r2
|
||||
MOVW R0, 36(FP) // errno
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-52
|
||||
BL runtime·entersyscall(SB)
|
||||
MOVW 0(FP), R7 // syscall number
|
||||
MOVW 4(FP), R0 // a1
|
||||
MOVW 8(FP), R1 // a2
|
||||
MOVW 12(FP), R2 // a3
|
||||
MOVW 16(FP), R3 // a4
|
||||
MOVW R13, R4
|
||||
MOVW $20(FP), R13 // a5 to a9 are passed on stack
|
||||
SWI $0 // syscall
|
||||
MOVW R4, R13
|
||||
MOVW $0, R2
|
||||
BCS error9
|
||||
MOVW R0, 40(FP) // r1
|
||||
MOVW R1, 44(FP) // r2
|
||||
MOVW R2, 48(FP) // errno
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
error9:
|
||||
MOVW $-1, R3
|
||||
MOVW R3, 40(FP) // r1
|
||||
MOVW R2, 44(FP) // r2
|
||||
MOVW R0, 48(FP) // errno
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
||||
MOVW 0(FP), R7 // syscall number
|
||||
MOVW 4(FP), R0 // a1
|
||||
MOVW 8(FP), R1 // a2
|
||||
MOVW 12(FP), R2 // a3
|
||||
SWI $0 // syscall
|
||||
MOVW $0, R2
|
||||
BCS errorr
|
||||
MOVW R0, 16(FP) // r1
|
||||
MOVW R1, 20(FP) // r2
|
||||
MOVW R2, 24(FP) // errno
|
||||
RET
|
||||
errorr:
|
||||
MOVW $-1, R3
|
||||
MOVW R3, 16(FP) // r1
|
||||
MOVW R2, 20(FP) // r2
|
||||
MOVW R0, 24(FP) // errno
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
||||
MOVW 0(FP), R7 // syscall number
|
||||
MOVW 4(FP), R0 // a1
|
||||
MOVW 8(FP), R1 // a2
|
||||
MOVW 12(FP), R2 // a3
|
||||
MOVW 16(FP), R3 // a4
|
||||
MOVW R13, R4
|
||||
MOVW $20(FP), R13 // a5 to a6 are passed on stack
|
||||
SWI $0 // syscall
|
||||
MOVW R4, R13
|
||||
MOVW $0, R2
|
||||
BCS errorr6
|
||||
MOVW R0, 28(FP) // r1
|
||||
MOVW R1, 32(FP) // r2
|
||||
MOVW R2, 36(FP) // errno
|
||||
RET
|
||||
errorr6:
|
||||
MOVW $-1, R3
|
||||
MOVW R3, 28(FP) // r1
|
||||
MOVW R2, 32(FP) // r2
|
||||
MOVW R0, 36(FP) // errno
|
||||
RET
|
||||
186
unix/asm_linux_386.s
Normal file
186
unix/asm_linux_386.s
Normal file
@@ -0,0 +1,186 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
|
||||
// so that go vet can check that they are correct.
|
||||
|
||||
#include "../../cmd/ld/textflag.h"
|
||||
|
||||
//
|
||||
// System calls for 386, Linux
|
||||
//
|
||||
|
||||
// func Syscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr);
|
||||
// Trap # in AX, args in BX CX DX SI DI, return in AX
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-28
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
MOVL 8(SP), BX
|
||||
MOVL 12(SP), CX
|
||||
MOVL 16(SP), DX
|
||||
MOVL $0, SI
|
||||
MOVL $0, DI
|
||||
CALL *runtime·_vdso(SB)
|
||||
CMPL AX, $0xfffff001
|
||||
JLS ok
|
||||
MOVL $-1, 20(SP) // r1
|
||||
MOVL $0, 24(SP) // r2
|
||||
NEGL AX
|
||||
MOVL AX, 28(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok:
|
||||
MOVL AX, 20(SP) // r1
|
||||
MOVL DX, 24(SP) // r2
|
||||
MOVL $0, 28(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
// func Syscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
MOVL 8(SP), BX
|
||||
MOVL 12(SP), CX
|
||||
MOVL 16(SP), DX
|
||||
MOVL 20(SP), SI
|
||||
MOVL 24(SP), DI
|
||||
MOVL 28(SP), BP
|
||||
CALL *runtime·_vdso(SB)
|
||||
CMPL AX, $0xfffff001
|
||||
JLS ok6
|
||||
MOVL $-1, 32(SP) // r1
|
||||
MOVL $0, 36(SP) // r2
|
||||
NEGL AX
|
||||
MOVL AX, 40(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok6:
|
||||
MOVL AX, 32(SP) // r1
|
||||
MOVL DX, 36(SP) // r2
|
||||
MOVL $0, 40(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
// func RawSyscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr);
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
MOVL 8(SP), BX
|
||||
MOVL 12(SP), CX
|
||||
MOVL 16(SP), DX
|
||||
MOVL $0, SI
|
||||
MOVL $0, DI
|
||||
CALL *runtime·_vdso(SB)
|
||||
CMPL AX, $0xfffff001
|
||||
JLS ok1
|
||||
MOVL $-1, 20(SP) // r1
|
||||
MOVL $0, 24(SP) // r2
|
||||
NEGL AX
|
||||
MOVL AX, 28(SP) // errno
|
||||
RET
|
||||
ok1:
|
||||
MOVL AX, 20(SP) // r1
|
||||
MOVL DX, 24(SP) // r2
|
||||
MOVL $0, 28(SP) // errno
|
||||
RET
|
||||
|
||||
// func RawSyscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
MOVL 8(SP), BX
|
||||
MOVL 12(SP), CX
|
||||
MOVL 16(SP), DX
|
||||
MOVL 20(SP), SI
|
||||
MOVL 24(SP), DI
|
||||
MOVL 28(SP), BP
|
||||
CALL *runtime·_vdso(SB)
|
||||
CMPL AX, $0xfffff001
|
||||
JLS ok2
|
||||
MOVL $-1, 32(SP) // r1
|
||||
MOVL $0, 36(SP) // r2
|
||||
NEGL AX
|
||||
MOVL AX, 40(SP) // errno
|
||||
RET
|
||||
ok2:
|
||||
MOVL AX, 32(SP) // r1
|
||||
MOVL DX, 36(SP) // r2
|
||||
MOVL $0, 40(SP) // errno
|
||||
RET
|
||||
|
||||
#define SYS_SOCKETCALL 102 /* from zsysnum_linux_386.go */
|
||||
|
||||
// func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int)
|
||||
// Kernel interface gets call sub-number and pointer to a0.
|
||||
TEXT ·socketcall(SB),NOSPLIT,$0-36
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL $SYS_SOCKETCALL, AX // syscall entry
|
||||
MOVL 4(SP), BX // socket call number
|
||||
LEAL 8(SP), CX // pointer to call arguments
|
||||
MOVL $0, DX
|
||||
MOVL $0, SI
|
||||
MOVL $0, DI
|
||||
CALL *runtime·_vdso(SB)
|
||||
CMPL AX, $0xfffff001
|
||||
JLS oksock
|
||||
MOVL $-1, 32(SP) // n
|
||||
NEGL AX
|
||||
MOVL AX, 36(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
oksock:
|
||||
MOVL AX, 32(SP) // n
|
||||
MOVL $0, 36(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
// func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int)
|
||||
// Kernel interface gets call sub-number and pointer to a0.
|
||||
TEXT ·rawsocketcall(SB),NOSPLIT,$0-36
|
||||
MOVL $SYS_SOCKETCALL, AX // syscall entry
|
||||
MOVL 4(SP), BX // socket call number
|
||||
LEAL 8(SP), CX // pointer to call arguments
|
||||
MOVL $0, DX
|
||||
MOVL $0, SI
|
||||
MOVL $0, DI
|
||||
CALL *runtime·_vdso(SB)
|
||||
CMPL AX, $0xfffff001
|
||||
JLS oksock1
|
||||
MOVL $-1, 32(SP) // n
|
||||
NEGL AX
|
||||
MOVL AX, 36(SP) // errno
|
||||
RET
|
||||
oksock1:
|
||||
MOVL AX, 32(SP) // n
|
||||
MOVL $0, 36(SP) // errno
|
||||
RET
|
||||
|
||||
#define SYS__LLSEEK 140 /* from zsysnum_linux_386.go */
|
||||
// func Seek(fd int, offset int64, whence int) (newoffset int64, errno int)
|
||||
// Implemented in assembly to avoid allocation when
|
||||
// taking the address of the return value newoffset.
|
||||
// Underlying system call is
|
||||
// llseek(int fd, int offhi, int offlo, int64 *result, int whence)
|
||||
TEXT ·seek(SB),NOSPLIT,$0-28
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL $SYS__LLSEEK, AX // syscall entry
|
||||
MOVL 4(SP), BX // fd
|
||||
MOVL 12(SP), CX // offset-high
|
||||
MOVL 8(SP), DX // offset-low
|
||||
LEAL 20(SP), SI // result pointer
|
||||
MOVL 16(SP), DI // whence
|
||||
CALL *runtime·_vdso(SB)
|
||||
CMPL AX, $0xfffff001
|
||||
JLS okseek
|
||||
MOVL $-1, 20(SP) // newoffset low
|
||||
MOVL $-1, 24(SP) // newoffset high
|
||||
NEGL AX
|
||||
MOVL AX, 28(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
okseek:
|
||||
// system call filled in newoffset already
|
||||
MOVL $0, 28(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
126
unix/asm_linux_amd64.s
Normal file
126
unix/asm_linux_amd64.s
Normal file
@@ -0,0 +1,126 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
|
||||
// so that go vet can check that they are correct.
|
||||
|
||||
#include "../../cmd/ld/textflag.h"
|
||||
|
||||
//
|
||||
// System calls for AMD64, Linux
|
||||
//
|
||||
|
||||
// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
|
||||
// Trap # in AX, args in DI SI DX R10 R8 R9, return in AX DX
|
||||
// Note that this differs from "standard" ABI convention, which
|
||||
// would pass 4th arg in CX, not R10.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ $0, R10
|
||||
MOVQ $0, R8
|
||||
MOVQ $0, R9
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
SYSCALL
|
||||
CMPQ AX, $0xfffffffffffff001
|
||||
JLS ok
|
||||
MOVQ $-1, 40(SP) // r1
|
||||
MOVQ $0, 48(SP) // r2
|
||||
NEGQ AX
|
||||
MOVQ AX, 56(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok:
|
||||
MOVQ AX, 40(SP) // r1
|
||||
MOVQ DX, 48(SP) // r2
|
||||
MOVQ $0, 56(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ 40(SP), R10
|
||||
MOVQ 48(SP), R8
|
||||
MOVQ 56(SP), R9
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
SYSCALL
|
||||
CMPQ AX, $0xfffffffffffff001
|
||||
JLS ok6
|
||||
MOVQ $-1, 64(SP) // r1
|
||||
MOVQ $0, 72(SP) // r2
|
||||
NEGQ AX
|
||||
MOVQ AX, 80(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok6:
|
||||
MOVQ AX, 64(SP) // r1
|
||||
MOVQ DX, 72(SP) // r2
|
||||
MOVQ $0, 80(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ $0, R10
|
||||
MOVQ $0, R8
|
||||
MOVQ $0, R9
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
SYSCALL
|
||||
CMPQ AX, $0xfffffffffffff001
|
||||
JLS ok1
|
||||
MOVQ $-1, 40(SP) // r1
|
||||
MOVQ $0, 48(SP) // r2
|
||||
NEGQ AX
|
||||
MOVQ AX, 56(SP) // errno
|
||||
RET
|
||||
ok1:
|
||||
MOVQ AX, 40(SP) // r1
|
||||
MOVQ DX, 48(SP) // r2
|
||||
MOVQ $0, 56(SP) // errno
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ 40(SP), R10
|
||||
MOVQ 48(SP), R8
|
||||
MOVQ 56(SP), R9
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
SYSCALL
|
||||
CMPQ AX, $0xfffffffffffff001
|
||||
JLS ok2
|
||||
MOVQ $-1, 64(SP) // r1
|
||||
MOVQ $0, 72(SP) // r2
|
||||
NEGQ AX
|
||||
MOVQ AX, 80(SP) // errno
|
||||
RET
|
||||
ok2:
|
||||
MOVQ AX, 64(SP) // r1
|
||||
MOVQ DX, 72(SP) // r2
|
||||
MOVQ $0, 80(SP) // errno
|
||||
RET
|
||||
|
||||
TEXT ·gettimeofday(SB),NOSPLIT,$0-16
|
||||
MOVQ 8(SP), DI
|
||||
MOVQ $0, SI
|
||||
MOVQ runtime·__vdso_gettimeofday_sym(SB), AX
|
||||
CALL AX
|
||||
|
||||
CMPQ AX, $0xfffffffffffff001
|
||||
JLS ok7
|
||||
NEGQ AX
|
||||
MOVQ AX, 16(SP) // errno
|
||||
RET
|
||||
ok7:
|
||||
MOVQ $0, 16(SP) // errno
|
||||
RET
|
||||
155
unix/asm_linux_arm.s
Normal file
155
unix/asm_linux_arm.s
Normal file
@@ -0,0 +1,155 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
#include "../../cmd/ld/textflag.h"
|
||||
|
||||
//
|
||||
// System calls for arm, Linux
|
||||
//
|
||||
|
||||
// TODO(kaib): handle error returns
|
||||
|
||||
// func Syscall(syscall uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr);
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-28
|
||||
BL runtime·entersyscall(SB)
|
||||
MOVW 4(SP), R7
|
||||
MOVW 8(SP), R0
|
||||
MOVW 12(SP), R1
|
||||
MOVW 16(SP), R2
|
||||
SWI $0
|
||||
MOVW $0xfffff001, R1
|
||||
CMP R1, R0
|
||||
BLS ok
|
||||
MOVW $-1, R1
|
||||
MOVW R1, 20(SP) // r1
|
||||
MOVW $0, R2
|
||||
MOVW R2, 24(SP) // r2
|
||||
RSB $0, R0, R0
|
||||
MOVW R0, 28(SP) // errno
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok:
|
||||
MOVW R0, 20(SP) // r1
|
||||
MOVW $0, R0
|
||||
MOVW R0, 24(SP) // r2
|
||||
MOVW R0, 28(SP) // errno
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
// func Syscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
|
||||
// Actually Syscall5 but the rest of the code expects it to be named Syscall6.
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
||||
BL runtime·entersyscall(SB)
|
||||
MOVW 4(SP), R7 // syscall entry
|
||||
MOVW 8(SP), R0
|
||||
MOVW 12(SP), R1
|
||||
MOVW 16(SP), R2
|
||||
MOVW 20(SP), R3
|
||||
MOVW 24(SP), R4
|
||||
MOVW 28(SP), R5
|
||||
SWI $0
|
||||
MOVW $0xfffff001, R6
|
||||
CMP R6, R0
|
||||
BLS ok6
|
||||
MOVW $-1, R1
|
||||
MOVW R1, 32(SP) // r1
|
||||
MOVW $0, R2
|
||||
MOVW R2, 36(SP) // r2
|
||||
RSB $0, R0, R0
|
||||
MOVW R0, 40(SP) // errno
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok6:
|
||||
MOVW R0, 32(SP) // r1
|
||||
MOVW R1, 36(SP) // r2
|
||||
MOVW $0, R0
|
||||
MOVW R0, 40(SP) // errno
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
// func RawSyscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
|
||||
// Actually RawSyscall5 but the rest of the code expects it to be named RawSyscall6.
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
||||
MOVW 4(SP), R7 // syscall entry
|
||||
MOVW 8(SP), R0
|
||||
MOVW 12(SP), R1
|
||||
MOVW 16(SP), R2
|
||||
MOVW 20(SP), R3
|
||||
MOVW 24(SP), R4
|
||||
MOVW 28(SP), R5
|
||||
SWI $0
|
||||
MOVW $0xfffff001, R6
|
||||
CMP R6, R0
|
||||
BLS ok2
|
||||
MOVW $-1, R1
|
||||
MOVW R1, 32(SP) // r1
|
||||
MOVW $0, R2
|
||||
MOVW R2, 36(SP) // r2
|
||||
RSB $0, R0, R0
|
||||
MOVW R0, 40(SP) // errno
|
||||
RET
|
||||
ok2:
|
||||
MOVW R0, 32(SP) // r1
|
||||
MOVW R1, 36(SP) // r2
|
||||
MOVW $0, R0
|
||||
MOVW R0, 40(SP) // errno
|
||||
RET
|
||||
|
||||
#define SYS__LLSEEK 140 /* from zsysnum_linux_arm.go */
|
||||
// func seek(fd int, offset int64, whence int) (newoffset int64, errno int)
|
||||
// Implemented in assembly to avoid allocation when
|
||||
// taking the address of the return value newoffset.
|
||||
// Underlying system call is
|
||||
// llseek(int fd, int offhi, int offlo, int64 *result, int whence)
|
||||
TEXT ·seek(SB),NOSPLIT,$0-32
|
||||
BL runtime·entersyscall(SB)
|
||||
MOVW $SYS__LLSEEK, R7 // syscall entry
|
||||
MOVW 4(SP), R0 // fd
|
||||
MOVW 12(SP), R1 // offset-high
|
||||
MOVW 8(SP), R2 // offset-low
|
||||
MOVW $20(SP), R3
|
||||
MOVW 16(SP), R4 // whence
|
||||
SWI $0
|
||||
MOVW $0xfffff001, R6
|
||||
CMP R6, R0
|
||||
BLS okseek
|
||||
MOVW $0, R1
|
||||
MOVW R1, 20(SP)
|
||||
MOVW R1, 24(SP)
|
||||
RSB $0, R0, R0
|
||||
MOVW R0, 28(SP) // errno
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
okseek:
|
||||
// system call filled in newoffset already
|
||||
MOVW $0, R0
|
||||
MOVW R0, 28(SP) // errno
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
// func RawSyscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr);
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
||||
MOVW 4(SP), R7 // syscall entry
|
||||
MOVW 8(SP), R0
|
||||
MOVW 12(SP), R1
|
||||
MOVW 16(SP), R2
|
||||
SWI $0
|
||||
MOVW $0xfffff001, R1
|
||||
CMP R1, R0
|
||||
BLS ok1
|
||||
MOVW $-1, R1
|
||||
MOVW R1, 20(SP) // r1
|
||||
MOVW $0, R2
|
||||
MOVW R2, 24(SP) // r2
|
||||
RSB $0, R0, R0
|
||||
MOVW R0, 28(SP) // errno
|
||||
RET
|
||||
ok1:
|
||||
MOVW R0, 20(SP) // r1
|
||||
MOVW $0, R0
|
||||
MOVW R0, 24(SP) // r2
|
||||
MOVW R0, 28(SP) // errno
|
||||
RET
|
||||
|
||||
43
unix/asm_nacl_386.s
Normal file
43
unix/asm_nacl_386.s
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
#include "../../cmd/ld/textflag.h"
|
||||
#include "../runtime/syscall_nacl.h"
|
||||
|
||||
//
|
||||
// System call support for 386, Native Client
|
||||
//
|
||||
|
||||
#define NACL_SYSCALL(code) \
|
||||
MOVL $(0x10000 + ((code)<<5)), AX; CALL AX
|
||||
|
||||
#define NACL_SYSJMP(code) \
|
||||
MOVL $(0x10000 + ((code)<<5)), AX; JMP AX
|
||||
|
||||
TEXT syscall·Syscall(SB),NOSPLIT,$12-28
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL trap+0(FP), AX
|
||||
MOVL a1+4(FP), BX
|
||||
MOVL BX, 0(SP)
|
||||
MOVL a2+8(FP), BX
|
||||
MOVL BX, 4(SP)
|
||||
MOVL a3+12(FP), BX
|
||||
MOVL BX, 8(SP)
|
||||
SHLL $5, AX
|
||||
ADDL $0x10000, AX
|
||||
CALL AX
|
||||
CMPL AX, $0
|
||||
JGE ok
|
||||
MOVL $-1, r1+16(FP)
|
||||
MOVL $-1, r2+20(FP)
|
||||
NEGL AX
|
||||
MOVL AX, err+24(FP)
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok:
|
||||
MOVL AX, r1+16(FP)
|
||||
MOVL DX, r2+20(FP)
|
||||
MOVL $0, err+24(FP)
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
41
unix/asm_nacl_amd64p32.s
Normal file
41
unix/asm_nacl_amd64p32.s
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
#include "../../cmd/ld/textflag.h"
|
||||
#include "../runtime/syscall_nacl.h"
|
||||
|
||||
//
|
||||
// System call support for amd64, Native Client
|
||||
//
|
||||
|
||||
#define NACL_SYSCALL(code) \
|
||||
MOVL $(0x10000 + ((code)<<5)), AX; CALL AX
|
||||
|
||||
#define NACL_SYSJMP(code) \
|
||||
MOVL $(0x10000 + ((code)<<5)), AX; JMP AX
|
||||
|
||||
TEXT syscall·Syscall(SB),NOSPLIT,$0-28
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL trap+0(FP), AX
|
||||
MOVL a1+4(FP), DI
|
||||
MOVL a2+8(FP), SI
|
||||
MOVL a3+12(FP), DX
|
||||
// more args would use CX, R8, R9
|
||||
SHLL $5, AX
|
||||
ADDL $0x10000, AX
|
||||
CALL AX
|
||||
CMPL AX, $0
|
||||
JGE ok
|
||||
MOVL $-1, r1+16(FP)
|
||||
MOVL $-1, r2+20(FP)
|
||||
NEGL AX
|
||||
MOVL AX, err+24(FP)
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok:
|
||||
MOVL AX, r1+16(FP)
|
||||
MOVL DX, r2+20(FP)
|
||||
MOVL $0, err+24(FP)
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
43
unix/asm_nacl_arm.s
Normal file
43
unix/asm_nacl_arm.s
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
#include "../../cmd/ld/textflag.h"
|
||||
#include "../runtime/syscall_nacl.h"
|
||||
|
||||
//
|
||||
// System call support for ARM, Native Client
|
||||
//
|
||||
|
||||
#define NACL_SYSCALL(code) \
|
||||
MOVW $(0x10000 + ((code)<<5)), R8; BL (R8)
|
||||
|
||||
#define NACL_SYSJMP(code) \
|
||||
MOVW $(0x10000 + ((code)<<5)), R8; B (R8)
|
||||
|
||||
TEXT syscall·Syscall(SB),NOSPLIT,$0-28
|
||||
BL runtime·entersyscall(SB)
|
||||
MOVW trap+0(FP), R8
|
||||
MOVW a1+4(FP), R0
|
||||
MOVW a2+8(FP), R1
|
||||
MOVW a3+12(FP), R2
|
||||
// more args would use R3, and then stack.
|
||||
MOVW $0x10000, R7
|
||||
ADD R8<<5, R7
|
||||
BL (R7)
|
||||
CMP $0, R0
|
||||
BGE ok
|
||||
MOVW $-1, R1
|
||||
MOVW R1, r1+16(FP)
|
||||
MOVW R1, r2+20(FP)
|
||||
RSB $0, R0
|
||||
MOVW R0, err+24(FP)
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok:
|
||||
MOVW R0, r1+16(FP)
|
||||
MOVW R1, r2+20(FP)
|
||||
MOVW $0, R2
|
||||
MOVW R2, err+24(FP)
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
142
unix/asm_netbsd_386.s
Normal file
142
unix/asm_netbsd_386.s
Normal file
@@ -0,0 +1,142 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
|
||||
// so that go vet can check that they are correct.
|
||||
|
||||
#include "../../cmd/ld/textflag.h"
|
||||
|
||||
//
|
||||
// System call support for 386, NetBSD
|
||||
//
|
||||
|
||||
// func Syscall(trap int32, a1, a2, a3 int32) (r1, r2, err int32);
|
||||
// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
|
||||
// Trap # in AX, args on stack above caller pc.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-28
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $0x80
|
||||
JAE ok
|
||||
MOVL $-1, 20(SP) // r1
|
||||
MOVL $-1, 24(SP) // r2
|
||||
MOVL AX, 28(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok:
|
||||
MOVL AX, 20(SP) // r1
|
||||
MOVL DX, 24(SP) // r2
|
||||
MOVL $0, 28(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $0x80
|
||||
JAE ok6
|
||||
MOVL $-1, 32(SP) // r1
|
||||
MOVL $-1, 36(SP) // r2
|
||||
MOVL AX, 40(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok6:
|
||||
MOVL AX, 32(SP) // r1
|
||||
MOVL DX, 36(SP) // r2
|
||||
MOVL $0, 40(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-52
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $0x80
|
||||
JAE ok9
|
||||
MOVL $-1, 44(SP) // r1
|
||||
MOVL $-1, 48(SP) // r2
|
||||
MOVL AX, 52(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok9:
|
||||
MOVL AX, 44(SP) // r1
|
||||
MOVL DX, 48(SP) // r2
|
||||
MOVL $0, 52(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $0x80
|
||||
JAE ok1
|
||||
MOVL $-1, 20(SP) // r1
|
||||
MOVL $-1, 24(SP) // r2
|
||||
MOVL AX, 28(SP) // errno
|
||||
RET
|
||||
ok1:
|
||||
MOVL AX, 20(SP) // r1
|
||||
MOVL DX, 24(SP) // r2
|
||||
MOVL $0, 28(SP) // errno
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $0x80
|
||||
JAE ok2
|
||||
MOVL $-1, 32(SP) // r1
|
||||
MOVL $-1, 36(SP) // r2
|
||||
MOVL AX, 40(SP) // errno
|
||||
RET
|
||||
ok2:
|
||||
MOVL AX, 32(SP) // r1
|
||||
MOVL DX, 36(SP) // r2
|
||||
MOVL $0, 40(SP) // errno
|
||||
RET
|
||||
135
unix/asm_netbsd_amd64.s
Normal file
135
unix/asm_netbsd_amd64.s
Normal file
@@ -0,0 +1,135 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
|
||||
// so that go vet can check that they are correct.
|
||||
|
||||
#include "../../cmd/ld/textflag.h"
|
||||
|
||||
//
|
||||
// System call support for AMD64, NetBSD
|
||||
//
|
||||
|
||||
// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
|
||||
// func Syscall6(trap int64, a1, a2, a3, a4, a5, a6 int64) (r1, r2, err int64);
|
||||
// func Syscall9(trap int64, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int64);
|
||||
// Trap # in AX, args in DI SI DX, return in AX DX
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ $0, R10
|
||||
MOVQ $0, R8
|
||||
MOVQ $0, R9
|
||||
SYSCALL
|
||||
JCC ok
|
||||
MOVQ $-1, 40(SP) // r1
|
||||
MOVQ $0, 48(SP) // r2
|
||||
MOVQ AX, 56(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok:
|
||||
MOVQ AX, 40(SP) // r1
|
||||
MOVQ DX, 48(SP) // r2
|
||||
MOVQ $0, 56(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ 40(SP), R10
|
||||
MOVQ 48(SP), R8
|
||||
MOVQ 56(SP), R9
|
||||
SYSCALL
|
||||
JCC ok6
|
||||
MOVQ $-1, 64(SP) // r1
|
||||
MOVQ $0, 72(SP) // r2
|
||||
MOVQ AX, 80(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok6:
|
||||
MOVQ AX, 64(SP) // r1
|
||||
MOVQ DX, 72(SP) // r2
|
||||
MOVQ $0, 80(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-104
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ 40(SP), R10
|
||||
MOVQ 48(SP), R8
|
||||
MOVQ 56(SP), R9
|
||||
MOVQ 64(SP), R11
|
||||
MOVQ 72(SP), R12
|
||||
MOVQ 80(SP), R13
|
||||
SUBQ $32, SP
|
||||
MOVQ R11, 8(SP) // arg 7
|
||||
MOVQ R12, 16(SP) // arg 8
|
||||
MOVQ R13, 24(SP) // arg 9
|
||||
SYSCALL
|
||||
JCC ok9
|
||||
ADDQ $32, SP
|
||||
MOVQ $-1, 88(SP) // r1
|
||||
MOVQ $0, 96(SP) // r2
|
||||
MOVQ AX, 104(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok9:
|
||||
ADDQ $32, SP
|
||||
MOVQ AX, 88(SP) // r1
|
||||
MOVQ DX, 96(SP) // r2
|
||||
MOVQ $0, 104(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ $0, R10
|
||||
MOVQ $0, R8
|
||||
MOVQ $0, R9
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
SYSCALL
|
||||
JCC ok1
|
||||
MOVQ $-1, 40(SP) // r1
|
||||
MOVQ $0, 48(SP) // r2
|
||||
MOVQ AX, 56(SP) // errno
|
||||
RET
|
||||
ok1:
|
||||
MOVQ AX, 40(SP) // r1
|
||||
MOVQ DX, 48(SP) // r2
|
||||
MOVQ $0, 56(SP) // errno
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ 40(SP), R10
|
||||
MOVQ 48(SP), R8
|
||||
MOVQ 56(SP), R9
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
SYSCALL
|
||||
JCC ok2
|
||||
MOVQ $-1, 64(SP) // r1
|
||||
MOVQ $0, 72(SP) // r2
|
||||
MOVQ AX, 80(SP) // errno
|
||||
RET
|
||||
ok2:
|
||||
MOVQ AX, 64(SP) // r1
|
||||
MOVQ DX, 72(SP) // r2
|
||||
MOVQ $0, 80(SP) // errno
|
||||
RET
|
||||
126
unix/asm_netbsd_arm.s
Normal file
126
unix/asm_netbsd_arm.s
Normal file
@@ -0,0 +1,126 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
#include "../../cmd/ld/textflag.h"
|
||||
|
||||
//
|
||||
// System call support for ARM, NetBSD
|
||||
//
|
||||
|
||||
// func Syscall(trap int32, a1, a2, a3 int32) (r1, r2, err int32);
|
||||
// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
|
||||
// func Syscall9(trap int32, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int32)
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-28
|
||||
BL runtime·entersyscall(SB)
|
||||
MOVW 0(FP), R0 // sigcall num
|
||||
MOVW 4(FP), R1 // a1
|
||||
MOVW 8(FP), R2 // a2
|
||||
MOVW 12(FP), R3 // a3
|
||||
SWI $0 // syscall
|
||||
MOVW $0, R2
|
||||
BCS error
|
||||
MOVW R0, 16(FP) // r1
|
||||
MOVW R1, 20(FP) // r2
|
||||
MOVW R2, 24(FP) // err
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
error:
|
||||
MOVW $-1, R3
|
||||
MOVW R3, 16(FP) // r1
|
||||
MOVW R2, 20(FP) // r2
|
||||
MOVW R0, 24(FP) // err
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
||||
BL runtime·entersyscall(SB)
|
||||
MOVW 0(FP), R0 // sigcall num
|
||||
MOVW 4(FP), R1 // a1
|
||||
MOVW 8(FP), R2 // a2
|
||||
MOVW 12(FP), R3 // a3
|
||||
MOVW R13, R4
|
||||
MOVW $16(FP), R13 // a4 to a6 are passed on stack
|
||||
SWI $0 // syscall
|
||||
MOVW R4, R13
|
||||
MOVW $0, R2
|
||||
BCS error6
|
||||
MOVW R0, 28(FP) // r1
|
||||
MOVW R1, 32(FP) // r2
|
||||
MOVW R2, 36(FP) // err
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
error6:
|
||||
MOVW $-1, R3
|
||||
MOVW R3, 28(FP) // r1
|
||||
MOVW R2, 32(FP) // r2
|
||||
MOVW R0, 36(FP) // err
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-52
|
||||
BL runtime·entersyscall(SB)
|
||||
MOVW 0(FP), R0 // sigcall num
|
||||
MOVW 4(FP), R1 // a1
|
||||
MOVW 8(FP), R2 // a2
|
||||
MOVW 12(FP), R3 // a3
|
||||
MOVW R13, R4
|
||||
MOVW $16(FP), R13 // a4 to a9 are passed on stack
|
||||
SWI $0 // syscall
|
||||
MOVW R4, R13
|
||||
MOVW $0, R2
|
||||
BCS error9
|
||||
MOVW R0, 40(FP) // r1
|
||||
MOVW R1, 44(FP) // r2
|
||||
MOVW R2, 48(FP) // err
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
error9:
|
||||
MOVW $-1, R3
|
||||
MOVW R3, 40(FP) // r1
|
||||
MOVW R2, 44(FP) // r2
|
||||
MOVW R0, 48(FP) // err
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
||||
MOVW 0(FP), R0 // sigcall num
|
||||
MOVW 4(FP), R1 // a1
|
||||
MOVW 8(FP), R2 // a2
|
||||
MOVW 12(FP), R3 // a3
|
||||
SWI $0 // syscall
|
||||
MOVW $0, R2
|
||||
BCS errorr
|
||||
MOVW R0, 16(FP) // r1
|
||||
MOVW R1, 20(FP) // r2
|
||||
MOVW R2, 24(FP) // err
|
||||
RET
|
||||
errorr:
|
||||
MOVW $-1, R3
|
||||
MOVW R3, 16(FP) // r1
|
||||
MOVW R2, 20(FP) // r2
|
||||
MOVW R0, 24(FP) // err
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
||||
MOVW 0(FP), R0 // sigcall num
|
||||
MOVW 4(FP), R1 // a1
|
||||
MOVW 8(FP), R2 // a2
|
||||
MOVW 12(FP), R3 // a3
|
||||
MOVW R13, R4
|
||||
MOVW $16(FP), R13 // a4 to a9 are passed on stack
|
||||
SWI $0 // syscall
|
||||
MOVW R4, R13
|
||||
MOVW $0, R2
|
||||
BCS errorr6
|
||||
MOVW R0, 28(FP) // r1
|
||||
MOVW R1, 32(FP) // r2
|
||||
MOVW R2, 36(FP) // err
|
||||
RET
|
||||
errorr6:
|
||||
MOVW $-1, R3
|
||||
MOVW R3, 28(FP) // r1
|
||||
MOVW R2, 32(FP) // r2
|
||||
MOVW R0, 36(FP) // err
|
||||
RET
|
||||
142
unix/asm_openbsd_386.s
Normal file
142
unix/asm_openbsd_386.s
Normal file
@@ -0,0 +1,142 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
|
||||
// so that go vet can check that they are correct.
|
||||
|
||||
#include "../../cmd/ld/textflag.h"
|
||||
|
||||
//
|
||||
// System call support for 386, OpenBSD
|
||||
//
|
||||
|
||||
// func Syscall(trap int32, a1, a2, a3 int32) (r1, r2, err int32);
|
||||
// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
|
||||
// Trap # in AX, args on stack above caller pc.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-28
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $0x80
|
||||
JAE ok
|
||||
MOVL $-1, 20(SP) // r1
|
||||
MOVL $-1, 24(SP) // r2
|
||||
MOVL AX, 28(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok:
|
||||
MOVL AX, 20(SP) // r1
|
||||
MOVL DX, 24(SP) // r2
|
||||
MOVL $0, 28(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $0x80
|
||||
JAE ok6
|
||||
MOVL $-1, 32(SP) // r1
|
||||
MOVL $-1, 36(SP) // r2
|
||||
MOVL AX, 40(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok6:
|
||||
MOVL AX, 32(SP) // r1
|
||||
MOVL DX, 36(SP) // r2
|
||||
MOVL $0, 40(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-52
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $0x80
|
||||
JAE ok9
|
||||
MOVL $-1, 44(SP) // r1
|
||||
MOVL $-1, 48(SP) // r2
|
||||
MOVL AX, 52(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok9:
|
||||
MOVL AX, 44(SP) // r1
|
||||
MOVL DX, 48(SP) // r2
|
||||
MOVL $0, 52(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $0x80
|
||||
JAE ok1
|
||||
MOVL $-1, 20(SP) // r1
|
||||
MOVL $-1, 24(SP) // r2
|
||||
MOVL AX, 28(SP) // errno
|
||||
RET
|
||||
ok1:
|
||||
MOVL AX, 20(SP) // r1
|
||||
MOVL DX, 24(SP) // r2
|
||||
MOVL $0, 28(SP) // errno
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $0x80
|
||||
JAE ok2
|
||||
MOVL $-1, 32(SP) // r1
|
||||
MOVL $-1, 36(SP) // r2
|
||||
MOVL AX, 40(SP) // errno
|
||||
RET
|
||||
ok2:
|
||||
MOVL AX, 32(SP) // r1
|
||||
MOVL DX, 36(SP) // r2
|
||||
MOVL $0, 40(SP) // errno
|
||||
RET
|
||||
135
unix/asm_openbsd_amd64.s
Normal file
135
unix/asm_openbsd_amd64.s
Normal file
@@ -0,0 +1,135 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
|
||||
// so that go vet can check that they are correct.
|
||||
|
||||
#include "../../cmd/ld/textflag.h"
|
||||
|
||||
//
|
||||
// System call support for AMD64, OpenBSD
|
||||
//
|
||||
|
||||
// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
|
||||
// func Syscall6(trap int64, a1, a2, a3, a4, a5, a6 int64) (r1, r2, err int64);
|
||||
// func Syscall9(trap int64, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int64);
|
||||
// Trap # in AX, args in DI SI DX, return in AX DX
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ $0, R10
|
||||
MOVQ $0, R8
|
||||
MOVQ $0, R9
|
||||
SYSCALL
|
||||
JCC ok
|
||||
MOVQ $-1, 40(SP) // r1
|
||||
MOVQ $0, 48(SP) // r2
|
||||
MOVQ AX, 56(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok:
|
||||
MOVQ AX, 40(SP) // r1
|
||||
MOVQ DX, 48(SP) // r2
|
||||
MOVQ $0, 56(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ 40(SP), R10
|
||||
MOVQ 48(SP), R8
|
||||
MOVQ 56(SP), R9
|
||||
SYSCALL
|
||||
JCC ok6
|
||||
MOVQ $-1, 64(SP) // r1
|
||||
MOVQ $0, 72(SP) // r2
|
||||
MOVQ AX, 80(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok6:
|
||||
MOVQ AX, 64(SP) // r1
|
||||
MOVQ DX, 72(SP) // r2
|
||||
MOVQ $0, 80(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-104
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ 40(SP), R10
|
||||
MOVQ 48(SP), R8
|
||||
MOVQ 56(SP), R9
|
||||
MOVQ 64(SP), R11
|
||||
MOVQ 72(SP), R12
|
||||
MOVQ 80(SP), R13
|
||||
SUBQ $32, SP
|
||||
MOVQ R11, 8(SP) // arg 7
|
||||
MOVQ R12, 16(SP) // arg 8
|
||||
MOVQ R13, 24(SP) // arg 9
|
||||
SYSCALL
|
||||
JCC ok9
|
||||
ADDQ $32, SP
|
||||
MOVQ $-1, 88(SP) // r1
|
||||
MOVQ $0, 96(SP) // r2
|
||||
MOVQ AX, 104(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
ok9:
|
||||
ADDQ $32, SP
|
||||
MOVQ AX, 88(SP) // r1
|
||||
MOVQ DX, 96(SP) // r2
|
||||
MOVQ $0, 104(SP) // errno
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ $0, R10
|
||||
MOVQ $0, R8
|
||||
MOVQ $0, R9
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
SYSCALL
|
||||
JCC ok1
|
||||
MOVQ $-1, 40(SP) // r1
|
||||
MOVQ $0, 48(SP) // r2
|
||||
MOVQ AX, 56(SP) // errno
|
||||
RET
|
||||
ok1:
|
||||
MOVQ AX, 40(SP) // r1
|
||||
MOVQ DX, 48(SP) // r2
|
||||
MOVQ $0, 56(SP) // errno
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||
MOVQ 16(SP), DI
|
||||
MOVQ 24(SP), SI
|
||||
MOVQ 32(SP), DX
|
||||
MOVQ 40(SP), R10
|
||||
MOVQ 48(SP), R8
|
||||
MOVQ 56(SP), R9
|
||||
MOVQ 8(SP), AX // syscall entry
|
||||
SYSCALL
|
||||
JCC ok2
|
||||
MOVQ $-1, 64(SP) // r1
|
||||
MOVQ $0, 72(SP) // r2
|
||||
MOVQ AX, 80(SP) // errno
|
||||
RET
|
||||
ok2:
|
||||
MOVQ AX, 64(SP) // r1
|
||||
MOVQ DX, 72(SP) // r2
|
||||
MOVQ $0, 80(SP) // errno
|
||||
RET
|
||||
7
unix/asm_solaris_amd64.s
Normal file
7
unix/asm_solaris_amd64.s
Normal file
@@ -0,0 +1,7 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
//
|
||||
// System calls for amd64, Solaris are implemented in ../runtime/syscall_solaris.goc
|
||||
//
|
||||
169
unix/bpf_bsd.go
Normal file
169
unix/bpf_bsd.go
Normal file
@@ -0,0 +1,169 @@
|
||||
// Copyright 2011 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 darwin dragonfly freebsd netbsd openbsd
|
||||
|
||||
// Berkeley packet filter for BSD variants
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func BpfStmt(code, k int) *BpfInsn {
|
||||
return &BpfInsn{Code: uint16(code), K: uint32(k)}
|
||||
}
|
||||
|
||||
func BpfJump(code, k, jt, jf int) *BpfInsn {
|
||||
return &BpfInsn{Code: uint16(code), Jt: uint8(jt), Jf: uint8(jf), K: uint32(k)}
|
||||
}
|
||||
|
||||
func BpfBuflen(fd int) (int, error) {
|
||||
var l int
|
||||
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGBLEN, uintptr(unsafe.Pointer(&l)))
|
||||
if err != 0 {
|
||||
return 0, Errno(err)
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
func SetBpfBuflen(fd, l int) (int, error) {
|
||||
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSBLEN, uintptr(unsafe.Pointer(&l)))
|
||||
if err != 0 {
|
||||
return 0, Errno(err)
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
func BpfDatalink(fd int) (int, error) {
|
||||
var t int
|
||||
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGDLT, uintptr(unsafe.Pointer(&t)))
|
||||
if err != 0 {
|
||||
return 0, Errno(err)
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func SetBpfDatalink(fd, t int) (int, error) {
|
||||
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSDLT, uintptr(unsafe.Pointer(&t)))
|
||||
if err != 0 {
|
||||
return 0, Errno(err)
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func SetBpfPromisc(fd, m int) error {
|
||||
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCPROMISC, uintptr(unsafe.Pointer(&m)))
|
||||
if err != 0 {
|
||||
return Errno(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func FlushBpf(fd int) error {
|
||||
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCFLUSH, 0)
|
||||
if err != 0 {
|
||||
return Errno(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ivalue struct {
|
||||
name [IFNAMSIZ]byte
|
||||
value int16
|
||||
}
|
||||
|
||||
func BpfInterface(fd int, name string) (string, error) {
|
||||
var iv ivalue
|
||||
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGETIF, uintptr(unsafe.Pointer(&iv)))
|
||||
if err != 0 {
|
||||
return "", Errno(err)
|
||||
}
|
||||
return name, nil
|
||||
}
|
||||
|
||||
func SetBpfInterface(fd int, name string) error {
|
||||
var iv ivalue
|
||||
copy(iv.name[:], []byte(name))
|
||||
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSETIF, uintptr(unsafe.Pointer(&iv)))
|
||||
if err != 0 {
|
||||
return Errno(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func BpfTimeout(fd int) (*Timeval, error) {
|
||||
var tv Timeval
|
||||
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGRTIMEOUT, uintptr(unsafe.Pointer(&tv)))
|
||||
if err != 0 {
|
||||
return nil, Errno(err)
|
||||
}
|
||||
return &tv, nil
|
||||
}
|
||||
|
||||
func SetBpfTimeout(fd int, tv *Timeval) error {
|
||||
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSRTIMEOUT, uintptr(unsafe.Pointer(tv)))
|
||||
if err != 0 {
|
||||
return Errno(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func BpfStats(fd int) (*BpfStat, error) {
|
||||
var s BpfStat
|
||||
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGSTATS, uintptr(unsafe.Pointer(&s)))
|
||||
if err != 0 {
|
||||
return nil, Errno(err)
|
||||
}
|
||||
return &s, nil
|
||||
}
|
||||
|
||||
func SetBpfImmediate(fd, m int) error {
|
||||
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCIMMEDIATE, uintptr(unsafe.Pointer(&m)))
|
||||
if err != 0 {
|
||||
return Errno(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetBpf(fd int, i []BpfInsn) error {
|
||||
var p BpfProgram
|
||||
p.Len = uint32(len(i))
|
||||
p.Insns = (*BpfInsn)(unsafe.Pointer(&i[0]))
|
||||
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSETF, uintptr(unsafe.Pointer(&p)))
|
||||
if err != 0 {
|
||||
return Errno(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func CheckBpfVersion(fd int) error {
|
||||
var v BpfVersion
|
||||
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCVERSION, uintptr(unsafe.Pointer(&v)))
|
||||
if err != 0 {
|
||||
return Errno(err)
|
||||
}
|
||||
if v.Major != BPF_MAJOR_VERSION || v.Minor != BPF_MINOR_VERSION {
|
||||
return EINVAL
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func BpfHeadercmpl(fd int) (int, error) {
|
||||
var f int
|
||||
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGHDRCMPLT, uintptr(unsafe.Pointer(&f)))
|
||||
if err != 0 {
|
||||
return 0, Errno(err)
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func SetBpfHeadercmpl(fd, f int) error {
|
||||
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSHDRCMPLT, uintptr(unsafe.Pointer(&f)))
|
||||
if err != 0 {
|
||||
return Errno(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
113
unix/creds_test.go
Normal file
113
unix/creds_test.go
Normal file
@@ -0,0 +1,113 @@
|
||||
// Copyright 2012 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 linux
|
||||
|
||||
package syscall_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net"
|
||||
"os"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestSCMCredentials tests the sending and receiving of credentials
|
||||
// (PID, UID, GID) in an ancillary message between two UNIX
|
||||
// sockets. The SO_PASSCRED socket option is enabled on the sending
|
||||
// socket for this to work.
|
||||
func TestSCMCredentials(t *testing.T) {
|
||||
fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("Socketpair: %v", err)
|
||||
}
|
||||
defer syscall.Close(fds[0])
|
||||
defer syscall.Close(fds[1])
|
||||
|
||||
err = syscall.SetsockoptInt(fds[0], syscall.SOL_SOCKET, syscall.SO_PASSCRED, 1)
|
||||
if err != nil {
|
||||
t.Fatalf("SetsockoptInt: %v", err)
|
||||
}
|
||||
|
||||
srvFile := os.NewFile(uintptr(fds[0]), "server")
|
||||
defer srvFile.Close()
|
||||
srv, err := net.FileConn(srvFile)
|
||||
if err != nil {
|
||||
t.Errorf("FileConn: %v", err)
|
||||
return
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
cliFile := os.NewFile(uintptr(fds[1]), "client")
|
||||
defer cliFile.Close()
|
||||
cli, err := net.FileConn(cliFile)
|
||||
if err != nil {
|
||||
t.Errorf("FileConn: %v", err)
|
||||
return
|
||||
}
|
||||
defer cli.Close()
|
||||
|
||||
var ucred syscall.Ucred
|
||||
if os.Getuid() != 0 {
|
||||
ucred.Pid = int32(os.Getpid())
|
||||
ucred.Uid = 0
|
||||
ucred.Gid = 0
|
||||
oob := syscall.UnixCredentials(&ucred)
|
||||
_, _, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil)
|
||||
if err.(*net.OpError).Err != syscall.EPERM {
|
||||
t.Fatalf("WriteMsgUnix failed with %v, want EPERM", err)
|
||||
}
|
||||
}
|
||||
|
||||
ucred.Pid = int32(os.Getpid())
|
||||
ucred.Uid = uint32(os.Getuid())
|
||||
ucred.Gid = uint32(os.Getgid())
|
||||
oob := syscall.UnixCredentials(&ucred)
|
||||
|
||||
// this is going to send a dummy byte
|
||||
n, oobn, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("WriteMsgUnix: %v", err)
|
||||
}
|
||||
if n != 0 {
|
||||
t.Fatalf("WriteMsgUnix n = %d, want 0", n)
|
||||
}
|
||||
if oobn != len(oob) {
|
||||
t.Fatalf("WriteMsgUnix oobn = %d, want %d", oobn, len(oob))
|
||||
}
|
||||
|
||||
oob2 := make([]byte, 10*len(oob))
|
||||
n, oobn2, flags, _, err := srv.(*net.UnixConn).ReadMsgUnix(nil, oob2)
|
||||
if err != nil {
|
||||
t.Fatalf("ReadMsgUnix: %v", err)
|
||||
}
|
||||
if flags != 0 {
|
||||
t.Fatalf("ReadMsgUnix flags = 0x%x, want 0", flags)
|
||||
}
|
||||
if n != 1 {
|
||||
t.Fatalf("ReadMsgUnix n = %d, want 1 (dummy byte)", n)
|
||||
}
|
||||
if oobn2 != oobn {
|
||||
// without SO_PASSCRED set on the socket, ReadMsgUnix will
|
||||
// return zero oob bytes
|
||||
t.Fatalf("ReadMsgUnix oobn = %d, want %d", oobn2, oobn)
|
||||
}
|
||||
oob2 = oob2[:oobn2]
|
||||
if !bytes.Equal(oob, oob2) {
|
||||
t.Fatal("ReadMsgUnix oob bytes don't match")
|
||||
}
|
||||
|
||||
scm, err := syscall.ParseSocketControlMessage(oob2)
|
||||
if err != nil {
|
||||
t.Fatalf("ParseSocketControlMessage: %v", err)
|
||||
}
|
||||
newUcred, err := syscall.ParseUnixCredentials(&scm[0])
|
||||
if err != nil {
|
||||
t.Fatalf("ParseUnixCredentials: %v", err)
|
||||
}
|
||||
if *newUcred != ucred {
|
||||
t.Fatalf("ParseUnixCredentials = %+v, want %+v", newUcred, ucred)
|
||||
}
|
||||
}
|
||||
119
unix/env_unix.go
Normal file
119
unix/env_unix.go
Normal file
@@ -0,0 +1,119 @@
|
||||
// Copyright 2010 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 darwin dragonfly freebsd linux nacl netbsd openbsd solaris
|
||||
|
||||
// Unix environment variables.
|
||||
|
||||
package syscall
|
||||
|
||||
import "sync"
|
||||
|
||||
var (
|
||||
// envOnce guards initialization by copyenv, which populates env.
|
||||
envOnce sync.Once
|
||||
|
||||
// envLock guards env and envs.
|
||||
envLock sync.RWMutex
|
||||
|
||||
// env maps from an environment variable to its first occurrence in envs.
|
||||
env map[string]int
|
||||
|
||||
// envs is provided by the runtime. elements are expected to be
|
||||
// of the form "key=value".
|
||||
envs []string
|
||||
)
|
||||
|
||||
// setenv_c is provided by the runtime, but is a no-op if cgo isn't
|
||||
// loaded.
|
||||
func setenv_c(k, v string)
|
||||
|
||||
func copyenv() {
|
||||
env = make(map[string]int)
|
||||
for i, s := range envs {
|
||||
for j := 0; j < len(s); j++ {
|
||||
if s[j] == '=' {
|
||||
key := s[:j]
|
||||
if _, ok := env[key]; !ok {
|
||||
env[key] = i
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Getenv(key string) (value string, found bool) {
|
||||
envOnce.Do(copyenv)
|
||||
if len(key) == 0 {
|
||||
return "", false
|
||||
}
|
||||
|
||||
envLock.RLock()
|
||||
defer envLock.RUnlock()
|
||||
|
||||
i, ok := env[key]
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
s := envs[i]
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] == '=' {
|
||||
return s[i+1:], true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
func Setenv(key, value string) error {
|
||||
envOnce.Do(copyenv)
|
||||
if len(key) == 0 {
|
||||
return EINVAL
|
||||
}
|
||||
for i := 0; i < len(key); i++ {
|
||||
if key[i] == '=' || key[i] == 0 {
|
||||
return EINVAL
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(value); i++ {
|
||||
if value[i] == 0 {
|
||||
return EINVAL
|
||||
}
|
||||
}
|
||||
|
||||
envLock.Lock()
|
||||
defer envLock.Unlock()
|
||||
|
||||
i, ok := env[key]
|
||||
kv := key + "=" + value
|
||||
if ok {
|
||||
envs[i] = kv
|
||||
} else {
|
||||
i = len(envs)
|
||||
envs = append(envs, kv)
|
||||
}
|
||||
env[key] = i
|
||||
setenv_c(key, value)
|
||||
return nil
|
||||
}
|
||||
|
||||
func Clearenv() {
|
||||
envOnce.Do(copyenv) // prevent copyenv in Getenv/Setenv
|
||||
|
||||
envLock.Lock()
|
||||
defer envLock.Unlock()
|
||||
|
||||
env = make(map[string]int)
|
||||
envs = []string{}
|
||||
// TODO(bradfitz): pass through to C
|
||||
}
|
||||
|
||||
func Environ() []string {
|
||||
envOnce.Do(copyenv)
|
||||
envLock.RLock()
|
||||
defer envLock.RUnlock()
|
||||
a := make([]string, len(envs))
|
||||
copy(a, envs)
|
||||
return a
|
||||
}
|
||||
247
unix/exec_bsd.go
Normal file
247
unix/exec_bsd.go
Normal file
@@ -0,0 +1,247 @@
|
||||
// Copyright 2011 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 darwin dragonfly freebsd netbsd openbsd
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type SysProcAttr struct {
|
||||
Chroot string // Chroot.
|
||||
Credential *Credential // Credential.
|
||||
Ptrace bool // Enable tracing.
|
||||
Setsid bool // Create session.
|
||||
Setpgid bool // Set process group ID to new pid (SYSV setpgrp)
|
||||
Setctty bool // Set controlling terminal to fd 0
|
||||
Noctty bool // Detach fd 0 from controlling terminal
|
||||
}
|
||||
|
||||
// Implemented in runtime package.
|
||||
func runtime_BeforeFork()
|
||||
func runtime_AfterFork()
|
||||
|
||||
// Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
|
||||
// If a dup or exec fails, write the errno error to pipe.
|
||||
// (Pipe is close-on-exec so if exec succeeds, it will be closed.)
|
||||
// In the child, this function must not acquire any locks, because
|
||||
// they might have been locked at the time of the fork. This means
|
||||
// no rescheduling, no malloc calls, and no new stack segments.
|
||||
// For the same reason compiler does not race instrument it.
|
||||
// The calls to RawSyscall are okay because they are assembly
|
||||
// functions that do not grow the stack.
|
||||
func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
|
||||
// Declare all variables at top in case any
|
||||
// declarations require heap allocation (e.g., err1).
|
||||
var (
|
||||
r1, r2 uintptr
|
||||
err1 Errno
|
||||
nextfd int
|
||||
i int
|
||||
)
|
||||
|
||||
// guard against side effects of shuffling fds below.
|
||||
// Make sure that nextfd is beyond any currently open files so
|
||||
// that we can't run the risk of overwriting any of them.
|
||||
fd := make([]int, len(attr.Files))
|
||||
nextfd = len(attr.Files)
|
||||
for i, ufd := range attr.Files {
|
||||
if nextfd < int(ufd) {
|
||||
nextfd = int(ufd)
|
||||
}
|
||||
fd[i] = int(ufd)
|
||||
}
|
||||
nextfd++
|
||||
|
||||
darwin := runtime.GOOS == "darwin"
|
||||
|
||||
// About to call fork.
|
||||
// No more allocation or calls of non-assembly functions.
|
||||
runtime_BeforeFork()
|
||||
r1, r2, err1 = RawSyscall(SYS_FORK, 0, 0, 0)
|
||||
if err1 != 0 {
|
||||
runtime_AfterFork()
|
||||
return 0, err1
|
||||
}
|
||||
|
||||
// On Darwin:
|
||||
// r1 = child pid in both parent and child.
|
||||
// r2 = 0 in parent, 1 in child.
|
||||
// Convert to normal Unix r1 = 0 in child.
|
||||
if darwin && r2 == 1 {
|
||||
r1 = 0
|
||||
}
|
||||
|
||||
if r1 != 0 {
|
||||
// parent; return PID
|
||||
runtime_AfterFork()
|
||||
return int(r1), 0
|
||||
}
|
||||
|
||||
// Fork succeeded, now in child.
|
||||
|
||||
// Enable tracing if requested.
|
||||
if sys.Ptrace {
|
||||
_, _, err1 = RawSyscall(SYS_PTRACE, uintptr(PTRACE_TRACEME), 0, 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// Session ID
|
||||
if sys.Setsid {
|
||||
_, _, err1 = RawSyscall(SYS_SETSID, 0, 0, 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// Set process group
|
||||
if sys.Setpgid {
|
||||
_, _, err1 = RawSyscall(SYS_SETPGID, 0, 0, 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// Chroot
|
||||
if chroot != nil {
|
||||
_, _, err1 = RawSyscall(SYS_CHROOT, uintptr(unsafe.Pointer(chroot)), 0, 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// User and groups
|
||||
if cred := sys.Credential; cred != nil {
|
||||
ngroups := uintptr(len(cred.Groups))
|
||||
groups := uintptr(0)
|
||||
if ngroups > 0 {
|
||||
groups = uintptr(unsafe.Pointer(&cred.Groups[0]))
|
||||
}
|
||||
_, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, groups, 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
_, _, err1 = RawSyscall(SYS_SETGID, uintptr(cred.Gid), 0, 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
_, _, err1 = RawSyscall(SYS_SETUID, uintptr(cred.Uid), 0, 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// Chdir
|
||||
if dir != nil {
|
||||
_, _, err1 = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)), 0, 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// Pass 1: look for fd[i] < i and move those up above len(fd)
|
||||
// so that pass 2 won't stomp on an fd it needs later.
|
||||
if pipe < nextfd {
|
||||
_, _, err1 = RawSyscall(SYS_DUP2, uintptr(pipe), uintptr(nextfd), 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
|
||||
pipe = nextfd
|
||||
nextfd++
|
||||
}
|
||||
for i = 0; i < len(fd); i++ {
|
||||
if fd[i] >= 0 && fd[i] < int(i) {
|
||||
_, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(nextfd), 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
|
||||
fd[i] = nextfd
|
||||
nextfd++
|
||||
if nextfd == pipe { // don't stomp on pipe
|
||||
nextfd++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pass 2: dup fd[i] down onto i.
|
||||
for i = 0; i < len(fd); i++ {
|
||||
if fd[i] == -1 {
|
||||
RawSyscall(SYS_CLOSE, uintptr(i), 0, 0)
|
||||
continue
|
||||
}
|
||||
if fd[i] == int(i) {
|
||||
// dup2(i, i) won't clear close-on-exec flag on Linux,
|
||||
// probably not elsewhere either.
|
||||
_, _, err1 = RawSyscall(SYS_FCNTL, uintptr(fd[i]), F_SETFD, 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
continue
|
||||
}
|
||||
// The new fd is created NOT close-on-exec,
|
||||
// which is exactly what we want.
|
||||
_, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(i), 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// By convention, we don't close-on-exec the fds we are
|
||||
// started with, so if len(fd) < 3, close 0, 1, 2 as needed.
|
||||
// Programs that know they inherit fds >= 3 will need
|
||||
// to set them close-on-exec.
|
||||
for i = len(fd); i < 3; i++ {
|
||||
RawSyscall(SYS_CLOSE, uintptr(i), 0, 0)
|
||||
}
|
||||
|
||||
// Detach fd 0 from tty
|
||||
if sys.Noctty {
|
||||
_, _, err1 = RawSyscall(SYS_IOCTL, 0, uintptr(TIOCNOTTY), 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// Make fd 0 the tty
|
||||
if sys.Setctty {
|
||||
_, _, err1 = RawSyscall(SYS_IOCTL, 0, uintptr(TIOCSCTTY), 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// Time to exec.
|
||||
_, _, err1 = RawSyscall(SYS_EXECVE,
|
||||
uintptr(unsafe.Pointer(argv0)),
|
||||
uintptr(unsafe.Pointer(&argv[0])),
|
||||
uintptr(unsafe.Pointer(&envv[0])))
|
||||
|
||||
childerror:
|
||||
// send error code on pipe
|
||||
RawSyscall(SYS_WRITE, uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1))
|
||||
for {
|
||||
RawSyscall(SYS_EXIT, 253, 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
// Try to open a pipe with O_CLOEXEC set on both file descriptors.
|
||||
func forkExecPipe(p []int) error {
|
||||
err := Pipe(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = fcntl(p[0], F_SETFD, FD_CLOEXEC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = fcntl(p[1], F_SETFD, FD_CLOEXEC)
|
||||
return err
|
||||
}
|
||||
262
unix/exec_linux.go
Normal file
262
unix/exec_linux.go
Normal file
@@ -0,0 +1,262 @@
|
||||
// Copyright 2011 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 linux
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type SysProcAttr struct {
|
||||
Chroot string // Chroot.
|
||||
Credential *Credential // Credential.
|
||||
Ptrace bool // Enable tracing.
|
||||
Setsid bool // Create session.
|
||||
Setpgid bool // Set process group ID to new pid (SYSV setpgrp)
|
||||
Setctty bool // Set controlling terminal to fd Ctty (only meaningful if Setsid is set)
|
||||
Noctty bool // Detach fd 0 from controlling terminal
|
||||
Ctty int // Controlling TTY fd (Linux only)
|
||||
Pdeathsig Signal // Signal that the process will get when its parent dies (Linux only)
|
||||
Cloneflags uintptr // Flags for clone calls (Linux only)
|
||||
}
|
||||
|
||||
// Implemented in runtime package.
|
||||
func runtime_BeforeFork()
|
||||
func runtime_AfterFork()
|
||||
|
||||
// Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
|
||||
// If a dup or exec fails, write the errno error to pipe.
|
||||
// (Pipe is close-on-exec so if exec succeeds, it will be closed.)
|
||||
// In the child, this function must not acquire any locks, because
|
||||
// they might have been locked at the time of the fork. This means
|
||||
// no rescheduling, no malloc calls, and no new stack segments.
|
||||
// For the same reason compiler does not race instrument it.
|
||||
// The calls to RawSyscall are okay because they are assembly
|
||||
// functions that do not grow the stack.
|
||||
func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
|
||||
// Declare all variables at top in case any
|
||||
// declarations require heap allocation (e.g., err1).
|
||||
var (
|
||||
r1 uintptr
|
||||
err1 Errno
|
||||
nextfd int
|
||||
i int
|
||||
)
|
||||
|
||||
// Guard against side effects of shuffling fds below.
|
||||
// Make sure that nextfd is beyond any currently open files so
|
||||
// that we can't run the risk of overwriting any of them.
|
||||
fd := make([]int, len(attr.Files))
|
||||
nextfd = len(attr.Files)
|
||||
for i, ufd := range attr.Files {
|
||||
if nextfd < int(ufd) {
|
||||
nextfd = int(ufd)
|
||||
}
|
||||
fd[i] = int(ufd)
|
||||
}
|
||||
nextfd++
|
||||
|
||||
// About to call fork.
|
||||
// No more allocation or calls of non-assembly functions.
|
||||
runtime_BeforeFork()
|
||||
r1, _, err1 = RawSyscall6(SYS_CLONE, uintptr(SIGCHLD)|sys.Cloneflags, 0, 0, 0, 0, 0)
|
||||
if err1 != 0 {
|
||||
runtime_AfterFork()
|
||||
return 0, err1
|
||||
}
|
||||
|
||||
if r1 != 0 {
|
||||
// parent; return PID
|
||||
runtime_AfterFork()
|
||||
return int(r1), 0
|
||||
}
|
||||
|
||||
// Fork succeeded, now in child.
|
||||
|
||||
// Parent death signal
|
||||
if sys.Pdeathsig != 0 {
|
||||
_, _, err1 = RawSyscall6(SYS_PRCTL, PR_SET_PDEATHSIG, uintptr(sys.Pdeathsig), 0, 0, 0, 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
|
||||
// Signal self if parent is already dead. This might cause a
|
||||
// duplicate signal in rare cases, but it won't matter when
|
||||
// using SIGKILL.
|
||||
r1, _, _ = RawSyscall(SYS_GETPPID, 0, 0, 0)
|
||||
if r1 == 1 {
|
||||
pid, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
|
||||
_, _, err1 := RawSyscall(SYS_KILL, pid, uintptr(sys.Pdeathsig), 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enable tracing if requested.
|
||||
if sys.Ptrace {
|
||||
_, _, err1 = RawSyscall(SYS_PTRACE, uintptr(PTRACE_TRACEME), 0, 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// Session ID
|
||||
if sys.Setsid {
|
||||
_, _, err1 = RawSyscall(SYS_SETSID, 0, 0, 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// Set process group
|
||||
if sys.Setpgid {
|
||||
_, _, err1 = RawSyscall(SYS_SETPGID, 0, 0, 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// Chroot
|
||||
if chroot != nil {
|
||||
_, _, err1 = RawSyscall(SYS_CHROOT, uintptr(unsafe.Pointer(chroot)), 0, 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// User and groups
|
||||
if cred := sys.Credential; cred != nil {
|
||||
ngroups := uintptr(len(cred.Groups))
|
||||
var groups unsafe.Pointer
|
||||
if ngroups > 0 {
|
||||
groups = unsafe.Pointer(&cred.Groups[0])
|
||||
}
|
||||
_, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, uintptr(groups), 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
_, _, err1 = RawSyscall(SYS_SETGID, uintptr(cred.Gid), 0, 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
_, _, err1 = RawSyscall(SYS_SETUID, uintptr(cred.Uid), 0, 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// Chdir
|
||||
if dir != nil {
|
||||
_, _, err1 = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)), 0, 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// Pass 1: look for fd[i] < i and move those up above len(fd)
|
||||
// so that pass 2 won't stomp on an fd it needs later.
|
||||
if pipe < nextfd {
|
||||
_, _, err1 = RawSyscall(SYS_DUP2, uintptr(pipe), uintptr(nextfd), 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
|
||||
pipe = nextfd
|
||||
nextfd++
|
||||
}
|
||||
for i = 0; i < len(fd); i++ {
|
||||
if fd[i] >= 0 && fd[i] < int(i) {
|
||||
_, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(nextfd), 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
|
||||
fd[i] = nextfd
|
||||
nextfd++
|
||||
if nextfd == pipe { // don't stomp on pipe
|
||||
nextfd++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pass 2: dup fd[i] down onto i.
|
||||
for i = 0; i < len(fd); i++ {
|
||||
if fd[i] == -1 {
|
||||
RawSyscall(SYS_CLOSE, uintptr(i), 0, 0)
|
||||
continue
|
||||
}
|
||||
if fd[i] == int(i) {
|
||||
// dup2(i, i) won't clear close-on-exec flag on Linux,
|
||||
// probably not elsewhere either.
|
||||
_, _, err1 = RawSyscall(SYS_FCNTL, uintptr(fd[i]), F_SETFD, 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
continue
|
||||
}
|
||||
// The new fd is created NOT close-on-exec,
|
||||
// which is exactly what we want.
|
||||
_, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(i), 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// By convention, we don't close-on-exec the fds we are
|
||||
// started with, so if len(fd) < 3, close 0, 1, 2 as needed.
|
||||
// Programs that know they inherit fds >= 3 will need
|
||||
// to set them close-on-exec.
|
||||
for i = len(fd); i < 3; i++ {
|
||||
RawSyscall(SYS_CLOSE, uintptr(i), 0, 0)
|
||||
}
|
||||
|
||||
// Detach fd 0 from tty
|
||||
if sys.Noctty {
|
||||
_, _, err1 = RawSyscall(SYS_IOCTL, 0, uintptr(TIOCNOTTY), 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// Set the controlling TTY to Ctty
|
||||
if sys.Setctty && sys.Ctty >= 0 {
|
||||
_, _, err1 = RawSyscall(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TIOCSCTTY), 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// Time to exec.
|
||||
_, _, err1 = RawSyscall(SYS_EXECVE,
|
||||
uintptr(unsafe.Pointer(argv0)),
|
||||
uintptr(unsafe.Pointer(&argv[0])),
|
||||
uintptr(unsafe.Pointer(&envv[0])))
|
||||
|
||||
childerror:
|
||||
// send error code on pipe
|
||||
RawSyscall(SYS_WRITE, uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1))
|
||||
for {
|
||||
RawSyscall(SYS_EXIT, 253, 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
// Try to open a pipe with O_CLOEXEC set on both file descriptors.
|
||||
func forkExecPipe(p []int) (err error) {
|
||||
err = Pipe2(p, O_CLOEXEC)
|
||||
// pipe2 was added in 2.6.27 and our minimum requirement is 2.6.23, so it
|
||||
// might not be implemented.
|
||||
if err == ENOSYS {
|
||||
if err = Pipe(p); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err = fcntl(p[0], F_SETFD, FD_CLOEXEC); err != nil {
|
||||
return
|
||||
}
|
||||
_, err = fcntl(p[1], F_SETFD, FD_CLOEXEC)
|
||||
}
|
||||
return
|
||||
}
|
||||
243
unix/exec_solaris.go
Normal file
243
unix/exec_solaris.go
Normal file
@@ -0,0 +1,243 @@
|
||||
// Copyright 2011 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.
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type SysProcAttr struct {
|
||||
Chroot string // Chroot.
|
||||
Credential *Credential // Credential.
|
||||
Setsid bool // Create session.
|
||||
Setpgid bool // Set process group ID to new pid (SYSV setpgrp)
|
||||
Setctty bool // Set controlling terminal to fd 0
|
||||
Noctty bool // Detach fd 0 from controlling terminal
|
||||
}
|
||||
|
||||
// Implemented in runtime package.
|
||||
func runtime_BeforeFork()
|
||||
func runtime_AfterFork()
|
||||
|
||||
func chdir(path uintptr) (err Errno)
|
||||
func chroot1(path uintptr) (err Errno)
|
||||
func close(fd uintptr) (err Errno)
|
||||
func execve(path uintptr, argv uintptr, envp uintptr) (err Errno)
|
||||
func exit(code uintptr)
|
||||
func fcntl1(fd uintptr, cmd uintptr, arg uintptr) (val uintptr, err Errno)
|
||||
func forkx(flags uintptr) (pid uintptr, err Errno)
|
||||
func ioctl(fd uintptr, req uintptr, arg uintptr) (err Errno)
|
||||
func setgid(gid uintptr) (err Errno)
|
||||
func setgroups1(ngid uintptr, gid uintptr) (err Errno)
|
||||
func setsid() (pid uintptr, err Errno)
|
||||
func setuid(uid uintptr) (err Errno)
|
||||
func setpgid(pid uintptr, pgid uintptr) (err Errno)
|
||||
func write1(fd uintptr, buf uintptr, nbyte uintptr) (n uintptr, err Errno)
|
||||
|
||||
// Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
|
||||
// If a dup or exec fails, write the errno error to pipe.
|
||||
// (Pipe is close-on-exec so if exec succeeds, it will be closed.)
|
||||
// In the child, this function must not acquire any locks, because
|
||||
// they might have been locked at the time of the fork. This means
|
||||
// no rescheduling, no malloc calls, and no new stack segments.
|
||||
//
|
||||
// We call hand-crafted syscalls, implemented in
|
||||
// ../runtime/syscall_solaris.goc, rather than generated libc wrappers
|
||||
// because we need to avoid lazy-loading the functions (might malloc,
|
||||
// split the stack, or acquire mutexes). We can't call RawSyscall
|
||||
// because it's not safe even for BSD-subsystem calls.
|
||||
func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
|
||||
// Declare all variables at top in case any
|
||||
// declarations require heap allocation (e.g., err1).
|
||||
var (
|
||||
r1 uintptr
|
||||
err1 Errno
|
||||
nextfd int
|
||||
i int
|
||||
)
|
||||
|
||||
// guard against side effects of shuffling fds below.
|
||||
// Make sure that nextfd is beyond any currently open files so
|
||||
// that we can't run the risk of overwriting any of them.
|
||||
fd := make([]int, len(attr.Files))
|
||||
nextfd = len(attr.Files)
|
||||
for i, ufd := range attr.Files {
|
||||
if nextfd < int(ufd) {
|
||||
nextfd = int(ufd)
|
||||
}
|
||||
fd[i] = int(ufd)
|
||||
}
|
||||
nextfd++
|
||||
|
||||
// About to call fork.
|
||||
// No more allocation or calls of non-assembly functions.
|
||||
runtime_BeforeFork()
|
||||
r1, err1 = forkx(0x1) // FORK_NOSIGCHLD
|
||||
if err1 != 0 {
|
||||
runtime_AfterFork()
|
||||
return 0, err1
|
||||
}
|
||||
|
||||
if r1 != 0 {
|
||||
// parent; return PID
|
||||
runtime_AfterFork()
|
||||
return int(r1), 0
|
||||
}
|
||||
|
||||
// Fork succeeded, now in child.
|
||||
|
||||
// Session ID
|
||||
if sys.Setsid {
|
||||
_, err1 = setsid()
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// Set process group
|
||||
if sys.Setpgid {
|
||||
err1 = setpgid(0, 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// Chroot
|
||||
if chroot != nil {
|
||||
err1 = chroot1(uintptr(unsafe.Pointer(chroot)))
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// User and groups
|
||||
if cred := sys.Credential; cred != nil {
|
||||
ngroups := uintptr(len(cred.Groups))
|
||||
groups := uintptr(0)
|
||||
if ngroups > 0 {
|
||||
groups = uintptr(unsafe.Pointer(&cred.Groups[0]))
|
||||
}
|
||||
err1 = setgroups1(ngroups, groups)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
err1 = setgid(uintptr(cred.Gid))
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
err1 = setuid(uintptr(cred.Uid))
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// Chdir
|
||||
if dir != nil {
|
||||
err1 = chdir(uintptr(unsafe.Pointer(dir)))
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// Pass 1: look for fd[i] < i and move those up above len(fd)
|
||||
// so that pass 2 won't stomp on an fd it needs later.
|
||||
if pipe < nextfd {
|
||||
_, err1 = fcntl1(uintptr(pipe), F_DUP2FD, uintptr(nextfd))
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
fcntl1(uintptr(nextfd), F_SETFD, FD_CLOEXEC)
|
||||
pipe = nextfd
|
||||
nextfd++
|
||||
}
|
||||
for i = 0; i < len(fd); i++ {
|
||||
if fd[i] >= 0 && fd[i] < int(i) {
|
||||
_, err1 = fcntl1(uintptr(fd[i]), F_DUP2FD, uintptr(nextfd))
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
fcntl1(uintptr(nextfd), F_SETFD, FD_CLOEXEC)
|
||||
fd[i] = nextfd
|
||||
nextfd++
|
||||
if nextfd == pipe { // don't stomp on pipe
|
||||
nextfd++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pass 2: dup fd[i] down onto i.
|
||||
for i = 0; i < len(fd); i++ {
|
||||
if fd[i] == -1 {
|
||||
close(uintptr(i))
|
||||
continue
|
||||
}
|
||||
if fd[i] == int(i) {
|
||||
// dup2(i, i) won't clear close-on-exec flag on Linux,
|
||||
// probably not elsewhere either.
|
||||
_, err1 = fcntl1(uintptr(fd[i]), F_SETFD, 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
continue
|
||||
}
|
||||
// The new fd is created NOT close-on-exec,
|
||||
// which is exactly what we want.
|
||||
_, err1 = fcntl1(uintptr(fd[i]), F_DUP2FD, uintptr(i))
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// By convention, we don't close-on-exec the fds we are
|
||||
// started with, so if len(fd) < 3, close 0, 1, 2 as needed.
|
||||
// Programs that know they inherit fds >= 3 will need
|
||||
// to set them close-on-exec.
|
||||
for i = len(fd); i < 3; i++ {
|
||||
close(uintptr(i))
|
||||
}
|
||||
|
||||
// Detach fd 0 from tty
|
||||
if sys.Noctty {
|
||||
err1 = ioctl(0, uintptr(TIOCNOTTY), 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// Make fd 0 the tty
|
||||
if sys.Setctty {
|
||||
err1 = ioctl(0, uintptr(TIOCSCTTY), 0)
|
||||
if err1 != 0 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// Time to exec.
|
||||
err1 = execve(
|
||||
uintptr(unsafe.Pointer(argv0)),
|
||||
uintptr(unsafe.Pointer(&argv[0])),
|
||||
uintptr(unsafe.Pointer(&envv[0])))
|
||||
|
||||
childerror:
|
||||
// send error code on pipe
|
||||
write1(uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1))
|
||||
for {
|
||||
exit(253)
|
||||
}
|
||||
}
|
||||
|
||||
// Try to open a pipe with O_CLOEXEC set on both file descriptors.
|
||||
func forkExecPipe(p []int) error {
|
||||
err := Pipe(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = fcntl(p[0], F_SETFD, FD_CLOEXEC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = fcntl(p[1], F_SETFD, FD_CLOEXEC)
|
||||
return err
|
||||
}
|
||||
261
unix/exec_unix.go
Normal file
261
unix/exec_unix.go
Normal file
@@ -0,0 +1,261 @@
|
||||
// Copyright 2009 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 darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
|
||||
// Fork, exec, wait, etc.
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Lock synchronizing creation of new file descriptors with fork.
|
||||
//
|
||||
// We want the child in a fork/exec sequence to inherit only the
|
||||
// file descriptors we intend. To do that, we mark all file
|
||||
// descriptors close-on-exec and then, in the child, explicitly
|
||||
// unmark the ones we want the exec'ed program to keep.
|
||||
// Unix doesn't make this easy: there is, in general, no way to
|
||||
// allocate a new file descriptor close-on-exec. Instead you
|
||||
// have to allocate the descriptor and then mark it close-on-exec.
|
||||
// If a fork happens between those two events, the child's exec
|
||||
// will inherit an unwanted file descriptor.
|
||||
//
|
||||
// This lock solves that race: the create new fd/mark close-on-exec
|
||||
// operation is done holding ForkLock for reading, and the fork itself
|
||||
// is done holding ForkLock for writing. At least, that's the idea.
|
||||
// There are some complications.
|
||||
//
|
||||
// Some system calls that create new file descriptors can block
|
||||
// for arbitrarily long times: open on a hung NFS server or named
|
||||
// pipe, accept on a socket, and so on. We can't reasonably grab
|
||||
// the lock across those operations.
|
||||
//
|
||||
// It is worse to inherit some file descriptors than others.
|
||||
// If a non-malicious child accidentally inherits an open ordinary file,
|
||||
// that's not a big deal. On the other hand, if a long-lived child
|
||||
// accidentally inherits the write end of a pipe, then the reader
|
||||
// of that pipe will not see EOF until that child exits, potentially
|
||||
// causing the parent program to hang. This is a common problem
|
||||
// in threaded C programs that use popen.
|
||||
//
|
||||
// Luckily, the file descriptors that are most important not to
|
||||
// inherit are not the ones that can take an arbitrarily long time
|
||||
// to create: pipe returns instantly, and the net package uses
|
||||
// non-blocking I/O to accept on a listening socket.
|
||||
// The rules for which file descriptor-creating operations use the
|
||||
// ForkLock are as follows:
|
||||
//
|
||||
// 1) Pipe. Does not block. Use the ForkLock.
|
||||
// 2) Socket. Does not block. Use the ForkLock.
|
||||
// 3) Accept. If using non-blocking mode, use the ForkLock.
|
||||
// Otherwise, live with the race.
|
||||
// 4) Open. Can block. Use O_CLOEXEC if available (Linux).
|
||||
// Otherwise, live with the race.
|
||||
// 5) Dup. Does not block. Use the ForkLock.
|
||||
// On Linux, could use fcntl F_DUPFD_CLOEXEC
|
||||
// instead of the ForkLock, but only for dup(fd, -1).
|
||||
|
||||
var ForkLock sync.RWMutex
|
||||
|
||||
// StringSlicePtr is deprecated. Use SlicePtrFromStrings instead.
|
||||
// If any string contains a NUL byte this function panics instead
|
||||
// of returning an error.
|
||||
func StringSlicePtr(ss []string) []*byte {
|
||||
bb := make([]*byte, len(ss)+1)
|
||||
for i := 0; i < len(ss); i++ {
|
||||
bb[i] = StringBytePtr(ss[i])
|
||||
}
|
||||
bb[len(ss)] = nil
|
||||
return bb
|
||||
}
|
||||
|
||||
// SlicePtrFromStrings converts a slice of strings to a slice of
|
||||
// pointers to NUL-terminated byte slices. If any string contains
|
||||
// a NUL byte, it returns (nil, EINVAL).
|
||||
func SlicePtrFromStrings(ss []string) ([]*byte, error) {
|
||||
var err error
|
||||
bb := make([]*byte, len(ss)+1)
|
||||
for i := 0; i < len(ss); i++ {
|
||||
bb[i], err = BytePtrFromString(ss[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
bb[len(ss)] = nil
|
||||
return bb, nil
|
||||
}
|
||||
|
||||
func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) }
|
||||
|
||||
func SetNonblock(fd int, nonblocking bool) (err error) {
|
||||
flag, err := fcntl(fd, F_GETFL, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if nonblocking {
|
||||
flag |= O_NONBLOCK
|
||||
} else {
|
||||
flag &= ^O_NONBLOCK
|
||||
}
|
||||
_, err = fcntl(fd, F_SETFL, flag)
|
||||
return err
|
||||
}
|
||||
|
||||
// Credential holds user and group identities to be assumed
|
||||
// by a child process started by StartProcess.
|
||||
type Credential struct {
|
||||
Uid uint32 // User ID.
|
||||
Gid uint32 // Group ID.
|
||||
Groups []uint32 // Supplementary group IDs.
|
||||
}
|
||||
|
||||
// ProcAttr holds attributes that will be applied to a new process started
|
||||
// by StartProcess.
|
||||
type ProcAttr struct {
|
||||
Dir string // Current working directory.
|
||||
Env []string // Environment.
|
||||
Files []uintptr // File descriptors.
|
||||
Sys *SysProcAttr
|
||||
}
|
||||
|
||||
var zeroProcAttr ProcAttr
|
||||
var zeroSysProcAttr SysProcAttr
|
||||
|
||||
func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
|
||||
var p [2]int
|
||||
var n int
|
||||
var err1 Errno
|
||||
var wstatus WaitStatus
|
||||
|
||||
if attr == nil {
|
||||
attr = &zeroProcAttr
|
||||
}
|
||||
sys := attr.Sys
|
||||
if sys == nil {
|
||||
sys = &zeroSysProcAttr
|
||||
}
|
||||
|
||||
p[0] = -1
|
||||
p[1] = -1
|
||||
|
||||
// Convert args to C form.
|
||||
argv0p, err := BytePtrFromString(argv0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
argvp, err := SlicePtrFromStrings(argv)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
envvp, err := SlicePtrFromStrings(attr.Env)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if (runtime.GOOS == "freebsd" || runtime.GOOS == "dragonfly") && len(argv[0]) > len(argv0) {
|
||||
argvp[0] = argv0p
|
||||
}
|
||||
|
||||
var chroot *byte
|
||||
if sys.Chroot != "" {
|
||||
chroot, err = BytePtrFromString(sys.Chroot)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
var dir *byte
|
||||
if attr.Dir != "" {
|
||||
dir, err = BytePtrFromString(attr.Dir)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
// Acquire the fork lock so that no other threads
|
||||
// create new fds that are not yet close-on-exec
|
||||
// before we fork.
|
||||
ForkLock.Lock()
|
||||
|
||||
// Allocate child status pipe close on exec.
|
||||
if err = forkExecPipe(p[:]); err != nil {
|
||||
goto error
|
||||
}
|
||||
|
||||
// Kick off child.
|
||||
pid, err1 = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1])
|
||||
if err1 != 0 {
|
||||
err = Errno(err1)
|
||||
goto error
|
||||
}
|
||||
ForkLock.Unlock()
|
||||
|
||||
// Read child error status from pipe.
|
||||
Close(p[1])
|
||||
n, err = readlen(p[0], (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1)))
|
||||
Close(p[0])
|
||||
if err != nil || n != 0 {
|
||||
if n == int(unsafe.Sizeof(err1)) {
|
||||
err = Errno(err1)
|
||||
}
|
||||
if err == nil {
|
||||
err = EPIPE
|
||||
}
|
||||
|
||||
// Child failed; wait for it to exit, to make sure
|
||||
// the zombies don't accumulate.
|
||||
_, err1 := Wait4(pid, &wstatus, 0, nil)
|
||||
for err1 == EINTR {
|
||||
_, err1 = Wait4(pid, &wstatus, 0, nil)
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Read got EOF, so pipe closed on exec, so exec succeeded.
|
||||
return pid, nil
|
||||
|
||||
error:
|
||||
if p[0] >= 0 {
|
||||
Close(p[0])
|
||||
Close(p[1])
|
||||
}
|
||||
ForkLock.Unlock()
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Combination of fork and exec, careful to be thread safe.
|
||||
func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
|
||||
return forkExec(argv0, argv, attr)
|
||||
}
|
||||
|
||||
// StartProcess wraps ForkExec for package os.
|
||||
func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
|
||||
pid, err = forkExec(argv0, argv, attr)
|
||||
return pid, 0, err
|
||||
}
|
||||
|
||||
// Ordinary exec.
|
||||
func Exec(argv0 string, argv []string, envv []string) (err error) {
|
||||
argv0p, err := BytePtrFromString(argv0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
argvp, err := SlicePtrFromStrings(argv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
envvp, err := SlicePtrFromStrings(envv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, _, err1 := RawSyscall(SYS_EXECVE,
|
||||
uintptr(unsafe.Pointer(argv0p)),
|
||||
uintptr(unsafe.Pointer(&argvp[0])),
|
||||
uintptr(unsafe.Pointer(&envvp[0])))
|
||||
return Errno(err1)
|
||||
}
|
||||
326
unix/fd_nacl.go
Normal file
326
unix/fd_nacl.go
Normal file
@@ -0,0 +1,326 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
// File descriptor support for Native Client.
|
||||
// We want to provide access to a broader range of (simulated) files than
|
||||
// Native Client allows, so we maintain our own file descriptor table exposed
|
||||
// to higher-level packages.
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// files is the table indexed by a file descriptor.
|
||||
var files struct {
|
||||
sync.RWMutex
|
||||
tab []*file
|
||||
}
|
||||
|
||||
// A file is an open file, something with a file descriptor.
|
||||
// A particular *file may appear in files multiple times, due to use of Dup or Dup2.
|
||||
type file struct {
|
||||
fdref int // uses in files.tab
|
||||
impl fileImpl // underlying implementation
|
||||
}
|
||||
|
||||
// A fileImpl is the implementation of something that can be a file.
|
||||
type fileImpl interface {
|
||||
// Standard operations.
|
||||
// These can be called concurrently from multiple goroutines.
|
||||
stat(*Stat_t) error
|
||||
read([]byte) (int, error)
|
||||
write([]byte) (int, error)
|
||||
seek(int64, int) (int64, error)
|
||||
pread([]byte, int64) (int, error)
|
||||
pwrite([]byte, int64) (int, error)
|
||||
|
||||
// Close is called when the last reference to a *file is removed
|
||||
// from the file descriptor table. It may be called concurrently
|
||||
// with active operations such as blocked read or write calls.
|
||||
close() error
|
||||
}
|
||||
|
||||
// newFD adds impl to the file descriptor table,
|
||||
// returning the new file descriptor.
|
||||
// Like Unix, it uses the lowest available descriptor.
|
||||
func newFD(impl fileImpl) int {
|
||||
files.Lock()
|
||||
defer files.Unlock()
|
||||
f := &file{impl: impl, fdref: 1}
|
||||
for fd, oldf := range files.tab {
|
||||
if oldf == nil {
|
||||
files.tab[fd] = f
|
||||
return fd
|
||||
}
|
||||
}
|
||||
fd := len(files.tab)
|
||||
files.tab = append(files.tab, f)
|
||||
return fd
|
||||
}
|
||||
|
||||
// Install Native Client stdin, stdout, stderr.
|
||||
func init() {
|
||||
newFD(&naclFile{naclFD: 0})
|
||||
newFD(&naclFile{naclFD: 1})
|
||||
newFD(&naclFile{naclFD: 2})
|
||||
}
|
||||
|
||||
// fdToFile retrieves the *file corresponding to a file descriptor.
|
||||
func fdToFile(fd int) (*file, error) {
|
||||
files.Lock()
|
||||
defer files.Unlock()
|
||||
if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil {
|
||||
return nil, EBADF
|
||||
}
|
||||
return files.tab[fd], nil
|
||||
}
|
||||
|
||||
func Close(fd int) error {
|
||||
files.Lock()
|
||||
if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil {
|
||||
files.Unlock()
|
||||
return EBADF
|
||||
}
|
||||
f := files.tab[fd]
|
||||
files.tab[fd] = nil
|
||||
f.fdref--
|
||||
fdref := f.fdref
|
||||
files.Unlock()
|
||||
if fdref > 0 {
|
||||
return nil
|
||||
}
|
||||
return f.impl.close()
|
||||
}
|
||||
|
||||
func CloseOnExec(fd int) {
|
||||
// nothing to do - no exec
|
||||
}
|
||||
|
||||
func Dup(fd int) (int, error) {
|
||||
files.Lock()
|
||||
defer files.Unlock()
|
||||
if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil {
|
||||
return -1, EBADF
|
||||
}
|
||||
f := files.tab[fd]
|
||||
f.fdref++
|
||||
for newfd, oldf := range files.tab {
|
||||
if oldf == nil {
|
||||
files.tab[newfd] = f
|
||||
return newfd, nil
|
||||
}
|
||||
}
|
||||
newfd := len(files.tab)
|
||||
files.tab = append(files.tab, f)
|
||||
return newfd, nil
|
||||
}
|
||||
|
||||
func Dup2(fd, newfd int) error {
|
||||
files.Lock()
|
||||
defer files.Unlock()
|
||||
if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil || newfd < 0 || newfd >= len(files.tab)+100 {
|
||||
files.Unlock()
|
||||
return EBADF
|
||||
}
|
||||
f := files.tab[fd]
|
||||
f.fdref++
|
||||
for cap(files.tab) <= newfd {
|
||||
files.tab = append(files.tab[:cap(files.tab)], nil)
|
||||
}
|
||||
oldf := files.tab[newfd]
|
||||
var oldfdref int
|
||||
if oldf != nil {
|
||||
oldf.fdref--
|
||||
oldfdref = oldf.fdref
|
||||
}
|
||||
files.tab[newfd] = f
|
||||
files.Unlock()
|
||||
if oldf != nil {
|
||||
if oldfdref == 0 {
|
||||
oldf.impl.close()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Fstat(fd int, st *Stat_t) error {
|
||||
f, err := fdToFile(fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return f.impl.stat(st)
|
||||
}
|
||||
|
||||
func Read(fd int, b []byte) (int, error) {
|
||||
f, err := fdToFile(fd)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return f.impl.read(b)
|
||||
}
|
||||
|
||||
var zerobuf [0]byte
|
||||
|
||||
func Write(fd int, b []byte) (int, error) {
|
||||
if b == nil {
|
||||
// avoid nil in syscalls; nacl doesn't like that.
|
||||
b = zerobuf[:]
|
||||
}
|
||||
f, err := fdToFile(fd)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return f.impl.write(b)
|
||||
}
|
||||
|
||||
func Pread(fd int, b []byte, offset int64) (int, error) {
|
||||
f, err := fdToFile(fd)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return f.impl.pread(b, offset)
|
||||
}
|
||||
|
||||
func Pwrite(fd int, b []byte, offset int64) (int, error) {
|
||||
f, err := fdToFile(fd)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return f.impl.pwrite(b, offset)
|
||||
}
|
||||
|
||||
func Seek(fd int, offset int64, whence int) (int64, error) {
|
||||
f, err := fdToFile(fd)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return f.impl.seek(offset, whence)
|
||||
}
|
||||
|
||||
// defaulFileImpl implements fileImpl.
|
||||
// It can be embedded to complete a partial fileImpl implementation.
|
||||
type defaultFileImpl struct{}
|
||||
|
||||
func (*defaultFileImpl) close() error { return nil }
|
||||
func (*defaultFileImpl) stat(*Stat_t) error { return ENOSYS }
|
||||
func (*defaultFileImpl) read([]byte) (int, error) { return 0, ENOSYS }
|
||||
func (*defaultFileImpl) write([]byte) (int, error) { return 0, ENOSYS }
|
||||
func (*defaultFileImpl) seek(int64, int) (int64, error) { return 0, ENOSYS }
|
||||
func (*defaultFileImpl) pread([]byte, int64) (int, error) { return 0, ENOSYS }
|
||||
func (*defaultFileImpl) pwrite([]byte, int64) (int, error) { return 0, ENOSYS }
|
||||
|
||||
// naclFile is the fileImpl implementation for a Native Client file descriptor.
|
||||
type naclFile struct {
|
||||
defaultFileImpl
|
||||
naclFD int
|
||||
}
|
||||
|
||||
func (f *naclFile) stat(st *Stat_t) error {
|
||||
return naclFstat(f.naclFD, st)
|
||||
}
|
||||
|
||||
func (f *naclFile) read(b []byte) (int, error) {
|
||||
n, err := naclRead(f.naclFD, b)
|
||||
if err != nil {
|
||||
n = 0
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
// implemented in package runtime, to add time header on playground
|
||||
func naclWrite(fd int, b []byte) int
|
||||
|
||||
func (f *naclFile) write(b []byte) (int, error) {
|
||||
n := naclWrite(f.naclFD, b)
|
||||
if n < 0 {
|
||||
return 0, Errno(-n)
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (f *naclFile) seek(off int64, whence int) (int64, error) {
|
||||
old := off
|
||||
err := naclSeek(f.naclFD, &off, whence)
|
||||
if err != nil {
|
||||
return old, err
|
||||
}
|
||||
return off, nil
|
||||
}
|
||||
|
||||
func (f *naclFile) prw(b []byte, offset int64, rw func([]byte) (int, error)) (int, error) {
|
||||
// NaCl has no pread; simulate with seek and hope for no races.
|
||||
old, err := f.seek(0, 1)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if _, err := f.seek(offset, 0); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
n, err := rw(b)
|
||||
f.seek(old, 0)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (f *naclFile) pread(b []byte, offset int64) (int, error) {
|
||||
return f.prw(b, offset, f.read)
|
||||
}
|
||||
|
||||
func (f *naclFile) pwrite(b []byte, offset int64) (int, error) {
|
||||
return f.prw(b, offset, f.write)
|
||||
}
|
||||
|
||||
func (f *naclFile) close() error {
|
||||
err := naclClose(f.naclFD)
|
||||
f.naclFD = -1
|
||||
return err
|
||||
}
|
||||
|
||||
// A pipeFile is an in-memory implementation of a pipe.
|
||||
// The byteq implementation is in net_nacl.go.
|
||||
type pipeFile struct {
|
||||
defaultFileImpl
|
||||
rd *byteq
|
||||
wr *byteq
|
||||
}
|
||||
|
||||
func (f *pipeFile) close() error {
|
||||
if f.rd != nil {
|
||||
f.rd.close()
|
||||
}
|
||||
if f.wr != nil {
|
||||
f.wr.close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *pipeFile) read(b []byte) (int, error) {
|
||||
if f.rd == nil {
|
||||
return 0, EINVAL
|
||||
}
|
||||
n, err := f.rd.read(b, 0)
|
||||
if err == EAGAIN {
|
||||
err = nil
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (f *pipeFile) write(b []byte) (int, error) {
|
||||
if f.wr == nil {
|
||||
return 0, EINVAL
|
||||
}
|
||||
n, err := f.wr.write(b, 0)
|
||||
if err == EAGAIN {
|
||||
err = EPIPE
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func Pipe(fd []int) error {
|
||||
q := newByteq()
|
||||
fd[0] = newFD(&pipeFile{rd: q})
|
||||
fd[1] = newFD(&pipeFile{wr: q})
|
||||
return nil
|
||||
}
|
||||
22
unix/flock.go
Normal file
22
unix/flock.go
Normal file
@@ -0,0 +1,22 @@
|
||||
// +build linux darwin freebsd openbsd netbsd dragonfly
|
||||
|
||||
// Copyright 2014 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.
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// fcntl64Syscall is usually SYS_FCNTL, but is overridden on 32-bit Linux
|
||||
// systems by flock_linux_32bit.go to be SYS_FCNTL64.
|
||||
var fcntl64Syscall uintptr = SYS_FCNTL
|
||||
|
||||
// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
|
||||
func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
|
||||
_, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(unsafe.Pointer(lk)))
|
||||
if errno == 0 {
|
||||
return nil
|
||||
}
|
||||
return errno
|
||||
}
|
||||
13
unix/flock_linux_32bit.go
Normal file
13
unix/flock_linux_32bit.go
Normal file
@@ -0,0 +1,13 @@
|
||||
// +build linux,386 linux,arm
|
||||
|
||||
// Copyright 2014 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.
|
||||
|
||||
package syscall
|
||||
|
||||
func init() {
|
||||
// On 32-bit Linux systems, the fcntl syscall that matches Go's
|
||||
// Flock_t type is SYS_FCNTL64, not SYS_FCNTL.
|
||||
fcntl64Syscall = SYS_FCNTL64
|
||||
}
|
||||
832
unix/fs_nacl.go
Normal file
832
unix/fs_nacl.go
Normal file
@@ -0,0 +1,832 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
// A simulated Unix-like file system for use within NaCl.
|
||||
//
|
||||
// The simulation is not particularly tied to NaCl other than the reuse
|
||||
// of NaCl's definition for the Stat_t structure.
|
||||
//
|
||||
// The file system need never be written to disk, so it is represented as
|
||||
// in-memory Go data structures, never in a serialized form.
|
||||
//
|
||||
// TODO: Perhaps support symlinks, although they muck everything up.
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Provided by package runtime.
|
||||
func now() (sec int64, nsec int32)
|
||||
|
||||
// An fsys is a file system.
|
||||
// Since there is no I/O (everything is in memory),
|
||||
// the global lock mu protects the whole file system state,
|
||||
// and that's okay.
|
||||
type fsys struct {
|
||||
mu sync.Mutex
|
||||
root *inode // root directory
|
||||
cwd *inode // process current directory
|
||||
inum uint64 // number of inodes created
|
||||
dev []func() (devFile, error) // table for opening devices
|
||||
}
|
||||
|
||||
// A devFile is the implementation required of device files
|
||||
// like /dev/null or /dev/random.
|
||||
type devFile interface {
|
||||
pread([]byte, int64) (int, error)
|
||||
pwrite([]byte, int64) (int, error)
|
||||
}
|
||||
|
||||
// An inode is a (possibly special) file in the file system.
|
||||
type inode struct {
|
||||
Stat_t
|
||||
data []byte
|
||||
dir []dirent
|
||||
}
|
||||
|
||||
// A dirent describes a single directory entry.
|
||||
type dirent struct {
|
||||
name string
|
||||
inode *inode
|
||||
}
|
||||
|
||||
// An fsysFile is the fileImpl implementation backed by the file system.
|
||||
type fsysFile struct {
|
||||
defaultFileImpl
|
||||
fsys *fsys
|
||||
inode *inode
|
||||
openmode int
|
||||
offset int64
|
||||
dev devFile
|
||||
}
|
||||
|
||||
// newFsys creates a new file system.
|
||||
func newFsys() *fsys {
|
||||
fs := &fsys{}
|
||||
fs.mu.Lock()
|
||||
defer fs.mu.Unlock()
|
||||
ip := fs.newInode()
|
||||
ip.Mode = 0555 | S_IFDIR
|
||||
fs.dirlink(ip, ".", ip)
|
||||
fs.dirlink(ip, "..", ip)
|
||||
fs.cwd = ip
|
||||
fs.root = ip
|
||||
return fs
|
||||
}
|
||||
|
||||
var fs = newFsys()
|
||||
var fsinit = func() {}
|
||||
|
||||
func init() {
|
||||
// do not trigger loading of zipped file system here
|
||||
oldFsinit := fsinit
|
||||
defer func() { fsinit = oldFsinit }()
|
||||
fsinit = func() {}
|
||||
Mkdir("/dev", 0555)
|
||||
Mkdir("/tmp", 0777)
|
||||
mkdev("/dev/null", 0666, openNull)
|
||||
mkdev("/dev/random", 0444, openRandom)
|
||||
mkdev("/dev/urandom", 0444, openRandom)
|
||||
mkdev("/dev/zero", 0666, openZero)
|
||||
chdirEnv()
|
||||
}
|
||||
|
||||
func chdirEnv() {
|
||||
pwd, ok := Getenv("NACLPWD")
|
||||
if ok {
|
||||
chdir(pwd)
|
||||
}
|
||||
}
|
||||
|
||||
// Except where indicated otherwise, unexported methods on fsys
|
||||
// expect fs.mu to have been locked by the caller.
|
||||
|
||||
// newInode creates a new inode.
|
||||
func (fs *fsys) newInode() *inode {
|
||||
fs.inum++
|
||||
ip := &inode{
|
||||
Stat_t: Stat_t{
|
||||
Ino: fs.inum,
|
||||
Blksize: 512,
|
||||
},
|
||||
}
|
||||
return ip
|
||||
}
|
||||
|
||||
// atime sets ip.Atime to the current time.
|
||||
func (fs *fsys) atime(ip *inode) {
|
||||
sec, nsec := now()
|
||||
ip.Atime, ip.AtimeNsec = sec, int64(nsec)
|
||||
}
|
||||
|
||||
// mtime sets ip.Mtime to the current time.
|
||||
func (fs *fsys) mtime(ip *inode) {
|
||||
sec, nsec := now()
|
||||
ip.Mtime, ip.MtimeNsec = sec, int64(nsec)
|
||||
}
|
||||
|
||||
// dirlookup looks for an entry in the directory dp with the given name.
|
||||
// It returns the directory entry and its index within the directory.
|
||||
func (fs *fsys) dirlookup(dp *inode, name string) (de *dirent, index int, err error) {
|
||||
fs.atime(dp)
|
||||
for i := range dp.dir {
|
||||
de := &dp.dir[i]
|
||||
if de.name == name {
|
||||
fs.atime(de.inode)
|
||||
return de, i, nil
|
||||
}
|
||||
}
|
||||
return nil, 0, ENOENT
|
||||
}
|
||||
|
||||
// dirlink adds to the directory dp an entry for name pointing at the inode ip.
|
||||
// If dp already contains an entry for name, that entry is overwritten.
|
||||
func (fs *fsys) dirlink(dp *inode, name string, ip *inode) {
|
||||
fs.mtime(dp)
|
||||
fs.atime(ip)
|
||||
ip.Nlink++
|
||||
for i := range dp.dir {
|
||||
if dp.dir[i].name == name {
|
||||
dp.dir[i] = dirent{name, ip}
|
||||
return
|
||||
}
|
||||
}
|
||||
dp.dir = append(dp.dir, dirent{name, ip})
|
||||
dp.dirSize()
|
||||
}
|
||||
|
||||
func (dp *inode) dirSize() {
|
||||
dp.Size = int64(len(dp.dir)) * (8 + 8 + 2 + 256) // Dirent
|
||||
}
|
||||
|
||||
// skipelem splits path into the first element and the remainder.
|
||||
// the returned first element contains no slashes, and the returned
|
||||
// remainder does not begin with a slash.
|
||||
func skipelem(path string) (elem, rest string) {
|
||||
for len(path) > 0 && path[0] == '/' {
|
||||
path = path[1:]
|
||||
}
|
||||
if len(path) == 0 {
|
||||
return "", ""
|
||||
}
|
||||
i := 0
|
||||
for i < len(path) && path[i] != '/' {
|
||||
i++
|
||||
}
|
||||
elem, path = path[:i], path[i:]
|
||||
for len(path) > 0 && path[0] == '/' {
|
||||
path = path[1:]
|
||||
}
|
||||
return elem, path
|
||||
}
|
||||
|
||||
// namei translates a file system path name into an inode.
|
||||
// If parent is false, the returned ip corresponds to the given name, and elem is the empty string.
|
||||
// If parent is true, the walk stops at the next-to-last element in the name,
|
||||
// so that ip is the parent directory and elem is the final element in the path.
|
||||
func (fs *fsys) namei(path string, parent bool) (ip *inode, elem string, err error) {
|
||||
// Reject NUL in name.
|
||||
for i := 0; i < len(path); i++ {
|
||||
if path[i] == '\x00' {
|
||||
return nil, "", EINVAL
|
||||
}
|
||||
}
|
||||
|
||||
// Reject empty name.
|
||||
if path == "" {
|
||||
return nil, "", EINVAL
|
||||
}
|
||||
|
||||
if path[0] == '/' {
|
||||
ip = fs.root
|
||||
} else {
|
||||
ip = fs.cwd
|
||||
}
|
||||
|
||||
for len(path) > 0 && path[len(path)-1] == '/' {
|
||||
path = path[:len(path)-1]
|
||||
}
|
||||
|
||||
for {
|
||||
elem, rest := skipelem(path)
|
||||
if elem == "" {
|
||||
if parent && ip.Mode&S_IFMT == S_IFDIR {
|
||||
return ip, ".", nil
|
||||
}
|
||||
break
|
||||
}
|
||||
if ip.Mode&S_IFMT != S_IFDIR {
|
||||
return nil, "", ENOTDIR
|
||||
}
|
||||
if len(elem) >= 256 {
|
||||
return nil, "", ENAMETOOLONG
|
||||
}
|
||||
if parent && rest == "" {
|
||||
// Stop one level early.
|
||||
return ip, elem, nil
|
||||
}
|
||||
de, _, err := fs.dirlookup(ip, elem)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
ip = de.inode
|
||||
path = rest
|
||||
}
|
||||
if parent {
|
||||
return nil, "", ENOTDIR
|
||||
}
|
||||
return ip, "", nil
|
||||
}
|
||||
|
||||
// open opens or creates a file with the given name, open mode,
|
||||
// and permission mode bits.
|
||||
func (fs *fsys) open(name string, openmode int, mode uint32) (fileImpl, error) {
|
||||
dp, elem, err := fs.namei(name, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var (
|
||||
ip *inode
|
||||
dev devFile
|
||||
)
|
||||
de, _, err := fs.dirlookup(dp, elem)
|
||||
if err != nil {
|
||||
if openmode&O_CREATE == 0 {
|
||||
return nil, err
|
||||
}
|
||||
ip = fs.newInode()
|
||||
ip.Mode = mode
|
||||
fs.dirlink(dp, elem, ip)
|
||||
if ip.Mode&S_IFMT == S_IFDIR {
|
||||
fs.dirlink(ip, ".", ip)
|
||||
fs.dirlink(ip, "..", dp)
|
||||
}
|
||||
} else {
|
||||
ip = de.inode
|
||||
if openmode&(O_CREATE|O_EXCL) == O_CREATE|O_EXCL {
|
||||
return nil, EEXIST
|
||||
}
|
||||
if openmode&O_TRUNC != 0 {
|
||||
if ip.Mode&S_IFMT == S_IFDIR {
|
||||
return nil, EISDIR
|
||||
}
|
||||
ip.data = nil
|
||||
}
|
||||
if ip.Mode&S_IFMT == S_IFCHR {
|
||||
if ip.Rdev < 0 || ip.Rdev >= int64(len(fs.dev)) || fs.dev[ip.Rdev] == nil {
|
||||
return nil, ENODEV
|
||||
}
|
||||
dev, err = fs.dev[ip.Rdev]()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch openmode & O_ACCMODE {
|
||||
case O_WRONLY, O_RDWR:
|
||||
if ip.Mode&S_IFMT == S_IFDIR {
|
||||
return nil, EISDIR
|
||||
}
|
||||
}
|
||||
|
||||
switch ip.Mode & S_IFMT {
|
||||
case S_IFDIR:
|
||||
if openmode&O_ACCMODE != O_RDONLY {
|
||||
return nil, EISDIR
|
||||
}
|
||||
|
||||
case S_IFREG:
|
||||
// ok
|
||||
|
||||
case S_IFCHR:
|
||||
// handled above
|
||||
|
||||
default:
|
||||
// TODO: some kind of special file
|
||||
return nil, EPERM
|
||||
}
|
||||
|
||||
f := &fsysFile{
|
||||
fsys: fs,
|
||||
inode: ip,
|
||||
openmode: openmode,
|
||||
dev: dev,
|
||||
}
|
||||
if openmode&O_APPEND != 0 {
|
||||
f.offset = ip.Size
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// fsysFile methods to implement fileImpl.
|
||||
|
||||
func (f *fsysFile) stat(st *Stat_t) error {
|
||||
f.fsys.mu.Lock()
|
||||
defer f.fsys.mu.Unlock()
|
||||
*st = f.inode.Stat_t
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fsysFile) read(b []byte) (int, error) {
|
||||
f.fsys.mu.Lock()
|
||||
defer f.fsys.mu.Unlock()
|
||||
n, err := f.preadLocked(b, f.offset)
|
||||
f.offset += int64(n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func ReadDirent(fd int, buf []byte) (int, error) {
|
||||
f, err := fdToFsysFile(fd)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
f.fsys.mu.Lock()
|
||||
defer f.fsys.mu.Unlock()
|
||||
if f.inode.Mode&S_IFMT != S_IFDIR {
|
||||
return 0, EINVAL
|
||||
}
|
||||
n, err := f.preadLocked(buf, f.offset)
|
||||
f.offset += int64(n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (f *fsysFile) write(b []byte) (int, error) {
|
||||
f.fsys.mu.Lock()
|
||||
defer f.fsys.mu.Unlock()
|
||||
n, err := f.pwriteLocked(b, f.offset)
|
||||
f.offset += int64(n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (f *fsysFile) seek(offset int64, whence int) (int64, error) {
|
||||
f.fsys.mu.Lock()
|
||||
defer f.fsys.mu.Unlock()
|
||||
switch whence {
|
||||
case 1:
|
||||
offset += f.offset
|
||||
case 2:
|
||||
offset += f.inode.Size
|
||||
}
|
||||
if offset < 0 {
|
||||
return 0, EINVAL
|
||||
}
|
||||
if offset > f.inode.Size {
|
||||
return 0, EINVAL
|
||||
}
|
||||
f.offset = offset
|
||||
return offset, nil
|
||||
}
|
||||
|
||||
func (f *fsysFile) pread(b []byte, offset int64) (int, error) {
|
||||
f.fsys.mu.Lock()
|
||||
defer f.fsys.mu.Unlock()
|
||||
return f.preadLocked(b, offset)
|
||||
}
|
||||
|
||||
func (f *fsysFile) pwrite(b []byte, offset int64) (int, error) {
|
||||
f.fsys.mu.Lock()
|
||||
defer f.fsys.mu.Unlock()
|
||||
return f.pwriteLocked(b, offset)
|
||||
}
|
||||
|
||||
func (f *fsysFile) preadLocked(b []byte, offset int64) (int, error) {
|
||||
if f.openmode&O_ACCMODE == O_WRONLY {
|
||||
return 0, EINVAL
|
||||
}
|
||||
if offset < 0 {
|
||||
return 0, EINVAL
|
||||
}
|
||||
if f.dev != nil {
|
||||
f.fsys.atime(f.inode)
|
||||
f.fsys.mu.Unlock()
|
||||
defer f.fsys.mu.Lock()
|
||||
return f.dev.pread(b, offset)
|
||||
}
|
||||
if offset > f.inode.Size {
|
||||
return 0, nil
|
||||
}
|
||||
if int64(len(b)) > f.inode.Size-offset {
|
||||
b = b[:f.inode.Size-offset]
|
||||
}
|
||||
|
||||
if f.inode.Mode&S_IFMT == S_IFDIR {
|
||||
if offset%direntSize != 0 || len(b) != 0 && len(b) < direntSize {
|
||||
return 0, EINVAL
|
||||
}
|
||||
fs.atime(f.inode)
|
||||
n := 0
|
||||
for len(b) >= direntSize {
|
||||
src := f.inode.dir[int(offset/direntSize)]
|
||||
dst := (*Dirent)(unsafe.Pointer(&b[0]))
|
||||
dst.Ino = int64(src.inode.Ino)
|
||||
dst.Off = offset
|
||||
dst.Reclen = direntSize
|
||||
for i := range dst.Name {
|
||||
dst.Name[i] = 0
|
||||
}
|
||||
copy(dst.Name[:], src.name)
|
||||
n += direntSize
|
||||
offset += direntSize
|
||||
b = b[direntSize:]
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
fs.atime(f.inode)
|
||||
n := copy(b, f.inode.data[offset:])
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (f *fsysFile) pwriteLocked(b []byte, offset int64) (int, error) {
|
||||
if f.openmode&O_ACCMODE == O_RDONLY {
|
||||
return 0, EINVAL
|
||||
}
|
||||
if offset < 0 {
|
||||
return 0, EINVAL
|
||||
}
|
||||
if f.dev != nil {
|
||||
f.fsys.atime(f.inode)
|
||||
f.fsys.mu.Unlock()
|
||||
defer f.fsys.mu.Lock()
|
||||
return f.dev.pwrite(b, offset)
|
||||
}
|
||||
if offset > f.inode.Size {
|
||||
return 0, EINVAL
|
||||
}
|
||||
f.fsys.mtime(f.inode)
|
||||
n := copy(f.inode.data[offset:], b)
|
||||
if n < len(b) {
|
||||
f.inode.data = append(f.inode.data, b[n:]...)
|
||||
f.inode.Size = int64(len(f.inode.data))
|
||||
}
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
// Standard Unix system calls.
|
||||
|
||||
func Open(path string, openmode int, perm uint32) (fd int, err error) {
|
||||
fsinit()
|
||||
fs.mu.Lock()
|
||||
defer fs.mu.Unlock()
|
||||
f, err := fs.open(path, openmode, perm&0777|S_IFREG)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return newFD(f), nil
|
||||
}
|
||||
|
||||
func Mkdir(path string, perm uint32) error {
|
||||
fs.mu.Lock()
|
||||
defer fs.mu.Unlock()
|
||||
_, err := fs.open(path, O_CREATE|O_EXCL, perm&0777|S_IFDIR)
|
||||
return err
|
||||
}
|
||||
|
||||
func Getcwd(buf []byte) (n int, err error) {
|
||||
// Force package os to default to the old algorithm using .. and directory reads.
|
||||
return 0, ENOSYS
|
||||
}
|
||||
|
||||
func Stat(path string, st *Stat_t) error {
|
||||
fsinit()
|
||||
fs.mu.Lock()
|
||||
defer fs.mu.Unlock()
|
||||
ip, _, err := fs.namei(path, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*st = ip.Stat_t
|
||||
return nil
|
||||
}
|
||||
|
||||
func Lstat(path string, st *Stat_t) error {
|
||||
return Stat(path, st)
|
||||
}
|
||||
|
||||
func unlink(path string, isdir bool) error {
|
||||
fsinit()
|
||||
fs.mu.Lock()
|
||||
defer fs.mu.Unlock()
|
||||
dp, elem, err := fs.namei(path, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if elem == "." || elem == ".." {
|
||||
return EINVAL
|
||||
}
|
||||
de, _, err := fs.dirlookup(dp, elem)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if isdir {
|
||||
if de.inode.Mode&S_IFMT != S_IFDIR {
|
||||
return ENOTDIR
|
||||
}
|
||||
if len(de.inode.dir) != 2 {
|
||||
return ENOTEMPTY
|
||||
}
|
||||
} else {
|
||||
if de.inode.Mode&S_IFMT == S_IFDIR {
|
||||
return EISDIR
|
||||
}
|
||||
}
|
||||
de.inode.Nlink--
|
||||
*de = dp.dir[len(dp.dir)-1]
|
||||
dp.dir = dp.dir[:len(dp.dir)-1]
|
||||
dp.dirSize()
|
||||
return nil
|
||||
}
|
||||
|
||||
func Unlink(path string) error {
|
||||
return unlink(path, false)
|
||||
}
|
||||
|
||||
func Rmdir(path string) error {
|
||||
return unlink(path, true)
|
||||
}
|
||||
|
||||
func Chmod(path string, mode uint32) error {
|
||||
fsinit()
|
||||
fs.mu.Lock()
|
||||
defer fs.mu.Unlock()
|
||||
ip, _, err := fs.namei(path, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ip.Mode = ip.Mode&^0777 | mode&0777
|
||||
return nil
|
||||
}
|
||||
|
||||
func Fchmod(fd int, mode uint32) error {
|
||||
f, err := fdToFsysFile(fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.fsys.mu.Lock()
|
||||
defer f.fsys.mu.Unlock()
|
||||
f.inode.Mode = f.inode.Mode&^0777 | mode&0777
|
||||
return nil
|
||||
}
|
||||
|
||||
func Chown(path string, uid, gid int) error {
|
||||
fsinit()
|
||||
fs.mu.Lock()
|
||||
defer fs.mu.Unlock()
|
||||
ip, _, err := fs.namei(path, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ip.Uid = uint32(uid)
|
||||
ip.Gid = uint32(gid)
|
||||
return nil
|
||||
}
|
||||
|
||||
func Fchown(fd int, uid, gid int) error {
|
||||
fs.mu.Lock()
|
||||
defer fs.mu.Unlock()
|
||||
f, err := fdToFsysFile(fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.fsys.mu.Lock()
|
||||
defer f.fsys.mu.Unlock()
|
||||
f.inode.Uid = uint32(uid)
|
||||
f.inode.Gid = uint32(gid)
|
||||
return nil
|
||||
}
|
||||
|
||||
func Lchown(path string, uid, gid int) error {
|
||||
return Chown(path, uid, gid)
|
||||
}
|
||||
|
||||
func UtimesNano(path string, ts []Timespec) error {
|
||||
if len(ts) != 2 {
|
||||
return EINVAL
|
||||
}
|
||||
fsinit()
|
||||
fs.mu.Lock()
|
||||
defer fs.mu.Unlock()
|
||||
ip, _, err := fs.namei(path, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ip.Atime = ts[0].Sec
|
||||
ip.AtimeNsec = int64(ts[0].Nsec)
|
||||
ip.Mtime = ts[1].Sec
|
||||
ip.MtimeNsec = int64(ts[1].Nsec)
|
||||
return nil
|
||||
}
|
||||
|
||||
func Link(path, link string) error {
|
||||
fsinit()
|
||||
ip, _, err := fs.namei(path, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dp, elem, err := fs.namei(link, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ip.Mode&S_IFMT == S_IFDIR {
|
||||
return EPERM
|
||||
}
|
||||
fs.dirlink(dp, elem, ip)
|
||||
return nil
|
||||
}
|
||||
|
||||
func Rename(from, to string) error {
|
||||
fsinit()
|
||||
fdp, felem, err := fs.namei(from, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fde, _, err := fs.dirlookup(fdp, felem)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tdp, telem, err := fs.namei(to, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fs.dirlink(tdp, telem, fde.inode)
|
||||
fde.inode.Nlink--
|
||||
*fde = fdp.dir[len(fdp.dir)-1]
|
||||
fdp.dir = fdp.dir[:len(fdp.dir)-1]
|
||||
fdp.dirSize()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fs *fsys) truncate(ip *inode, length int64) error {
|
||||
if length > 1e9 || ip.Mode&S_IFMT != S_IFREG {
|
||||
return EINVAL
|
||||
}
|
||||
if length < int64(len(ip.data)) {
|
||||
ip.data = ip.data[:length]
|
||||
} else {
|
||||
data := make([]byte, length)
|
||||
copy(data, ip.data)
|
||||
ip.data = data
|
||||
}
|
||||
ip.Size = int64(len(ip.data))
|
||||
return nil
|
||||
}
|
||||
|
||||
func Truncate(path string, length int64) error {
|
||||
fsinit()
|
||||
fs.mu.Lock()
|
||||
defer fs.mu.Unlock()
|
||||
ip, _, err := fs.namei(path, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fs.truncate(ip, length)
|
||||
}
|
||||
|
||||
func Ftruncate(fd int, length int64) error {
|
||||
f, err := fdToFsysFile(fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.fsys.mu.Lock()
|
||||
defer f.fsys.mu.Unlock()
|
||||
return f.fsys.truncate(f.inode, length)
|
||||
}
|
||||
|
||||
func Chdir(path string) error {
|
||||
fsinit()
|
||||
return chdir(path)
|
||||
}
|
||||
|
||||
func chdir(path string) error {
|
||||
fs.mu.Lock()
|
||||
defer fs.mu.Unlock()
|
||||
ip, _, err := fs.namei(path, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fs.cwd = ip
|
||||
return nil
|
||||
}
|
||||
|
||||
func Fchdir(fd int) error {
|
||||
f, err := fdToFsysFile(fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.fsys.mu.Lock()
|
||||
defer f.fsys.mu.Unlock()
|
||||
if f.inode.Mode&S_IFMT != S_IFDIR {
|
||||
return ENOTDIR
|
||||
}
|
||||
fs.cwd = f.inode
|
||||
return nil
|
||||
}
|
||||
|
||||
func Readlink(path string, buf []byte) (n int, err error) {
|
||||
return 0, ENOSYS
|
||||
}
|
||||
|
||||
func Symlink(path, link string) error {
|
||||
return ENOSYS
|
||||
}
|
||||
|
||||
func Fsync(fd int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Special devices.
|
||||
|
||||
func mkdev(path string, mode uint32, open func() (devFile, error)) error {
|
||||
f, err := fs.open(path, O_CREATE|O_RDONLY|O_EXCL, S_IFCHR|mode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ip := f.(*fsysFile).inode
|
||||
ip.Rdev = int64(len(fs.dev))
|
||||
fs.dev = append(fs.dev, open)
|
||||
return nil
|
||||
}
|
||||
|
||||
type nullFile struct{}
|
||||
|
||||
func openNull() (devFile, error) { return &nullFile{}, nil }
|
||||
func (f *nullFile) close() error { return nil }
|
||||
func (f *nullFile) pread(b []byte, offset int64) (int, error) { return 0, nil }
|
||||
func (f *nullFile) pwrite(b []byte, offset int64) (int, error) { return len(b), nil }
|
||||
|
||||
type zeroFile struct{}
|
||||
|
||||
func openZero() (devFile, error) { return &zeroFile{}, nil }
|
||||
func (f *zeroFile) close() error { return nil }
|
||||
func (f *zeroFile) pwrite(b []byte, offset int64) (int, error) { return len(b), nil }
|
||||
|
||||
func (f *zeroFile) pread(b []byte, offset int64) (int, error) {
|
||||
for i := range b {
|
||||
b[i] = 0
|
||||
}
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
type randomFile struct {
|
||||
naclFD int
|
||||
}
|
||||
|
||||
func openRandom() (devFile, error) {
|
||||
fd, err := openNamedService("SecureRandom", O_RDONLY)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &randomFile{naclFD: fd}, nil
|
||||
}
|
||||
|
||||
func (f *randomFile) close() error {
|
||||
naclClose(f.naclFD)
|
||||
f.naclFD = -1
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *randomFile) pread(b []byte, offset int64) (int, error) {
|
||||
return naclRead(f.naclFD, b)
|
||||
}
|
||||
|
||||
func (f *randomFile) pwrite(b []byte, offset int64) (int, error) {
|
||||
return 0, EPERM
|
||||
}
|
||||
|
||||
func fdToFsysFile(fd int) (*fsysFile, error) {
|
||||
f, err := fdToFile(fd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
impl := f.impl
|
||||
fsysf, ok := impl.(*fsysFile)
|
||||
if !ok {
|
||||
return nil, EINVAL
|
||||
}
|
||||
return fsysf, nil
|
||||
}
|
||||
|
||||
// create creates a file in the file system with the given name, mode, time, and data.
|
||||
// It is meant to be called when initializing the file system image.
|
||||
func create(name string, mode uint32, sec int64, data []byte) error {
|
||||
fs.mu.Lock()
|
||||
fs.mu.Unlock()
|
||||
f, err := fs.open(name, O_CREATE|O_EXCL, mode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ip := f.(*fsysFile).inode
|
||||
ip.Atime = sec
|
||||
ip.Mtime = sec
|
||||
ip.Ctime = sec
|
||||
if len(data) > 0 {
|
||||
ip.Size = int64(len(data))
|
||||
ip.data = data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
78
unix/lsf_linux.go
Normal file
78
unix/lsf_linux.go
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright 2011 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.
|
||||
|
||||
// Linux socket filter
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func LsfStmt(code, k int) *SockFilter {
|
||||
return &SockFilter{Code: uint16(code), K: uint32(k)}
|
||||
}
|
||||
|
||||
func LsfJump(code, k, jt, jf int) *SockFilter {
|
||||
return &SockFilter{Code: uint16(code), Jt: uint8(jt), Jf: uint8(jf), K: uint32(k)}
|
||||
}
|
||||
|
||||
func LsfSocket(ifindex, proto int) (int, error) {
|
||||
var lsall SockaddrLinklayer
|
||||
s, e := Socket(AF_PACKET, SOCK_RAW, proto)
|
||||
if e != nil {
|
||||
return 0, e
|
||||
}
|
||||
p := (*[2]byte)(unsafe.Pointer(&lsall.Protocol))
|
||||
p[0] = byte(proto >> 8)
|
||||
p[1] = byte(proto)
|
||||
lsall.Ifindex = ifindex
|
||||
e = Bind(s, &lsall)
|
||||
if e != nil {
|
||||
Close(s)
|
||||
return 0, e
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
type iflags struct {
|
||||
name [IFNAMSIZ]byte
|
||||
flags uint16
|
||||
}
|
||||
|
||||
func SetLsfPromisc(name string, m bool) error {
|
||||
s, e := Socket(AF_INET, SOCK_DGRAM, 0)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
defer Close(s)
|
||||
var ifl iflags
|
||||
copy(ifl.name[:], []byte(name))
|
||||
_, _, ep := Syscall(SYS_IOCTL, uintptr(s), SIOCGIFFLAGS, uintptr(unsafe.Pointer(&ifl)))
|
||||
if ep != 0 {
|
||||
return Errno(ep)
|
||||
}
|
||||
if m {
|
||||
ifl.flags |= uint16(IFF_PROMISC)
|
||||
} else {
|
||||
ifl.flags &= ^uint16(IFF_PROMISC)
|
||||
}
|
||||
_, _, ep = Syscall(SYS_IOCTL, uintptr(s), SIOCSIFFLAGS, uintptr(unsafe.Pointer(&ifl)))
|
||||
if ep != 0 {
|
||||
return Errno(ep)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func AttachLsf(fd int, i []SockFilter) error {
|
||||
var p SockFprog
|
||||
p.Len = uint16(len(i))
|
||||
p.Filter = (*SockFilter)(unsafe.Pointer(&i[0]))
|
||||
return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, unsafe.Pointer(&p), unsafe.Sizeof(p))
|
||||
}
|
||||
|
||||
func DetachLsf(fd int) error {
|
||||
var dummy int
|
||||
return setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, unsafe.Pointer(&dummy), unsafe.Sizeof(dummy))
|
||||
}
|
||||
263
unix/mkall.sh
Executable file
263
unix/mkall.sh
Executable file
@@ -0,0 +1,263 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright 2009 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.
|
||||
|
||||
# The syscall package provides access to the raw system call
|
||||
# interface of the underlying operating system. Porting Go to
|
||||
# a new architecture/operating system combination requires
|
||||
# some manual effort, though there are tools that automate
|
||||
# much of the process. The auto-generated files have names
|
||||
# beginning with z.
|
||||
#
|
||||
# This script runs or (given -n) prints suggested commands to generate z files
|
||||
# for the current system. Running those commands is not automatic.
|
||||
# This script is documentation more than anything else.
|
||||
#
|
||||
# * asm_${GOOS}_${GOARCH}.s
|
||||
#
|
||||
# This hand-written assembly file implements system call dispatch.
|
||||
# There are three entry points:
|
||||
#
|
||||
# func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr);
|
||||
# func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
|
||||
# func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr);
|
||||
#
|
||||
# The first and second are the standard ones; they differ only in
|
||||
# how many arguments can be passed to the kernel.
|
||||
# The third is for low-level use by the ForkExec wrapper;
|
||||
# unlike the first two, it does not call into the scheduler to
|
||||
# let it know that a system call is running.
|
||||
#
|
||||
# * syscall_${GOOS}.go
|
||||
#
|
||||
# This hand-written Go file implements system calls that need
|
||||
# special handling and lists "//sys" comments giving prototypes
|
||||
# for ones that can be auto-generated. Mksyscall reads those
|
||||
# comments to generate the stubs.
|
||||
#
|
||||
# * syscall_${GOOS}_${GOARCH}.go
|
||||
#
|
||||
# Same as syscall_${GOOS}.go except that it contains code specific
|
||||
# to ${GOOS} on one particular architecture.
|
||||
#
|
||||
# * types_${GOOS}.c
|
||||
#
|
||||
# This hand-written C file includes standard C headers and then
|
||||
# creates typedef or enum names beginning with a dollar sign
|
||||
# (use of $ in variable names is a gcc extension). The hardest
|
||||
# part about preparing this file is figuring out which headers to
|
||||
# include and which symbols need to be #defined to get the
|
||||
# actual data structures that pass through to the kernel system calls.
|
||||
# Some C libraries present alternate versions for binary compatibility
|
||||
# and translate them on the way in and out of system calls, but
|
||||
# there is almost always a #define that can get the real ones.
|
||||
# See types_darwin.c and types_linux.c for examples.
|
||||
#
|
||||
# * zerror_${GOOS}_${GOARCH}.go
|
||||
#
|
||||
# This machine-generated file defines the system's error numbers,
|
||||
# error strings, and signal numbers. The generator is "mkerrors.sh".
|
||||
# Usually no arguments are needed, but mkerrors.sh will pass its
|
||||
# arguments on to godefs.
|
||||
#
|
||||
# * zsyscall_${GOOS}_${GOARCH}.go
|
||||
#
|
||||
# Generated by mksyscall.pl; see syscall_${GOOS}.go above.
|
||||
#
|
||||
# * zsysnum_${GOOS}_${GOARCH}.go
|
||||
#
|
||||
# Generated by mksysnum_${GOOS}.
|
||||
#
|
||||
# * ztypes_${GOOS}_${GOARCH}.go
|
||||
#
|
||||
# Generated by godefs; see types_${GOOS}.c above.
|
||||
|
||||
GOOSARCH="${GOOS}_${GOARCH}"
|
||||
|
||||
# defaults
|
||||
mksyscall="./mksyscall.pl"
|
||||
mkerrors="./mkerrors.sh"
|
||||
zerrors="zerrors_$GOOSARCH.go"
|
||||
mksysctl=""
|
||||
zsysctl="zsysctl_$GOOSARCH.go"
|
||||
mksysnum=
|
||||
mktypes=
|
||||
run="sh"
|
||||
|
||||
case "$1" in
|
||||
-syscalls)
|
||||
for i in zsyscall*go
|
||||
do
|
||||
sed 1q $i | sed 's;^// ;;' | sh > _$i && gofmt < _$i > $i
|
||||
rm _$i
|
||||
done
|
||||
exit 0
|
||||
;;
|
||||
-n)
|
||||
run="cat"
|
||||
shift
|
||||
esac
|
||||
|
||||
case "$#" in
|
||||
0)
|
||||
;;
|
||||
*)
|
||||
echo 'usage: mkall.sh [-n]' 1>&2
|
||||
exit 2
|
||||
esac
|
||||
|
||||
case "$GOOSARCH" in
|
||||
_* | *_ | _)
|
||||
echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
darwin_386)
|
||||
mkerrors="$mkerrors -m32"
|
||||
mksyscall="./mksyscall.pl -l32"
|
||||
mksysnum="./mksysnum_darwin.pl /usr/include/sys/syscall.h"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
darwin_amd64)
|
||||
mkerrors="$mkerrors -m64"
|
||||
mksysnum="./mksysnum_darwin.pl /usr/include/sys/syscall.h"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
dragonfly_386)
|
||||
mkerrors="$mkerrors -m32"
|
||||
mksyscall="./mksyscall.pl -l32 -dragonfly"
|
||||
mksysnum="curl -s 'http://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/sys/kern/syscalls.master' | ./mksysnum_dragonfly.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
dragonfly_amd64)
|
||||
mkerrors="$mkerrors -m64"
|
||||
mksyscall="./mksyscall.pl -dragonfly"
|
||||
mksysnum="curl -s 'http://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/sys/kern/syscalls.master' | ./mksysnum_dragonfly.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
freebsd_386)
|
||||
mkerrors="$mkerrors -m32"
|
||||
mksyscall="./mksyscall.pl -l32"
|
||||
mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
freebsd_amd64)
|
||||
mkerrors="$mkerrors -m64"
|
||||
mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
freebsd_arm)
|
||||
mkerrors="$mkerrors"
|
||||
mksyscall="./mksyscall.pl -l32 -arm"
|
||||
mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
|
||||
# Let the type of C char be singed for making the bare syscall
|
||||
# API consistent across over platforms.
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
|
||||
;;
|
||||
linux_386)
|
||||
mkerrors="$mkerrors -m32"
|
||||
mksyscall="./mksyscall.pl -l32"
|
||||
mksysnum="./mksysnum_linux.pl /usr/include/asm/unistd_32.h"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
linux_amd64)
|
||||
unistd_h=$(ls -1 /usr/include/asm/unistd_64.h /usr/include/x86_64-linux-gnu/asm/unistd_64.h 2>/dev/null | head -1)
|
||||
if [ "$unistd_h" = "" ]; then
|
||||
echo >&2 cannot find unistd_64.h
|
||||
exit 1
|
||||
fi
|
||||
mkerrors="$mkerrors -m64"
|
||||
mksysnum="./mksysnum_linux.pl $unistd_h"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
linux_arm)
|
||||
mkerrors="$mkerrors"
|
||||
mksyscall="./mksyscall.pl -l32 -arm"
|
||||
mksysnum="curl -s 'http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/plain/arch/arm/include/uapi/asm/unistd.h' | ./mksysnum_linux.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
nacl_386)
|
||||
mkerrors=""
|
||||
mksyscall="./mksyscall.pl -l32 -nacl"
|
||||
mksysnum=""
|
||||
mktypes=""
|
||||
;;
|
||||
nacl_amd64p32)
|
||||
mkerrors=""
|
||||
mksyscall="./mksyscall.pl -nacl"
|
||||
mksysnum=""
|
||||
mktypes=""
|
||||
;;
|
||||
netbsd_386)
|
||||
mkerrors="$mkerrors -m32"
|
||||
mksyscall="./mksyscall.pl -l32 -netbsd"
|
||||
mksysnum="curl -s 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_netbsd.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
netbsd_amd64)
|
||||
mkerrors="$mkerrors -m64"
|
||||
mksyscall="./mksyscall.pl -netbsd"
|
||||
mksysnum="curl -s 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_netbsd.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
openbsd_386)
|
||||
mkerrors="$mkerrors -m32"
|
||||
mksyscall="./mksyscall.pl -l32 -openbsd"
|
||||
mksysctl="./mksysctl_openbsd.pl"
|
||||
zsysctl="zsysctl_openbsd.go"
|
||||
mksysnum="curl -s 'http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
openbsd_amd64)
|
||||
mkerrors="$mkerrors -m64"
|
||||
mksyscall="./mksyscall.pl -openbsd"
|
||||
mksysctl="./mksysctl_openbsd.pl"
|
||||
zsysctl="zsysctl_openbsd.go"
|
||||
mksysnum="curl -s 'http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
plan9_386)
|
||||
mkerrors=
|
||||
mksyscall="./mksyscall.pl -l32 -plan9"
|
||||
mksysnum="./mksysnum_plan9.sh /n/sources/plan9/sys/src/libc/9syscall/sys.h"
|
||||
mktypes="XXX"
|
||||
;;
|
||||
solaris_amd64)
|
||||
mksyscall="./mksyscall_solaris.pl"
|
||||
mkerrors="$mkerrors -m64"
|
||||
mksysnum=
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
windows_*)
|
||||
mksyscall=
|
||||
mkerrors=
|
||||
zerrors=
|
||||
;;
|
||||
*)
|
||||
echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
(
|
||||
if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >$zerrors"; fi
|
||||
case "$GOOS" in
|
||||
windows)
|
||||
echo "GOOS= GOARCH= go build mksyscall_windows.go"
|
||||
echo "./mksyscall_windows syscall_windows.go security_windows.go syscall_$GOOSARCH.go |gofmt >zsyscall_$GOOSARCH.go"
|
||||
echo "rm -f ./mksyscall_windows"
|
||||
;;
|
||||
*)
|
||||
syscall_goos="syscall_$GOOS.go"
|
||||
case "$GOOS" in
|
||||
darwin | dragonfly | freebsd | netbsd | openbsd)
|
||||
syscall_goos="syscall_bsd.go $syscall_goos"
|
||||
;;
|
||||
esac
|
||||
if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos syscall_$GOOSARCH.go |gofmt >zsyscall_$GOOSARCH.go"; fi
|
||||
;;
|
||||
esac
|
||||
if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
|
||||
if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
|
||||
if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go |gofmt >ztypes_$GOOSARCH.go"; fi
|
||||
) | $run
|
||||
313
unix/mksyscall.pl
Executable file
313
unix/mksyscall.pl
Executable file
@@ -0,0 +1,313 @@
|
||||
#!/usr/bin/env perl
|
||||
# Copyright 2009 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.
|
||||
|
||||
# This program reads a file containing function prototypes
|
||||
# (like syscall_darwin.go) and generates system call bodies.
|
||||
# The prototypes are marked by lines beginning with "//sys"
|
||||
# and read like func declarations if //sys is replaced by func, but:
|
||||
# * The parameter lists must give a name for each argument.
|
||||
# This includes return parameters.
|
||||
# * The parameter lists must give a type for each argument:
|
||||
# the (x, y, z int) shorthand is not allowed.
|
||||
# * If the return parameter is an error number, it must be named errno.
|
||||
|
||||
# A line beginning with //sysnb is like //sys, except that the
|
||||
# goroutine will not be suspended during the execution of the system
|
||||
# call. This must only be used for system calls which can never
|
||||
# block, as otherwise the system call could cause all goroutines to
|
||||
# hang.
|
||||
|
||||
use strict;
|
||||
|
||||
my $cmdline = "mksyscall.pl " . join(' ', @ARGV);
|
||||
my $errors = 0;
|
||||
my $_32bit = "";
|
||||
my $plan9 = 0;
|
||||
my $openbsd = 0;
|
||||
my $netbsd = 0;
|
||||
my $dragonfly = 0;
|
||||
my $nacl = 0;
|
||||
my $arm = 0; # 64-bit value should use (even, odd)-pair
|
||||
|
||||
if($ARGV[0] eq "-b32") {
|
||||
$_32bit = "big-endian";
|
||||
shift;
|
||||
} elsif($ARGV[0] eq "-l32") {
|
||||
$_32bit = "little-endian";
|
||||
shift;
|
||||
}
|
||||
if($ARGV[0] eq "-plan9") {
|
||||
$plan9 = 1;
|
||||
shift;
|
||||
}
|
||||
if($ARGV[0] eq "-openbsd") {
|
||||
$openbsd = 1;
|
||||
shift;
|
||||
}
|
||||
if($ARGV[0] eq "-netbsd") {
|
||||
$netbsd = 1;
|
||||
shift;
|
||||
}
|
||||
if($ARGV[0] eq "-dragonfly") {
|
||||
$dragonfly = 1;
|
||||
shift;
|
||||
}
|
||||
if($ARGV[0] eq "-nacl") {
|
||||
$nacl = 1;
|
||||
shift;
|
||||
}
|
||||
if($ARGV[0] eq "-arm") {
|
||||
$arm = 1;
|
||||
shift;
|
||||
}
|
||||
|
||||
if($ARGV[0] =~ /^-/) {
|
||||
print STDERR "usage: mksyscall.pl [-b32 | -l32] [file ...]\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
sub parseparamlist($) {
|
||||
my ($list) = @_;
|
||||
$list =~ s/^\s*//;
|
||||
$list =~ s/\s*$//;
|
||||
if($list eq "") {
|
||||
return ();
|
||||
}
|
||||
return split(/\s*,\s*/, $list);
|
||||
}
|
||||
|
||||
sub parseparam($) {
|
||||
my ($p) = @_;
|
||||
if($p !~ /^(\S*) (\S*)$/) {
|
||||
print STDERR "$ARGV:$.: malformed parameter: $p\n";
|
||||
$errors = 1;
|
||||
return ("xx", "int");
|
||||
}
|
||||
return ($1, $2);
|
||||
}
|
||||
|
||||
my $text = "";
|
||||
while(<>) {
|
||||
chomp;
|
||||
s/\s+/ /g;
|
||||
s/^\s+//;
|
||||
s/\s+$//;
|
||||
my $nonblock = /^\/\/sysnb /;
|
||||
next if !/^\/\/sys / && !$nonblock;
|
||||
|
||||
# Line must be of the form
|
||||
# func Open(path string, mode int, perm int) (fd int, errno error)
|
||||
# Split into name, in params, out params.
|
||||
if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*((?i)SYS_[A-Z0-9_]+))?$/) {
|
||||
print STDERR "$ARGV:$.: malformed //sys declaration\n";
|
||||
$errors = 1;
|
||||
next;
|
||||
}
|
||||
my ($func, $in, $out, $sysname) = ($2, $3, $4, $5);
|
||||
|
||||
# Split argument lists on comma.
|
||||
my @in = parseparamlist($in);
|
||||
my @out = parseparamlist($out);
|
||||
|
||||
# Try in vain to keep people from editing this file.
|
||||
# The theory is that they jump into the middle of the file
|
||||
# without reading the header.
|
||||
$text .= "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n";
|
||||
|
||||
# Go function header.
|
||||
my $out_decl = @out ? sprintf(" (%s)", join(', ', @out)) : "";
|
||||
$text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out_decl;
|
||||
|
||||
# Check if err return available
|
||||
my $errvar = "";
|
||||
foreach my $p (@out) {
|
||||
my ($name, $type) = parseparam($p);
|
||||
if($type eq "error") {
|
||||
$errvar = $name;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
# Prepare arguments to Syscall.
|
||||
my @args = ();
|
||||
my $n = 0;
|
||||
foreach my $p (@in) {
|
||||
my ($name, $type) = parseparam($p);
|
||||
if($type =~ /^\*/) {
|
||||
push @args, "uintptr(unsafe.Pointer($name))";
|
||||
} elsif($type eq "string" && $errvar ne "") {
|
||||
$text .= "\tvar _p$n *byte\n";
|
||||
$text .= "\t_p$n, $errvar = BytePtrFromString($name)\n";
|
||||
$text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n";
|
||||
push @args, "uintptr(unsafe.Pointer(_p$n))";
|
||||
$n++;
|
||||
} elsif($type eq "string") {
|
||||
print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n";
|
||||
$text .= "\tvar _p$n *byte\n";
|
||||
$text .= "\t_p$n, _ = BytePtrFromString($name)\n";
|
||||
push @args, "uintptr(unsafe.Pointer(_p$n))";
|
||||
$n++;
|
||||
} elsif($type =~ /^\[\](.*)/) {
|
||||
# Convert slice into pointer, length.
|
||||
# Have to be careful not to take address of &a[0] if len == 0:
|
||||
# pass dummy pointer in that case.
|
||||
# Used to pass nil, but some OSes or simulators reject write(fd, nil, 0).
|
||||
$text .= "\tvar _p$n unsafe.Pointer\n";
|
||||
$text .= "\tif len($name) > 0 {\n\t\t_p$n = unsafe.Pointer(\&${name}[0])\n\t}";
|
||||
$text .= " else {\n\t\t_p$n = unsafe.Pointer(&_zero)\n\t}";
|
||||
$text .= "\n";
|
||||
push @args, "uintptr(_p$n)", "uintptr(len($name))";
|
||||
$n++;
|
||||
} elsif($type eq "int64" && ($openbsd || $netbsd)) {
|
||||
push @args, "0";
|
||||
if($_32bit eq "big-endian") {
|
||||
push @args, "uintptr($name>>32)", "uintptr($name)";
|
||||
} elsif($_32bit eq "little-endian") {
|
||||
push @args, "uintptr($name)", "uintptr($name>>32)";
|
||||
} else {
|
||||
push @args, "uintptr($name)";
|
||||
}
|
||||
} elsif($type eq "int64" && $dragonfly) {
|
||||
if ($func !~ /^extp(read|write)/i) {
|
||||
push @args, "0";
|
||||
}
|
||||
if($_32bit eq "big-endian") {
|
||||
push @args, "uintptr($name>>32)", "uintptr($name)";
|
||||
} elsif($_32bit eq "little-endian") {
|
||||
push @args, "uintptr($name)", "uintptr($name>>32)";
|
||||
} else {
|
||||
push @args, "uintptr($name)";
|
||||
}
|
||||
} elsif($type eq "int64" && $_32bit ne "") {
|
||||
if(@args % 2 && $arm) {
|
||||
# arm abi specifies 64-bit argument uses
|
||||
# (even, odd) pair
|
||||
push @args, "0"
|
||||
}
|
||||
if($_32bit eq "big-endian") {
|
||||
push @args, "uintptr($name>>32)", "uintptr($name)";
|
||||
} else {
|
||||
push @args, "uintptr($name)", "uintptr($name>>32)";
|
||||
}
|
||||
} else {
|
||||
push @args, "uintptr($name)";
|
||||
}
|
||||
}
|
||||
|
||||
# Determine which form to use; pad args with zeros.
|
||||
my $asm = "Syscall";
|
||||
if ($nonblock) {
|
||||
$asm = "RawSyscall";
|
||||
}
|
||||
if(@args <= 3) {
|
||||
while(@args < 3) {
|
||||
push @args, "0";
|
||||
}
|
||||
} elsif(@args <= 6) {
|
||||
$asm .= "6";
|
||||
while(@args < 6) {
|
||||
push @args, "0";
|
||||
}
|
||||
} elsif(@args <= 9) {
|
||||
$asm .= "9";
|
||||
while(@args < 9) {
|
||||
push @args, "0";
|
||||
}
|
||||
} else {
|
||||
print STDERR "$ARGV:$.: too many arguments to system call\n";
|
||||
}
|
||||
|
||||
# System call number.
|
||||
if($sysname eq "") {
|
||||
$sysname = "SYS_$func";
|
||||
$sysname =~ s/([a-z])([A-Z])/${1}_$2/g; # turn FooBar into Foo_Bar
|
||||
$sysname =~ y/a-z/A-Z/;
|
||||
if($nacl) {
|
||||
$sysname =~ y/A-Z/a-z/;
|
||||
}
|
||||
}
|
||||
|
||||
# Actual call.
|
||||
my $args = join(', ', @args);
|
||||
my $call = "$asm($sysname, $args)";
|
||||
|
||||
# Assign return values.
|
||||
my $body = "";
|
||||
my @ret = ("_", "_", "_");
|
||||
my $do_errno = 0;
|
||||
for(my $i=0; $i<@out; $i++) {
|
||||
my $p = $out[$i];
|
||||
my ($name, $type) = parseparam($p);
|
||||
my $reg = "";
|
||||
if($name eq "err" && !$plan9) {
|
||||
$reg = "e1";
|
||||
$ret[2] = $reg;
|
||||
$do_errno = 1;
|
||||
} elsif($name eq "err" && $plan9) {
|
||||
$ret[0] = "r0";
|
||||
$ret[2] = "e1";
|
||||
next;
|
||||
} else {
|
||||
$reg = sprintf("r%d", $i);
|
||||
$ret[$i] = $reg;
|
||||
}
|
||||
if($type eq "bool") {
|
||||
$reg = "$reg != 0";
|
||||
}
|
||||
if($type eq "int64" && $_32bit ne "") {
|
||||
# 64-bit number in r1:r0 or r0:r1.
|
||||
if($i+2 > @out) {
|
||||
print STDERR "$ARGV:$.: not enough registers for int64 return\n";
|
||||
}
|
||||
if($_32bit eq "big-endian") {
|
||||
$reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i, $i+1);
|
||||
} else {
|
||||
$reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i+1, $i);
|
||||
}
|
||||
$ret[$i] = sprintf("r%d", $i);
|
||||
$ret[$i+1] = sprintf("r%d", $i+1);
|
||||
}
|
||||
if($reg ne "e1" || $plan9) {
|
||||
$body .= "\t$name = $type($reg)\n";
|
||||
}
|
||||
}
|
||||
if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") {
|
||||
$text .= "\t$call\n";
|
||||
} else {
|
||||
$text .= "\t$ret[0], $ret[1], $ret[2] := $call\n";
|
||||
}
|
||||
$text .= $body;
|
||||
|
||||
if ($plan9 && $ret[2] eq "e1") {
|
||||
$text .= "\tif int32(r0) == -1 {\n";
|
||||
$text .= "\t\terr = e1\n";
|
||||
$text .= "\t}\n";
|
||||
} elsif ($do_errno) {
|
||||
$text .= "\tif e1 != 0 {\n";
|
||||
$text .= "\t\terr = e1\n";
|
||||
$text .= "\t}\n";
|
||||
}
|
||||
$text .= "\treturn\n";
|
||||
$text .= "}\n\n";
|
||||
}
|
||||
|
||||
chomp $text;
|
||||
chomp $text;
|
||||
|
||||
if($errors) {
|
||||
exit 1;
|
||||
}
|
||||
|
||||
print <<EOF;
|
||||
// $cmdline
|
||||
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
$text
|
||||
EOF
|
||||
exit 0;
|
||||
279
unix/mksyscall_solaris.pl
Executable file
279
unix/mksyscall_solaris.pl
Executable file
@@ -0,0 +1,279 @@
|
||||
#!/usr/bin/env perl
|
||||
# Copyright 2009 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.
|
||||
|
||||
# This program reads a file containing function prototypes
|
||||
# (like syscall_solaris.go) and generates system call bodies.
|
||||
# The prototypes are marked by lines beginning with "//sys"
|
||||
# and read like func declarations if //sys is replaced by func, but:
|
||||
# * The parameter lists must give a name for each argument.
|
||||
# This includes return parameters.
|
||||
# * The parameter lists must give a type for each argument:
|
||||
# the (x, y, z int) shorthand is not allowed.
|
||||
# * If the return parameter is an error number, it must be named err.
|
||||
# * If go func name needs to be different than its libc name,
|
||||
# * or the function is not in libc, name could be specified
|
||||
# * at the end, after "=" sign, like
|
||||
# //sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) = libsocket.getsockopt
|
||||
|
||||
use strict;
|
||||
|
||||
my $cmdline = "mksyscall_solaris.pl " . join(' ', @ARGV);
|
||||
my $errors = 0;
|
||||
my $_32bit = "";
|
||||
|
||||
binmode STDOUT;
|
||||
|
||||
if($ARGV[0] eq "-b32") {
|
||||
$_32bit = "big-endian";
|
||||
shift;
|
||||
} elsif($ARGV[0] eq "-l32") {
|
||||
$_32bit = "little-endian";
|
||||
shift;
|
||||
}
|
||||
|
||||
if($ARGV[0] =~ /^-/) {
|
||||
print STDERR "usage: mksyscall_solaris.pl [-b32 | -l32] [file ...]\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
sub parseparamlist($) {
|
||||
my ($list) = @_;
|
||||
$list =~ s/^\s*//;
|
||||
$list =~ s/\s*$//;
|
||||
if($list eq "") {
|
||||
return ();
|
||||
}
|
||||
return split(/\s*,\s*/, $list);
|
||||
}
|
||||
|
||||
sub parseparam($) {
|
||||
my ($p) = @_;
|
||||
if($p !~ /^(\S*) (\S*)$/) {
|
||||
print STDERR "$ARGV:$.: malformed parameter: $p\n";
|
||||
$errors = 1;
|
||||
return ("xx", "int");
|
||||
}
|
||||
return ($1, $2);
|
||||
}
|
||||
|
||||
my $package = "";
|
||||
my $text = "";
|
||||
my $vars = "";
|
||||
my $mods = "";
|
||||
my $modnames = "";
|
||||
while(<>) {
|
||||
chomp;
|
||||
s/\s+/ /g;
|
||||
s/^\s+//;
|
||||
s/\s+$//;
|
||||
$package = $1 if !$package && /^package (\S+)$/;
|
||||
my $nonblock = /^\/\/sysnb /;
|
||||
next if !/^\/\/sys / && !$nonblock;
|
||||
|
||||
my $syscalldot = "";
|
||||
$syscalldot = "syscall." if $package ne "syscall";
|
||||
|
||||
# Line must be of the form
|
||||
# func Open(path string, mode int, perm int) (fd int, err error)
|
||||
# Split into name, in params, out params.
|
||||
if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$/) {
|
||||
print STDERR "$ARGV:$.: malformed //sys declaration\n";
|
||||
$errors = 1;
|
||||
next;
|
||||
}
|
||||
my ($nb, $func, $in, $out, $modname, $sysname) = ($1, $2, $3, $4, $5, $6);
|
||||
|
||||
# Split argument lists on comma.
|
||||
my @in = parseparamlist($in);
|
||||
my @out = parseparamlist($out);
|
||||
|
||||
# So file name.
|
||||
if($modname eq "") {
|
||||
$modname = "libc";
|
||||
}
|
||||
my $modvname = "mod$modname";
|
||||
if($modnames !~ /$modname/) {
|
||||
$modnames .= ".$modname";
|
||||
$mods .= "\t$modvname = ${syscalldot}newLazySO(\"$modname.so\")\n";
|
||||
}
|
||||
|
||||
# System call name.
|
||||
if($sysname eq "") {
|
||||
$sysname = "$func";
|
||||
}
|
||||
|
||||
# System call pointer variable name.
|
||||
my $sysvarname = "proc$sysname";
|
||||
|
||||
my $strconvfunc = "BytePtrFromString";
|
||||
my $strconvtype = "*byte";
|
||||
|
||||
# Library proc address variable.
|
||||
$sysname =~ y/A-Z/a-z/; # All libc functions are lowercase.
|
||||
$vars .= "\t$sysvarname = $modvname.NewProc(\"$sysname\")\n";
|
||||
|
||||
# Go function header.
|
||||
$out = join(', ', @out);
|
||||
if($out ne "") {
|
||||
$out = " ($out)";
|
||||
}
|
||||
if($text ne "") {
|
||||
$text .= "\n"
|
||||
}
|
||||
$text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out;
|
||||
|
||||
# Check if err return available
|
||||
my $errvar = "";
|
||||
foreach my $p (@out) {
|
||||
my ($name, $type) = parseparam($p);
|
||||
if($type eq "error") {
|
||||
$errvar = $name;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
# Prepare arguments to Syscall.
|
||||
my @args = ();
|
||||
my $n = 0;
|
||||
my @pin= ();
|
||||
foreach my $p (@in) {
|
||||
my ($name, $type) = parseparam($p);
|
||||
if($type =~ /^\*/) {
|
||||
push @args, "uintptr(unsafe.Pointer($name))";
|
||||
} elsif($type eq "string" && $errvar ne "") {
|
||||
$text .= "\tvar _p$n $strconvtype\n";
|
||||
$text .= "\t_p$n, $errvar = $strconvfunc($name)\n";
|
||||
$text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n";
|
||||
push @args, "uintptr(unsafe.Pointer(_p$n))";
|
||||
$n++;
|
||||
} elsif($type eq "string") {
|
||||
print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n";
|
||||
$text .= "\tvar _p$n $strconvtype\n";
|
||||
$text .= "\t_p$n, _ = $strconvfunc($name)\n";
|
||||
push @args, "uintptr(unsafe.Pointer(_p$n))";
|
||||
$n++;
|
||||
} elsif($type =~ /^\[\](.*)/) {
|
||||
# Convert slice into pointer, length.
|
||||
# Have to be careful not to take address of &a[0] if len == 0:
|
||||
# pass nil in that case.
|
||||
$text .= "\tvar _p$n *$1\n";
|
||||
$text .= "\tif len($name) > 0 {\n\t\t_p$n = \&$name\[0]\n\t}\n";
|
||||
push @args, "uintptr(unsafe.Pointer(_p$n))", "uintptr(len($name))";
|
||||
$n++;
|
||||
} elsif($type eq "int64" && $_32bit ne "") {
|
||||
if($_32bit eq "big-endian") {
|
||||
push @args, "uintptr($name >> 32)", "uintptr($name)";
|
||||
} else {
|
||||
push @args, "uintptr($name)", "uintptr($name >> 32)";
|
||||
}
|
||||
} elsif($type eq "bool") {
|
||||
$text .= "\tvar _p$n uint32\n";
|
||||
$text .= "\tif $name {\n\t\t_p$n = 1\n\t} else {\n\t\t_p$n = 0\n\t}\n";
|
||||
push @args, "uintptr(_p$n)";
|
||||
$n++;
|
||||
} else {
|
||||
push @args, "uintptr($name)";
|
||||
}
|
||||
push @pin, sprintf "\"%s=\", %s, ", $name, $name;
|
||||
}
|
||||
my $nargs = @args;
|
||||
|
||||
# Determine which form to use; pad args with zeros.
|
||||
my $asm = "${syscalldot}sysvicall6";
|
||||
if ($nonblock) {
|
||||
$asm = "${syscalldot}rawSysvicall6";
|
||||
}
|
||||
if(@args <= 6) {
|
||||
while(@args < 6) {
|
||||
push @args, "0";
|
||||
}
|
||||
} else {
|
||||
print STDERR "$ARGV:$.: too many arguments to system call\n";
|
||||
}
|
||||
|
||||
# Actual call.
|
||||
my $args = join(', ', @args);
|
||||
my $call = "$asm($sysvarname.Addr(), $nargs, $args)";
|
||||
|
||||
# Assign return values.
|
||||
my $body = "";
|
||||
my $failexpr = "";
|
||||
my @ret = ("_", "_", "_");
|
||||
my @pout= ();
|
||||
my $do_errno = 0;
|
||||
for(my $i=0; $i<@out; $i++) {
|
||||
my $p = $out[$i];
|
||||
my ($name, $type) = parseparam($p);
|
||||
my $reg = "";
|
||||
if($name eq "err") {
|
||||
$reg = "e1";
|
||||
$ret[2] = $reg;
|
||||
$do_errno = 1;
|
||||
} else {
|
||||
$reg = sprintf("r%d", $i);
|
||||
$ret[$i] = $reg;
|
||||
}
|
||||
if($type eq "bool") {
|
||||
$reg = "$reg != 0";
|
||||
}
|
||||
if($type eq "int64" && $_32bit ne "") {
|
||||
# 64-bit number in r1:r0 or r0:r1.
|
||||
if($i+2 > @out) {
|
||||
print STDERR "$ARGV:$.: not enough registers for int64 return\n";
|
||||
}
|
||||
if($_32bit eq "big-endian") {
|
||||
$reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i, $i+1);
|
||||
} else {
|
||||
$reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i+1, $i);
|
||||
}
|
||||
$ret[$i] = sprintf("r%d", $i);
|
||||
$ret[$i+1] = sprintf("r%d", $i+1);
|
||||
}
|
||||
if($reg ne "e1") {
|
||||
$body .= "\t$name = $type($reg)\n";
|
||||
}
|
||||
}
|
||||
if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") {
|
||||
$text .= "\t$call\n";
|
||||
} else {
|
||||
$text .= "\t$ret[0], $ret[1], $ret[2] := $call\n";
|
||||
}
|
||||
$text .= $body;
|
||||
|
||||
if ($do_errno) {
|
||||
$text .= "\tif e1 != 0 {\n";
|
||||
$text .= "\t\terr = e1\n";
|
||||
$text .= "\t}\n";
|
||||
}
|
||||
$text .= "\treturn\n";
|
||||
$text .= "}\n";
|
||||
}
|
||||
|
||||
if($errors) {
|
||||
exit 1;
|
||||
}
|
||||
|
||||
print <<EOF;
|
||||
// $cmdline
|
||||
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
|
||||
|
||||
package $package
|
||||
|
||||
import "unsafe"
|
||||
EOF
|
||||
|
||||
print "import \"syscall\"\n" if $package ne "syscall";
|
||||
|
||||
print <<EOF;
|
||||
|
||||
var (
|
||||
$mods
|
||||
$vars
|
||||
)
|
||||
|
||||
$text
|
||||
|
||||
EOF
|
||||
exit 0;
|
||||
257
unix/mksysctl_openbsd.pl
Executable file
257
unix/mksysctl_openbsd.pl
Executable file
@@ -0,0 +1,257 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
# Copyright 2011 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.
|
||||
|
||||
#
|
||||
# Parse the header files for OpenBSD and generate a Go usable sysctl MIB.
|
||||
#
|
||||
# Build a MIB with each entry being an array containing the level, type and
|
||||
# a hash that will contain additional entries if the current entry is a node.
|
||||
# We then walk this MIB and create a flattened sysctl name to OID hash.
|
||||
#
|
||||
|
||||
use strict;
|
||||
|
||||
my $debug = 0;
|
||||
my %ctls = ();
|
||||
|
||||
my @headers = qw (
|
||||
sys/sysctl.h
|
||||
sys/socket.h
|
||||
sys/tty.h
|
||||
sys/malloc.h
|
||||
sys/mount.h
|
||||
sys/namei.h
|
||||
sys/sem.h
|
||||
sys/shm.h
|
||||
sys/vmmeter.h
|
||||
uvm/uvm_param.h
|
||||
uvm/uvm_swap_encrypt.h
|
||||
ddb/db_var.h
|
||||
net/if.h
|
||||
net/if_pfsync.h
|
||||
net/pipex.h
|
||||
netinet/in.h
|
||||
netinet/icmp_var.h
|
||||
netinet/igmp_var.h
|
||||
netinet/ip_ah.h
|
||||
netinet/ip_carp.h
|
||||
netinet/ip_divert.h
|
||||
netinet/ip_esp.h
|
||||
netinet/ip_ether.h
|
||||
netinet/ip_gre.h
|
||||
netinet/ip_ipcomp.h
|
||||
netinet/ip_ipip.h
|
||||
netinet/pim_var.h
|
||||
netinet/tcp_var.h
|
||||
netinet/udp_var.h
|
||||
netinet6/in6.h
|
||||
netinet6/ip6_divert.h
|
||||
netinet6/pim6_var.h
|
||||
netinet/icmp6.h
|
||||
netmpls/mpls.h
|
||||
);
|
||||
|
||||
my @ctls = qw (
|
||||
kern
|
||||
vm
|
||||
fs
|
||||
net
|
||||
#debug # Special handling required
|
||||
hw
|
||||
#machdep # Arch specific
|
||||
user
|
||||
ddb
|
||||
#vfs # Special handling required
|
||||
fs.posix
|
||||
kern.forkstat
|
||||
kern.intrcnt
|
||||
kern.malloc
|
||||
kern.nchstats
|
||||
kern.seminfo
|
||||
kern.shminfo
|
||||
kern.timecounter
|
||||
kern.tty
|
||||
kern.watchdog
|
||||
net.bpf
|
||||
net.ifq
|
||||
net.inet
|
||||
net.inet.ah
|
||||
net.inet.carp
|
||||
net.inet.divert
|
||||
net.inet.esp
|
||||
net.inet.etherip
|
||||
net.inet.gre
|
||||
net.inet.icmp
|
||||
net.inet.igmp
|
||||
net.inet.ip
|
||||
net.inet.ip.ifq
|
||||
net.inet.ipcomp
|
||||
net.inet.ipip
|
||||
net.inet.mobileip
|
||||
net.inet.pfsync
|
||||
net.inet.pim
|
||||
net.inet.tcp
|
||||
net.inet.udp
|
||||
net.inet6
|
||||
net.inet6.divert
|
||||
net.inet6.ip6
|
||||
net.inet6.icmp6
|
||||
net.inet6.pim6
|
||||
net.inet6.tcp6
|
||||
net.inet6.udp6
|
||||
net.mpls
|
||||
net.mpls.ifq
|
||||
net.key
|
||||
net.pflow
|
||||
net.pfsync
|
||||
net.pipex
|
||||
net.rt
|
||||
vm.swapencrypt
|
||||
#vfsgenctl # Special handling required
|
||||
);
|
||||
|
||||
# Node name "fixups"
|
||||
my %ctl_map = (
|
||||
"ipproto" => "net.inet",
|
||||
"net.inet.ipproto" => "net.inet",
|
||||
"net.inet6.ipv6proto" => "net.inet6",
|
||||
"net.inet6.ipv6" => "net.inet6.ip6",
|
||||
"net.inet.icmpv6" => "net.inet6.icmp6",
|
||||
"net.inet6.divert6" => "net.inet6.divert",
|
||||
"net.inet6.tcp6" => "net.inet.tcp",
|
||||
"net.inet6.udp6" => "net.inet.udp",
|
||||
"mpls" => "net.mpls",
|
||||
"swpenc" => "vm.swapencrypt"
|
||||
);
|
||||
|
||||
# Node mappings
|
||||
my %node_map = (
|
||||
"net.inet.ip.ifq" => "net.ifq",
|
||||
"net.inet.pfsync" => "net.pfsync",
|
||||
"net.mpls.ifq" => "net.ifq"
|
||||
);
|
||||
|
||||
my $ctlname;
|
||||
my %mib = ();
|
||||
my %sysctl = ();
|
||||
my $node;
|
||||
|
||||
sub debug() {
|
||||
print STDERR "$_[0]\n" if $debug;
|
||||
}
|
||||
|
||||
# Walk the MIB and build a sysctl name to OID mapping.
|
||||
sub build_sysctl() {
|
||||
my ($node, $name, $oid) = @_;
|
||||
my %node = %{$node};
|
||||
my @oid = @{$oid};
|
||||
|
||||
foreach my $key (sort keys %node) {
|
||||
my @node = @{$node{$key}};
|
||||
my $nodename = $name.($name ne '' ? '.' : '').$key;
|
||||
my @nodeoid = (@oid, $node[0]);
|
||||
if ($node[1] eq 'CTLTYPE_NODE') {
|
||||
if (exists $node_map{$nodename}) {
|
||||
$node = \%mib;
|
||||
$ctlname = $node_map{$nodename};
|
||||
foreach my $part (split /\./, $ctlname) {
|
||||
$node = \%{@{$$node{$part}}[2]};
|
||||
}
|
||||
} else {
|
||||
$node = $node[2];
|
||||
}
|
||||
&build_sysctl($node, $nodename, \@nodeoid);
|
||||
} elsif ($node[1] ne '') {
|
||||
$sysctl{$nodename} = \@nodeoid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $ctl (@ctls) {
|
||||
$ctls{$ctl} = $ctl;
|
||||
}
|
||||
|
||||
# Build MIB
|
||||
foreach my $header (@headers) {
|
||||
&debug("Processing $header...");
|
||||
open HEADER, "/usr/include/$header" ||
|
||||
print STDERR "Failed to open $header\n";
|
||||
while (<HEADER>) {
|
||||
if ($_ =~ /^#define\s+(CTL_NAMES)\s+{/ ||
|
||||
$_ =~ /^#define\s+(CTL_(.*)_NAMES)\s+{/ ||
|
||||
$_ =~ /^#define\s+((.*)CTL_NAMES)\s+{/) {
|
||||
if ($1 eq 'CTL_NAMES') {
|
||||
# Top level.
|
||||
$node = \%mib;
|
||||
} else {
|
||||
# Node.
|
||||
my $nodename = lc($2);
|
||||
if ($header =~ /^netinet\//) {
|
||||
$ctlname = "net.inet.$nodename";
|
||||
} elsif ($header =~ /^netinet6\//) {
|
||||
$ctlname = "net.inet6.$nodename";
|
||||
} elsif ($header =~ /^net\//) {
|
||||
$ctlname = "net.$nodename";
|
||||
} else {
|
||||
$ctlname = "$nodename";
|
||||
$ctlname =~ s/^(fs|net|kern)_/$1\./;
|
||||
}
|
||||
if (exists $ctl_map{$ctlname}) {
|
||||
$ctlname = $ctl_map{$ctlname};
|
||||
}
|
||||
if (not exists $ctls{$ctlname}) {
|
||||
&debug("Ignoring $ctlname...");
|
||||
next;
|
||||
}
|
||||
|
||||
# Walk down from the top of the MIB.
|
||||
$node = \%mib;
|
||||
foreach my $part (split /\./, $ctlname) {
|
||||
if (not exists $$node{$part}) {
|
||||
&debug("Missing node $part");
|
||||
$$node{$part} = [ 0, '', {} ];
|
||||
}
|
||||
$node = \%{@{$$node{$part}}[2]};
|
||||
}
|
||||
}
|
||||
|
||||
# Populate current node with entries.
|
||||
my $i = -1;
|
||||
while (defined($_) && $_ !~ /^}/) {
|
||||
$_ = <HEADER>;
|
||||
$i++ if $_ =~ /{.*}/;
|
||||
next if $_ !~ /{\s+"(\w+)",\s+(CTLTYPE_[A-Z]+)\s+}/;
|
||||
$$node{$1} = [ $i, $2, {} ];
|
||||
}
|
||||
}
|
||||
}
|
||||
close HEADER;
|
||||
}
|
||||
|
||||
&build_sysctl(\%mib, "", []);
|
||||
|
||||
print <<EOF;
|
||||
// mksysctl_openbsd.pl
|
||||
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
|
||||
|
||||
package syscall;
|
||||
|
||||
type mibentry struct {
|
||||
ctlname string
|
||||
ctloid []_C_int
|
||||
}
|
||||
|
||||
var sysctlMib = []mibentry {
|
||||
EOF
|
||||
|
||||
foreach my $name (sort keys %sysctl) {
|
||||
my @oid = @{$sysctl{$name}};
|
||||
print "\t{ \"$name\", []_C_int{ ", join(', ', @oid), " } }, \n";
|
||||
}
|
||||
|
||||
print <<EOF;
|
||||
}
|
||||
EOF
|
||||
32
unix/mksysnum_darwin.pl
Executable file
32
unix/mksysnum_darwin.pl
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env perl
|
||||
# Copyright 2009 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.
|
||||
#
|
||||
# Generate system call table for Darwin from sys/syscall.h
|
||||
|
||||
use strict;
|
||||
|
||||
my $command = "mksysnum_darwin.pl " . join(' ', @ARGV);
|
||||
|
||||
print <<EOF;
|
||||
// $command
|
||||
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
|
||||
|
||||
package syscall
|
||||
|
||||
const (
|
||||
EOF
|
||||
|
||||
while(<>){
|
||||
if(/^#define\s+SYS_(\w+)\s+([0-9]+)/){
|
||||
my $name = $1;
|
||||
my $num = $2;
|
||||
$name =~ y/a-z/A-Z/;
|
||||
print " SYS_$name = $num;"
|
||||
}
|
||||
}
|
||||
|
||||
print <<EOF;
|
||||
)
|
||||
EOF
|
||||
43
unix/mksysnum_dragonfly.pl
Executable file
43
unix/mksysnum_dragonfly.pl
Executable file
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env perl
|
||||
# Copyright 2009 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.
|
||||
#
|
||||
# Generate system call table for DragonFly from master list
|
||||
# (for example, /usr/src/sys/kern/syscalls.master).
|
||||
|
||||
use strict;
|
||||
|
||||
my $command = "mksysnum_dragonfly.pl " . join(' ', @ARGV);
|
||||
|
||||
print <<EOF;
|
||||
// $command
|
||||
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
|
||||
|
||||
package syscall
|
||||
|
||||
const (
|
||||
EOF
|
||||
|
||||
while(<>){
|
||||
if(/^([0-9]+)\s+STD\s+({ \S+\s+(\w+).*)$/){
|
||||
my $num = $1;
|
||||
my $proto = $2;
|
||||
my $name = "SYS_$3";
|
||||
$name =~ y/a-z/A-Z/;
|
||||
|
||||
# There are multiple entries for enosys and nosys, so comment them out.
|
||||
if($name =~ /^SYS_E?NOSYS$/){
|
||||
$name = "// $name";
|
||||
}
|
||||
if($name eq 'SYS_SYS_EXIT'){
|
||||
$name = 'SYS_EXIT';
|
||||
}
|
||||
|
||||
print " $name = $num; // $proto\n";
|
||||
}
|
||||
}
|
||||
|
||||
print <<EOF;
|
||||
)
|
||||
EOF
|
||||
56
unix/mksysnum_freebsd.pl
Executable file
56
unix/mksysnum_freebsd.pl
Executable file
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env perl
|
||||
# Copyright 2009 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.
|
||||
#
|
||||
# Generate system call table for FreeBSD from master list
|
||||
# (for example, /usr/src/sys/kern/syscalls.master).
|
||||
|
||||
use strict;
|
||||
|
||||
my $command = "mksysnum_freebsd.pl " . join(' ', @ARGV);
|
||||
|
||||
print <<EOF;
|
||||
// $command
|
||||
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
|
||||
|
||||
package syscall
|
||||
|
||||
const (
|
||||
EOF
|
||||
|
||||
while(<>){
|
||||
if(/^([0-9]+)\s+\S+\s+STD\s+({ \S+\s+(\w+).*)$/){
|
||||
my $num = $1;
|
||||
my $proto = $2;
|
||||
my $name = "SYS_$3";
|
||||
$name =~ y/a-z/A-Z/;
|
||||
|
||||
# There are multiple entries for enosys and nosys, so comment them out.
|
||||
if($name =~ /^SYS_E?NOSYS$/){
|
||||
$name = "// $name";
|
||||
}
|
||||
if($name eq 'SYS_SYS_EXIT'){
|
||||
$name = 'SYS_EXIT';
|
||||
}
|
||||
if($name =~ /^SYS_CAP_+/ || $name =~ /^SYS___CAP_+/){
|
||||
next
|
||||
}
|
||||
|
||||
print " $name = $num; // $proto\n";
|
||||
|
||||
# We keep Capsicum syscall numbers for FreeBSD
|
||||
# 9-STABLE here because we are not sure whether they
|
||||
# are mature and stable.
|
||||
if($num == 513){
|
||||
print " SYS_CAP_NEW = 514 // { int cap_new(int fd, uint64_t rights); }\n";
|
||||
print " SYS_CAP_GETRIGHTS = 515 // { int cap_getrights(int fd, \\\n";
|
||||
print " SYS_CAP_ENTER = 516 // { int cap_enter(void); }\n";
|
||||
print " SYS_CAP_GETMODE = 517 // { int cap_getmode(u_int *modep); }\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print <<EOF;
|
||||
)
|
||||
EOF
|
||||
38
unix/mksysnum_linux.pl
Executable file
38
unix/mksysnum_linux.pl
Executable file
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env perl
|
||||
# Copyright 2009 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.
|
||||
|
||||
use strict;
|
||||
|
||||
my $command = "mksysnum_linux.pl ". join(' ', @ARGV);
|
||||
|
||||
print <<EOF;
|
||||
// $command
|
||||
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
|
||||
|
||||
package syscall
|
||||
|
||||
const(
|
||||
EOF
|
||||
|
||||
sub fmt {
|
||||
my ($name, $num) = @_;
|
||||
$name =~ y/a-z/A-Z/;
|
||||
print " SYS_$name = $num;\n";
|
||||
}
|
||||
|
||||
my $prev;
|
||||
while(<>){
|
||||
if(/^#define __NR_(\w+)\s+([0-9]+)/){
|
||||
$prev = $2;
|
||||
fmt($1, $2);
|
||||
}
|
||||
elsif(/^#define __NR_(\w+)\s+\(\w+\+\s*([0-9]+)\)/){
|
||||
fmt($1, $prev+$2)
|
||||
}
|
||||
}
|
||||
|
||||
print <<EOF;
|
||||
)
|
||||
EOF
|
||||
51
unix/mksysnum_netbsd.pl
Executable file
51
unix/mksysnum_netbsd.pl
Executable file
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env perl
|
||||
# Copyright 2009 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.
|
||||
#
|
||||
# Generate system call table for OpenBSD from master list
|
||||
# (for example, /usr/src/sys/kern/syscalls.master).
|
||||
|
||||
use strict;
|
||||
|
||||
my $command = "mksysnum_netbsd.pl " . join(' ', @ARGV);
|
||||
|
||||
print <<EOF;
|
||||
// $command
|
||||
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
|
||||
|
||||
package syscall
|
||||
|
||||
const (
|
||||
EOF
|
||||
|
||||
my $line = '';
|
||||
while(<>){
|
||||
if($line =~ /^(.*)\\$/) {
|
||||
# Handle continuation
|
||||
$line = $1;
|
||||
$_ =~ s/^\s+//;
|
||||
$line .= $_;
|
||||
} else {
|
||||
# New line
|
||||
$line = $_;
|
||||
}
|
||||
next if $line =~ /\\$/;
|
||||
if($line =~ /^([0-9]+)\s+((STD)|(NOERR))\s+(RUMP\s+)?({\s+\S+\s*\*?\s*\|(\S+)\|(\S*)\|(\w+).*\s+})(\s+(\S+))?$/) {
|
||||
my $num = $1;
|
||||
my $proto = $6;
|
||||
my $compat = $8;
|
||||
my $name = "$7_$9";
|
||||
|
||||
$name = "$7_$11" if $11 ne '';
|
||||
$name =~ y/a-z/A-Z/;
|
||||
|
||||
if($compat eq '' || $compat eq '30' || $compat eq '50') {
|
||||
print " $name = $num; // $proto\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print <<EOF;
|
||||
)
|
||||
EOF
|
||||
43
unix/mksysnum_openbsd.pl
Executable file
43
unix/mksysnum_openbsd.pl
Executable file
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env perl
|
||||
# Copyright 2009 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.
|
||||
#
|
||||
# Generate system call table for OpenBSD from master list
|
||||
# (for example, /usr/src/sys/kern/syscalls.master).
|
||||
|
||||
use strict;
|
||||
|
||||
my $command = "mksysnum_openbsd.pl " . join(' ', @ARGV);
|
||||
|
||||
print <<EOF;
|
||||
// $command
|
||||
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
|
||||
|
||||
package syscall
|
||||
|
||||
const (
|
||||
EOF
|
||||
|
||||
while(<>){
|
||||
if(/^([0-9]+)\s+STD\s+(NOLOCK\s+)?({ \S+\s+\*?(\w+).*)$/){
|
||||
my $num = $1;
|
||||
my $proto = $3;
|
||||
my $name = $4;
|
||||
$name =~ y/a-z/A-Z/;
|
||||
|
||||
# There are multiple entries for enosys and nosys, so comment them out.
|
||||
if($name =~ /^SYS_E?NOSYS$/){
|
||||
$name = "// $name";
|
||||
}
|
||||
if($name eq 'SYS_SYS_EXIT'){
|
||||
$name = 'SYS_EXIT';
|
||||
}
|
||||
|
||||
print " $name = $num; // $proto\n";
|
||||
}
|
||||
}
|
||||
|
||||
print <<EOF;
|
||||
)
|
||||
EOF
|
||||
22
unix/mmap_unix_test.go
Normal file
22
unix/mmap_unix_test.go
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright 2014 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 darwin dragonfly freebsd linux netbsd openbsd
|
||||
|
||||
package syscall_test
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMmap(t *testing.T) {
|
||||
b, err := syscall.Mmap(-1, 0, syscall.Getpagesize(), syscall.PROT_NONE, syscall.MAP_ANON|syscall.MAP_PRIVATE)
|
||||
if err != nil {
|
||||
t.Fatalf("Mmap: %v", err)
|
||||
}
|
||||
if err := syscall.Munmap(b); err != nil {
|
||||
t.Fatalf("Munmap: %v", err)
|
||||
}
|
||||
}
|
||||
912
unix/net_nacl.go
Normal file
912
unix/net_nacl.go
Normal file
@@ -0,0 +1,912 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
// A simulated network for use within NaCl.
|
||||
// The simulation is not particularly tied to NaCl,
|
||||
// but other systems have real networks.
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Interface to timers implemented in package runtime.
|
||||
// Must be in sync with ../runtime/runtime.h:/^struct.Timer$
|
||||
// Really for use by package time, but we cannot import time here.
|
||||
|
||||
type runtimeTimer struct {
|
||||
i int32
|
||||
when int64
|
||||
period int64
|
||||
f func(int64, interface{}) // NOTE: must not be closure
|
||||
arg interface{}
|
||||
}
|
||||
|
||||
func startTimer(*runtimeTimer)
|
||||
func stopTimer(*runtimeTimer) bool
|
||||
|
||||
type timer struct {
|
||||
expired bool
|
||||
q *queue
|
||||
r runtimeTimer
|
||||
}
|
||||
|
||||
func (t *timer) start(q *queue, deadline int64) {
|
||||
if deadline == 0 {
|
||||
return
|
||||
}
|
||||
t.q = q
|
||||
t.r.when = deadline
|
||||
t.r.f = timerExpired
|
||||
t.r.arg = t
|
||||
startTimer(&t.r)
|
||||
}
|
||||
|
||||
func (t *timer) stop() {
|
||||
stopTimer(&t.r)
|
||||
}
|
||||
|
||||
func timerExpired(now int64, i interface{}) {
|
||||
t := i.(*timer)
|
||||
go func() {
|
||||
t.q.Lock()
|
||||
defer t.q.Unlock()
|
||||
t.expired = true
|
||||
t.q.canRead.Broadcast()
|
||||
t.q.canWrite.Broadcast()
|
||||
}()
|
||||
}
|
||||
|
||||
// Network constants and data structures. These match the traditional values.
|
||||
|
||||
const (
|
||||
AF_UNSPEC = iota
|
||||
AF_UNIX
|
||||
AF_INET
|
||||
AF_INET6
|
||||
)
|
||||
|
||||
const (
|
||||
SHUT_RD = iota
|
||||
SHUT_WR
|
||||
SHUT_RDWR
|
||||
)
|
||||
|
||||
const (
|
||||
SOCK_STREAM = 1 + iota
|
||||
SOCK_DGRAM
|
||||
SOCK_RAW
|
||||
SOCK_SEQPACKET
|
||||
)
|
||||
|
||||
const (
|
||||
IPPROTO_IP = 0
|
||||
IPPROTO_IPV4 = 4
|
||||
IPPROTO_IPV6 = 0x29
|
||||
IPPROTO_TCP = 6
|
||||
IPPROTO_UDP = 0x11
|
||||
)
|
||||
|
||||
// Misc constants expected by package net but not supported.
|
||||
const (
|
||||
_ = iota
|
||||
SOL_SOCKET
|
||||
SO_TYPE
|
||||
NET_RT_IFLIST
|
||||
IFNAMSIZ
|
||||
IFF_UP
|
||||
IFF_BROADCAST
|
||||
IFF_LOOPBACK
|
||||
IFF_POINTOPOINT
|
||||
IFF_MULTICAST
|
||||
IPV6_V6ONLY
|
||||
SOMAXCONN
|
||||
F_DUPFD_CLOEXEC
|
||||
SO_BROADCAST
|
||||
SO_REUSEADDR
|
||||
SO_REUSEPORT
|
||||
SO_RCVBUF
|
||||
SO_SNDBUF
|
||||
SO_KEEPALIVE
|
||||
SO_LINGER
|
||||
SO_ERROR
|
||||
IP_PORTRANGE
|
||||
IP_PORTRANGE_DEFAULT
|
||||
IP_PORTRANGE_LOW
|
||||
IP_PORTRANGE_HIGH
|
||||
IP_MULTICAST_IF
|
||||
IP_MULTICAST_LOOP
|
||||
IP_ADD_MEMBERSHIP
|
||||
IPV6_PORTRANGE
|
||||
IPV6_PORTRANGE_DEFAULT
|
||||
IPV6_PORTRANGE_LOW
|
||||
IPV6_PORTRANGE_HIGH
|
||||
IPV6_MULTICAST_IF
|
||||
IPV6_MULTICAST_LOOP
|
||||
IPV6_JOIN_GROUP
|
||||
TCP_NODELAY
|
||||
TCP_KEEPINTVL
|
||||
TCP_KEEPIDLE
|
||||
|
||||
SYS_FCNTL = 500 // unsupported
|
||||
)
|
||||
|
||||
var SocketDisableIPv6 bool
|
||||
|
||||
// A Sockaddr is one of the SockaddrXxx structs.
|
||||
type Sockaddr interface {
|
||||
// copy returns a copy of the underlying data.
|
||||
copy() Sockaddr
|
||||
|
||||
// key returns the value of the underlying data,
|
||||
// for comparison as a map key.
|
||||
key() interface{}
|
||||
}
|
||||
|
||||
type SockaddrInet4 struct {
|
||||
Port int
|
||||
Addr [4]byte
|
||||
}
|
||||
|
||||
func (sa *SockaddrInet4) copy() Sockaddr {
|
||||
sa1 := *sa
|
||||
return &sa1
|
||||
}
|
||||
|
||||
func (sa *SockaddrInet4) key() interface{} { return *sa }
|
||||
|
||||
type SockaddrInet6 struct {
|
||||
Port int
|
||||
ZoneId uint32
|
||||
Addr [16]byte
|
||||
}
|
||||
|
||||
func (sa *SockaddrInet6) copy() Sockaddr {
|
||||
sa1 := *sa
|
||||
return &sa1
|
||||
}
|
||||
|
||||
func (sa *SockaddrInet6) key() interface{} { return *sa }
|
||||
|
||||
type SockaddrUnix struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (sa *SockaddrUnix) copy() Sockaddr {
|
||||
sa1 := *sa
|
||||
return &sa1
|
||||
}
|
||||
|
||||
func (sa *SockaddrUnix) key() interface{} { return *sa }
|
||||
|
||||
type SockaddrDatalink struct {
|
||||
Len uint8
|
||||
Family uint8
|
||||
Index uint16
|
||||
Type uint8
|
||||
Nlen uint8
|
||||
Alen uint8
|
||||
Slen uint8
|
||||
Data [12]int8
|
||||
}
|
||||
|
||||
func (sa *SockaddrDatalink) copy() Sockaddr {
|
||||
sa1 := *sa
|
||||
return &sa1
|
||||
}
|
||||
|
||||
func (sa *SockaddrDatalink) key() interface{} { return *sa }
|
||||
|
||||
// RoutingMessage represents a routing message.
|
||||
type RoutingMessage interface {
|
||||
unimplemented()
|
||||
}
|
||||
|
||||
type IPMreq struct {
|
||||
Multiaddr [4]byte /* in_addr */
|
||||
Interface [4]byte /* in_addr */
|
||||
}
|
||||
|
||||
type IPv6Mreq struct {
|
||||
Multiaddr [16]byte /* in6_addr */
|
||||
Interface uint32
|
||||
}
|
||||
|
||||
type Linger struct {
|
||||
Onoff int32
|
||||
Linger int32
|
||||
}
|
||||
|
||||
type ICMPv6Filter struct {
|
||||
Filt [8]uint32
|
||||
}
|
||||
|
||||
// A queue is the bookkeeping for a synchronized buffered queue.
|
||||
// We do not use channels because we need to be able to handle
|
||||
// writes after and during close, and because a chan byte would
|
||||
// require too many send and receive operations in real use.
|
||||
type queue struct {
|
||||
sync.Mutex
|
||||
canRead sync.Cond
|
||||
canWrite sync.Cond
|
||||
r int // total read index
|
||||
w int // total write index
|
||||
m int // index mask
|
||||
closed bool
|
||||
}
|
||||
|
||||
func (q *queue) init(size int) {
|
||||
if size&(size-1) != 0 {
|
||||
panic("invalid queue size - must be power of two")
|
||||
}
|
||||
q.canRead.L = &q.Mutex
|
||||
q.canWrite.L = &q.Mutex
|
||||
q.m = size - 1
|
||||
}
|
||||
|
||||
func past(deadline int64) bool {
|
||||
sec, nsec := now()
|
||||
return deadline > 0 && deadline < sec*1e9+int64(nsec)
|
||||
}
|
||||
|
||||
func (q *queue) waitRead(n int, deadline int64) (int, error) {
|
||||
if past(deadline) {
|
||||
return 0, EAGAIN
|
||||
}
|
||||
var t timer
|
||||
t.start(q, deadline)
|
||||
for q.w-q.r == 0 && !q.closed && !t.expired {
|
||||
q.canRead.Wait()
|
||||
}
|
||||
t.stop()
|
||||
m := q.w - q.r
|
||||
if m == 0 && t.expired {
|
||||
return 0, EAGAIN
|
||||
}
|
||||
if m > n {
|
||||
m = n
|
||||
q.canRead.Signal() // wake up next reader too
|
||||
}
|
||||
q.canWrite.Signal()
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (q *queue) waitWrite(n int, deadline int64) (int, error) {
|
||||
if past(deadline) {
|
||||
return 0, EAGAIN
|
||||
}
|
||||
var t timer
|
||||
t.start(q, deadline)
|
||||
for q.w-q.r > q.m && !q.closed && !t.expired {
|
||||
q.canWrite.Wait()
|
||||
}
|
||||
t.stop()
|
||||
m := q.m + 1 - (q.w - q.r)
|
||||
if m == 0 && t.expired {
|
||||
return 0, EAGAIN
|
||||
}
|
||||
if m == 0 {
|
||||
return 0, EAGAIN
|
||||
}
|
||||
if m > n {
|
||||
m = n
|
||||
q.canWrite.Signal() // wake up next writer too
|
||||
}
|
||||
q.canRead.Signal()
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (q *queue) close() {
|
||||
q.Lock()
|
||||
defer q.Unlock()
|
||||
q.closed = true
|
||||
q.canRead.Broadcast()
|
||||
q.canWrite.Broadcast()
|
||||
}
|
||||
|
||||
// A byteq is a byte queue.
|
||||
type byteq struct {
|
||||
queue
|
||||
data []byte
|
||||
}
|
||||
|
||||
func newByteq() *byteq {
|
||||
q := &byteq{
|
||||
data: make([]byte, 4096),
|
||||
}
|
||||
q.init(len(q.data))
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *byteq) read(b []byte, deadline int64) (int, error) {
|
||||
q.Lock()
|
||||
defer q.Unlock()
|
||||
n, err := q.waitRead(len(b), deadline)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
b = b[:n]
|
||||
for len(b) > 0 {
|
||||
m := copy(b, q.data[q.r&q.m:])
|
||||
q.r += m
|
||||
b = b[m:]
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (q *byteq) write(b []byte, deadline int64) (n int, err error) {
|
||||
q.Lock()
|
||||
defer q.Unlock()
|
||||
for n < len(b) {
|
||||
nn, err := q.waitWrite(len(b[n:]), deadline)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
bb := b[n : n+nn]
|
||||
n += nn
|
||||
for len(bb) > 0 {
|
||||
m := copy(q.data[q.w&q.m:], bb)
|
||||
q.w += m
|
||||
bb = bb[m:]
|
||||
}
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// A msgq is a queue of messages.
|
||||
type msgq struct {
|
||||
queue
|
||||
data []interface{}
|
||||
}
|
||||
|
||||
func newMsgq() *msgq {
|
||||
q := &msgq{
|
||||
data: make([]interface{}, 32),
|
||||
}
|
||||
q.init(len(q.data))
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *msgq) read(deadline int64) (interface{}, error) {
|
||||
q.Lock()
|
||||
defer q.Unlock()
|
||||
n, err := q.waitRead(1, deadline)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
m := q.data[q.r&q.m]
|
||||
q.r++
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (q *msgq) write(m interface{}, deadline int64) error {
|
||||
q.Lock()
|
||||
defer q.Unlock()
|
||||
_, err := q.waitWrite(1, deadline)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q.data[q.w&q.m] = m
|
||||
q.w++
|
||||
return nil
|
||||
}
|
||||
|
||||
// An addr is a sequence of bytes uniquely identifying a network address.
|
||||
// It is not human-readable.
|
||||
type addr string
|
||||
|
||||
// A conn is one side of a stream-based network connection.
|
||||
// That is, a stream-based network connection is a pair of cross-connected conns.
|
||||
type conn struct {
|
||||
rd *byteq
|
||||
wr *byteq
|
||||
local addr
|
||||
remote addr
|
||||
}
|
||||
|
||||
// A pktconn is one side of a packet-based network connection.
|
||||
// That is, a packet-based network connection is a pair of cross-connected pktconns.
|
||||
type pktconn struct {
|
||||
rd *msgq
|
||||
wr *msgq
|
||||
local addr
|
||||
remote addr
|
||||
}
|
||||
|
||||
// A listener accepts incoming stream-based network connections.
|
||||
type listener struct {
|
||||
rd *msgq
|
||||
local addr
|
||||
}
|
||||
|
||||
// A netFile is an open network file.
|
||||
type netFile struct {
|
||||
defaultFileImpl
|
||||
proto *netproto
|
||||
sotype int
|
||||
listener *msgq
|
||||
packet *msgq
|
||||
rd *byteq
|
||||
wr *byteq
|
||||
rddeadline int64
|
||||
wrdeadline int64
|
||||
addr Sockaddr
|
||||
raddr Sockaddr
|
||||
}
|
||||
|
||||
// A netAddr is a network address in the global listener map.
|
||||
// All the fields must have defined == operations.
|
||||
type netAddr struct {
|
||||
proto *netproto
|
||||
sotype int
|
||||
addr interface{}
|
||||
}
|
||||
|
||||
// net records the state of the network.
|
||||
// It maps a network address to the listener on that address.
|
||||
var net = struct {
|
||||
sync.Mutex
|
||||
listener map[netAddr]*netFile
|
||||
}{
|
||||
listener: make(map[netAddr]*netFile),
|
||||
}
|
||||
|
||||
// TODO(rsc): Some day, do a better job with port allocation.
|
||||
// For playground programs, incrementing is fine.
|
||||
var nextport = 2
|
||||
|
||||
// A netproto contains protocol-specific functionality
|
||||
// (one for AF_INET, one for AF_INET6 and so on).
|
||||
// It is a struct instead of an interface because the
|
||||
// implementation needs no state, and I expect to
|
||||
// add some data fields at some point.
|
||||
type netproto struct {
|
||||
bind func(*netFile, Sockaddr) error
|
||||
}
|
||||
|
||||
var netprotoAF_INET = &netproto{
|
||||
bind: func(f *netFile, sa Sockaddr) error {
|
||||
if sa == nil {
|
||||
f.addr = &SockaddrInet4{
|
||||
Port: nextport,
|
||||
Addr: [4]byte{127, 0, 0, 1},
|
||||
}
|
||||
nextport++
|
||||
return nil
|
||||
}
|
||||
addr, ok := sa.(*SockaddrInet4)
|
||||
if !ok {
|
||||
return EINVAL
|
||||
}
|
||||
addr = addr.copy().(*SockaddrInet4)
|
||||
if addr.Port == 0 {
|
||||
addr.Port = nextport
|
||||
nextport++
|
||||
}
|
||||
f.addr = addr
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var netprotos = map[int]*netproto{
|
||||
AF_INET: netprotoAF_INET,
|
||||
}
|
||||
|
||||
// These functions implement the usual BSD socket operations.
|
||||
|
||||
func (f *netFile) bind(sa Sockaddr) error {
|
||||
if f.addr != nil {
|
||||
return EISCONN
|
||||
}
|
||||
if err := f.proto.bind(f, sa); err != nil {
|
||||
return err
|
||||
}
|
||||
if f.sotype == SOCK_DGRAM {
|
||||
_, ok := net.listener[netAddr{f.proto, f.sotype, f.addr.key()}]
|
||||
if ok {
|
||||
f.addr = nil
|
||||
return EADDRINUSE
|
||||
}
|
||||
net.listener[netAddr{f.proto, f.sotype, f.addr.key()}] = f
|
||||
f.packet = newMsgq()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *netFile) listen(backlog int) error {
|
||||
net.Lock()
|
||||
defer net.Unlock()
|
||||
if f.listener != nil {
|
||||
return EINVAL
|
||||
}
|
||||
_, ok := net.listener[netAddr{f.proto, f.sotype, f.addr.key()}]
|
||||
if ok {
|
||||
return EADDRINUSE
|
||||
}
|
||||
net.listener[netAddr{f.proto, f.sotype, f.addr.key()}] = f
|
||||
f.listener = newMsgq()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *netFile) accept() (fd int, sa Sockaddr, err error) {
|
||||
msg, err := f.listener.read(f.readDeadline())
|
||||
if err != nil {
|
||||
return -1, nil, err
|
||||
}
|
||||
newf, ok := msg.(*netFile)
|
||||
if !ok {
|
||||
// must be eof
|
||||
return -1, nil, EAGAIN
|
||||
}
|
||||
return newFD(newf), newf.raddr.copy(), nil
|
||||
}
|
||||
|
||||
func (f *netFile) connect(sa Sockaddr) error {
|
||||
if past(f.writeDeadline()) {
|
||||
return EAGAIN
|
||||
}
|
||||
if f.addr == nil {
|
||||
if err := f.bind(nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
net.Lock()
|
||||
if sa == nil {
|
||||
net.Unlock()
|
||||
return EINVAL
|
||||
}
|
||||
sa = sa.copy()
|
||||
if f.raddr != nil {
|
||||
net.Unlock()
|
||||
return EISCONN
|
||||
}
|
||||
if f.sotype == SOCK_DGRAM {
|
||||
net.Unlock()
|
||||
f.raddr = sa
|
||||
return nil
|
||||
}
|
||||
if f.listener != nil {
|
||||
net.Unlock()
|
||||
return EISCONN
|
||||
}
|
||||
l, ok := net.listener[netAddr{f.proto, f.sotype, sa.key()}]
|
||||
if !ok {
|
||||
net.Unlock()
|
||||
return ECONNREFUSED
|
||||
}
|
||||
f.raddr = sa
|
||||
f.rd = newByteq()
|
||||
f.wr = newByteq()
|
||||
newf := &netFile{
|
||||
proto: f.proto,
|
||||
sotype: f.sotype,
|
||||
addr: f.raddr,
|
||||
raddr: f.addr,
|
||||
rd: f.wr,
|
||||
wr: f.rd,
|
||||
}
|
||||
net.Unlock()
|
||||
l.listener.write(newf, f.writeDeadline())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *netFile) read(b []byte) (int, error) {
|
||||
if f.rd == nil {
|
||||
if f.raddr != nil {
|
||||
n, _, err := f.recvfrom(b, 0)
|
||||
return n, err
|
||||
}
|
||||
return 0, ENOTCONN
|
||||
}
|
||||
return f.rd.read(b, f.readDeadline())
|
||||
}
|
||||
|
||||
func (f *netFile) write(b []byte) (int, error) {
|
||||
if f.wr == nil {
|
||||
if f.raddr != nil {
|
||||
err := f.sendto(b, 0, f.raddr)
|
||||
var n int
|
||||
if err == nil {
|
||||
n = len(b)
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
return 0, ENOTCONN
|
||||
}
|
||||
return f.wr.write(b, f.writeDeadline())
|
||||
}
|
||||
|
||||
type pktmsg struct {
|
||||
buf []byte
|
||||
addr Sockaddr
|
||||
}
|
||||
|
||||
func (f *netFile) recvfrom(p []byte, flags int) (n int, from Sockaddr, err error) {
|
||||
if f.sotype != SOCK_DGRAM {
|
||||
return 0, nil, EINVAL
|
||||
}
|
||||
if f.packet == nil {
|
||||
return 0, nil, ENOTCONN
|
||||
}
|
||||
msg1, err := f.packet.read(f.readDeadline())
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
msg, ok := msg1.(*pktmsg)
|
||||
if !ok {
|
||||
return 0, nil, EAGAIN
|
||||
}
|
||||
return copy(p, msg.buf), msg.addr, nil
|
||||
}
|
||||
|
||||
func (f *netFile) sendto(p []byte, flags int, to Sockaddr) error {
|
||||
if f.sotype != SOCK_DGRAM {
|
||||
return EINVAL
|
||||
}
|
||||
if f.packet == nil {
|
||||
if err := f.bind(nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
net.Lock()
|
||||
if to == nil {
|
||||
net.Unlock()
|
||||
return EINVAL
|
||||
}
|
||||
to = to.copy()
|
||||
l, ok := net.listener[netAddr{f.proto, f.sotype, to.key()}]
|
||||
if !ok || l.packet == nil {
|
||||
net.Unlock()
|
||||
return ECONNREFUSED
|
||||
}
|
||||
net.Unlock()
|
||||
msg := &pktmsg{
|
||||
buf: make([]byte, len(p)),
|
||||
addr: f.addr,
|
||||
}
|
||||
copy(msg.buf, p)
|
||||
l.packet.write(msg, f.writeDeadline())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *netFile) close() error {
|
||||
if f.listener != nil {
|
||||
f.listener.close()
|
||||
}
|
||||
if f.packet != nil {
|
||||
f.packet.close()
|
||||
}
|
||||
if f.rd != nil {
|
||||
f.rd.close()
|
||||
}
|
||||
if f.wr != nil {
|
||||
f.wr.close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func fdToNetFile(fd int) (*netFile, error) {
|
||||
f, err := fdToFile(fd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
impl := f.impl
|
||||
netf, ok := impl.(*netFile)
|
||||
if !ok {
|
||||
return nil, EINVAL
|
||||
}
|
||||
return netf, nil
|
||||
}
|
||||
|
||||
func Socket(proto, sotype, unused int) (fd int, err error) {
|
||||
p := netprotos[proto]
|
||||
if p == nil {
|
||||
return -1, EPROTONOSUPPORT
|
||||
}
|
||||
if sotype != SOCK_STREAM && sotype != SOCK_DGRAM {
|
||||
return -1, ESOCKTNOSUPPORT
|
||||
}
|
||||
f := &netFile{
|
||||
proto: p,
|
||||
sotype: sotype,
|
||||
}
|
||||
return newFD(f), nil
|
||||
}
|
||||
|
||||
func Bind(fd int, sa Sockaddr) error {
|
||||
f, err := fdToNetFile(fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return f.bind(sa)
|
||||
}
|
||||
|
||||
func StopIO(fd int) error {
|
||||
f, err := fdToNetFile(fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.close()
|
||||
return nil
|
||||
}
|
||||
|
||||
func Listen(fd int, backlog int) error {
|
||||
f, err := fdToNetFile(fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return f.listen(backlog)
|
||||
}
|
||||
|
||||
func Accept(fd int) (newfd int, sa Sockaddr, err error) {
|
||||
f, err := fdToNetFile(fd)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
return f.accept()
|
||||
}
|
||||
|
||||
func Getsockname(fd int) (sa Sockaddr, err error) {
|
||||
f, err := fdToNetFile(fd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if f.addr == nil {
|
||||
return nil, ENOTCONN
|
||||
}
|
||||
return f.addr.copy(), nil
|
||||
}
|
||||
|
||||
func Getpeername(fd int) (sa Sockaddr, err error) {
|
||||
f, err := fdToNetFile(fd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if f.raddr == nil {
|
||||
return nil, ENOTCONN
|
||||
}
|
||||
return f.raddr.copy(), nil
|
||||
}
|
||||
|
||||
func Connect(fd int, sa Sockaddr) error {
|
||||
f, err := fdToNetFile(fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return f.connect(sa)
|
||||
}
|
||||
|
||||
func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) {
|
||||
f, err := fdToNetFile(fd)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
return f.recvfrom(p, flags)
|
||||
}
|
||||
|
||||
func Sendto(fd int, p []byte, flags int, to Sockaddr) error {
|
||||
f, err := fdToNetFile(fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return f.sendto(p, flags, to)
|
||||
}
|
||||
|
||||
func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn, recvflags int, from Sockaddr, err error) {
|
||||
f, err := fdToNetFile(fd)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n, from, err = f.recvfrom(p, flags)
|
||||
return
|
||||
}
|
||||
|
||||
func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) error {
|
||||
_, err := SendmsgN(fd, p, oob, to, flags)
|
||||
return err
|
||||
}
|
||||
|
||||
func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
|
||||
f, err := fdToNetFile(fd)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
switch f.sotype {
|
||||
case SOCK_STREAM:
|
||||
n, err = f.write(p)
|
||||
case SOCK_DGRAM:
|
||||
n = len(p)
|
||||
err = f.sendto(p, flags, to)
|
||||
}
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func GetsockoptInt(fd, level, opt int) (value int, err error) {
|
||||
f, err := fdToNetFile(fd)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
switch {
|
||||
case level == SOL_SOCKET && opt == SO_TYPE:
|
||||
return f.sotype, nil
|
||||
}
|
||||
return 0, ENOTSUP
|
||||
}
|
||||
|
||||
func SetsockoptInt(fd, level, opt int, value int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetsockoptByte(fd, level, opt int, value byte) error {
|
||||
_, err := fdToNetFile(fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ENOTSUP
|
||||
}
|
||||
|
||||
func SetsockoptLinger(fd, level, opt int, l *Linger) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetReadDeadline(fd int, t int64) error {
|
||||
f, err := fdToNetFile(fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
atomic.StoreInt64(&f.rddeadline, t)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *netFile) readDeadline() int64 {
|
||||
return atomic.LoadInt64(&f.rddeadline)
|
||||
}
|
||||
|
||||
func SetWriteDeadline(fd int, t int64) error {
|
||||
f, err := fdToNetFile(fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
atomic.StoreInt64(&f.wrdeadline, t)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *netFile) writeDeadline() int64 {
|
||||
return atomic.LoadInt64(&f.wrdeadline)
|
||||
}
|
||||
|
||||
func Shutdown(fd int, how int) error {
|
||||
f, err := fdToNetFile(fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch how {
|
||||
case SHUT_RD:
|
||||
f.rd.close()
|
||||
case SHUT_WR:
|
||||
f.wr.close()
|
||||
case SHUT_RDWR:
|
||||
f.rd.close()
|
||||
f.wr.close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetsockoptICMPv6Filter(fd, level, opt int, filter *ICMPv6Filter) error { panic("SetsockoptICMPv") }
|
||||
func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) error { panic("SetsockoptIPMreq") }
|
||||
func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) error { panic("SetsockoptIPv") }
|
||||
func SetsockoptInet4Addr(fd, level, opt int, value [4]byte) error { panic("SetsockoptInet") }
|
||||
func SetsockoptString(fd, level, opt int, s string) error { panic("SetsockoptString") }
|
||||
func SetsockoptTimeval(fd, level, opt int, tv *Timeval) error { panic("SetsockoptTimeval") }
|
||||
func Socketpair(domain, typ, proto int) (fd [2]int, err error) { panic("Socketpair") }
|
||||
|
||||
func SetNonblock(fd int, nonblocking bool) error { return nil }
|
||||
178
unix/netlink_linux.go
Normal file
178
unix/netlink_linux.go
Normal file
@@ -0,0 +1,178 @@
|
||||
// Copyright 2011 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.
|
||||
|
||||
// Netlink sockets and messages
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// Round the length of a netlink message up to align it properly.
|
||||
func nlmAlignOf(msglen int) int {
|
||||
return (msglen + NLMSG_ALIGNTO - 1) & ^(NLMSG_ALIGNTO - 1)
|
||||
}
|
||||
|
||||
// Round the length of a netlink route attribute up to align it
|
||||
// properly.
|
||||
func rtaAlignOf(attrlen int) int {
|
||||
return (attrlen + RTA_ALIGNTO - 1) & ^(RTA_ALIGNTO - 1)
|
||||
}
|
||||
|
||||
// NetlinkRouteRequest represents a request message to receive routing
|
||||
// and link states from the kernel.
|
||||
type NetlinkRouteRequest struct {
|
||||
Header NlMsghdr
|
||||
Data RtGenmsg
|
||||
}
|
||||
|
||||
func (rr *NetlinkRouteRequest) toWireFormat() []byte {
|
||||
b := make([]byte, rr.Header.Len)
|
||||
*(*uint32)(unsafe.Pointer(&b[0:4][0])) = rr.Header.Len
|
||||
*(*uint16)(unsafe.Pointer(&b[4:6][0])) = rr.Header.Type
|
||||
*(*uint16)(unsafe.Pointer(&b[6:8][0])) = rr.Header.Flags
|
||||
*(*uint32)(unsafe.Pointer(&b[8:12][0])) = rr.Header.Seq
|
||||
*(*uint32)(unsafe.Pointer(&b[12:16][0])) = rr.Header.Pid
|
||||
b[16] = byte(rr.Data.Family)
|
||||
return b
|
||||
}
|
||||
|
||||
func newNetlinkRouteRequest(proto, seq, family int) []byte {
|
||||
rr := &NetlinkRouteRequest{}
|
||||
rr.Header.Len = uint32(NLMSG_HDRLEN + SizeofRtGenmsg)
|
||||
rr.Header.Type = uint16(proto)
|
||||
rr.Header.Flags = NLM_F_DUMP | NLM_F_REQUEST
|
||||
rr.Header.Seq = uint32(seq)
|
||||
rr.Data.Family = uint8(family)
|
||||
return rr.toWireFormat()
|
||||
}
|
||||
|
||||
// NetlinkRIB returns routing information base, as known as RIB, which
|
||||
// consists of network facility information, states and parameters.
|
||||
func NetlinkRIB(proto, family int) ([]byte, error) {
|
||||
s, err := Socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer Close(s)
|
||||
lsa := &SockaddrNetlink{Family: AF_NETLINK}
|
||||
if err := Bind(s, lsa); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wb := newNetlinkRouteRequest(proto, 1, family)
|
||||
if err := Sendto(s, wb, 0, lsa); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var tab []byte
|
||||
rbNew := make([]byte, Getpagesize())
|
||||
done:
|
||||
for {
|
||||
rb := rbNew
|
||||
nr, _, err := Recvfrom(s, rb, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if nr < NLMSG_HDRLEN {
|
||||
return nil, EINVAL
|
||||
}
|
||||
rb = rb[:nr]
|
||||
tab = append(tab, rb...)
|
||||
msgs, err := ParseNetlinkMessage(rb)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, m := range msgs {
|
||||
lsa, err := Getsockname(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch v := lsa.(type) {
|
||||
case *SockaddrNetlink:
|
||||
if m.Header.Seq != 1 || m.Header.Pid != v.Pid {
|
||||
return nil, EINVAL
|
||||
}
|
||||
default:
|
||||
return nil, EINVAL
|
||||
}
|
||||
if m.Header.Type == NLMSG_DONE {
|
||||
break done
|
||||
}
|
||||
if m.Header.Type == NLMSG_ERROR {
|
||||
return nil, EINVAL
|
||||
}
|
||||
}
|
||||
}
|
||||
return tab, nil
|
||||
}
|
||||
|
||||
// NetlinkMessage represents a netlink message.
|
||||
type NetlinkMessage struct {
|
||||
Header NlMsghdr
|
||||
Data []byte
|
||||
}
|
||||
|
||||
// ParseNetlinkMessage parses b as an array of netlink messages and
|
||||
// returns the slice containing the NetlinkMessage structures.
|
||||
func ParseNetlinkMessage(b []byte) ([]NetlinkMessage, error) {
|
||||
var msgs []NetlinkMessage
|
||||
for len(b) >= NLMSG_HDRLEN {
|
||||
h, dbuf, dlen, err := netlinkMessageHeaderAndData(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m := NetlinkMessage{Header: *h, Data: dbuf[:int(h.Len)-NLMSG_HDRLEN]}
|
||||
msgs = append(msgs, m)
|
||||
b = b[dlen:]
|
||||
}
|
||||
return msgs, nil
|
||||
}
|
||||
|
||||
func netlinkMessageHeaderAndData(b []byte) (*NlMsghdr, []byte, int, error) {
|
||||
h := (*NlMsghdr)(unsafe.Pointer(&b[0]))
|
||||
if int(h.Len) < NLMSG_HDRLEN || int(h.Len) > len(b) {
|
||||
return nil, nil, 0, EINVAL
|
||||
}
|
||||
return h, b[NLMSG_HDRLEN:], nlmAlignOf(int(h.Len)), nil
|
||||
}
|
||||
|
||||
// NetlinkRouteAttr represents a netlink route attribute.
|
||||
type NetlinkRouteAttr struct {
|
||||
Attr RtAttr
|
||||
Value []byte
|
||||
}
|
||||
|
||||
// ParseNetlinkRouteAttr parses m's payload as an array of netlink
|
||||
// route attributes and returns the slice containing the
|
||||
// NetlinkRouteAttr structures.
|
||||
func ParseNetlinkRouteAttr(m *NetlinkMessage) ([]NetlinkRouteAttr, error) {
|
||||
var b []byte
|
||||
switch m.Header.Type {
|
||||
case RTM_NEWLINK, RTM_DELLINK:
|
||||
b = m.Data[SizeofIfInfomsg:]
|
||||
case RTM_NEWADDR, RTM_DELADDR:
|
||||
b = m.Data[SizeofIfAddrmsg:]
|
||||
case RTM_NEWROUTE, RTM_DELROUTE:
|
||||
b = m.Data[SizeofRtMsg:]
|
||||
default:
|
||||
return nil, EINVAL
|
||||
}
|
||||
var attrs []NetlinkRouteAttr
|
||||
for len(b) >= SizeofRtAttr {
|
||||
a, vbuf, alen, err := netlinkRouteAttrAndValue(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ra := NetlinkRouteAttr{Attr: *a, Value: vbuf[:int(a.Len)-SizeofRtAttr]}
|
||||
attrs = append(attrs, ra)
|
||||
b = b[alen:]
|
||||
}
|
||||
return attrs, nil
|
||||
}
|
||||
|
||||
func netlinkRouteAttrAndValue(b []byte) (*RtAttr, []byte, int, error) {
|
||||
a := (*RtAttr)(unsafe.Pointer(&b[0]))
|
||||
if int(a.Len) < SizeofRtAttr || int(a.Len) > len(b) {
|
||||
return nil, nil, 0, EINVAL
|
||||
}
|
||||
return a, b[SizeofRtAttr:], rtaAlignOf(int(a.Len)), nil
|
||||
}
|
||||
30
unix/race.go
Normal file
30
unix/race.go
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright 2012 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 race
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const raceenabled = true
|
||||
|
||||
func raceAcquire(addr unsafe.Pointer) {
|
||||
runtime.RaceAcquire(addr)
|
||||
}
|
||||
|
||||
func raceReleaseMerge(addr unsafe.Pointer) {
|
||||
runtime.RaceReleaseMerge(addr)
|
||||
}
|
||||
|
||||
func raceReadRange(addr unsafe.Pointer, len int) {
|
||||
runtime.RaceReadRange(addr, len)
|
||||
}
|
||||
|
||||
func raceWriteRange(addr unsafe.Pointer, len int) {
|
||||
runtime.RaceWriteRange(addr, len)
|
||||
}
|
||||
25
unix/race0.go
Normal file
25
unix/race0.go
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2012 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 !race
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const raceenabled = false
|
||||
|
||||
func raceAcquire(addr unsafe.Pointer) {
|
||||
}
|
||||
|
||||
func raceReleaseMerge(addr unsafe.Pointer) {
|
||||
}
|
||||
|
||||
func raceReadRange(addr unsafe.Pointer, len int) {
|
||||
}
|
||||
|
||||
func raceWriteRange(addr unsafe.Pointer, len int) {
|
||||
}
|
||||
224
unix/route_bsd.go
Normal file
224
unix/route_bsd.go
Normal file
@@ -0,0 +1,224 @@
|
||||
// Copyright 2011 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 darwin dragonfly freebsd netbsd openbsd
|
||||
|
||||
// Routing sockets and messages
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// Round the length of a raw sockaddr up to align it properly.
|
||||
func rsaAlignOf(salen int) int {
|
||||
salign := sizeofPtr
|
||||
// NOTE: It seems like 64-bit Darwin kernel still requires
|
||||
// 32-bit aligned access to BSD subsystem. Also NetBSD 6
|
||||
// kernel and beyond require 64-bit aligned access to routing
|
||||
// facilities.
|
||||
if darwin64Bit {
|
||||
salign = 4
|
||||
} else if netbsd32Bit {
|
||||
salign = 8
|
||||
}
|
||||
if salen == 0 {
|
||||
return salign
|
||||
}
|
||||
return (salen + salign - 1) & ^(salign - 1)
|
||||
}
|
||||
|
||||
// RouteRIB returns routing information base, as known as RIB,
|
||||
// which consists of network facility information, states and
|
||||
// parameters.
|
||||
func RouteRIB(facility, param int) ([]byte, error) {
|
||||
mib := []_C_int{CTL_NET, AF_ROUTE, 0, 0, _C_int(facility), _C_int(param)}
|
||||
// Find size.
|
||||
n := uintptr(0)
|
||||
if err := sysctl(mib, nil, &n, nil, 0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
tab := make([]byte, n)
|
||||
if err := sysctl(mib, &tab[0], &n, nil, 0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tab[:n], nil
|
||||
}
|
||||
|
||||
// RoutingMessage represents a routing message.
|
||||
type RoutingMessage interface {
|
||||
sockaddr() []Sockaddr
|
||||
}
|
||||
|
||||
const anyMessageLen = int(unsafe.Sizeof(anyMessage{}))
|
||||
|
||||
type anyMessage struct {
|
||||
Msglen uint16
|
||||
Version uint8
|
||||
Type uint8
|
||||
}
|
||||
|
||||
// RouteMessage represents a routing message containing routing
|
||||
// entries.
|
||||
type RouteMessage struct {
|
||||
Header RtMsghdr
|
||||
Data []byte
|
||||
}
|
||||
|
||||
const rtaRtMask = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_GENMASK
|
||||
|
||||
func (m *RouteMessage) sockaddr() []Sockaddr {
|
||||
var (
|
||||
af int
|
||||
sas [4]Sockaddr
|
||||
)
|
||||
b := m.Data[:]
|
||||
for i := uint(0); i < RTAX_MAX; i++ {
|
||||
if m.Header.Addrs&rtaRtMask&(1<<i) == 0 {
|
||||
continue
|
||||
}
|
||||
rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))
|
||||
switch i {
|
||||
case RTAX_DST, RTAX_GATEWAY:
|
||||
sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if i == RTAX_DST {
|
||||
af = int(rsa.Family)
|
||||
}
|
||||
sas[i] = sa
|
||||
case RTAX_NETMASK, RTAX_GENMASK:
|
||||
switch af {
|
||||
case AF_INET:
|
||||
rsa4 := (*RawSockaddrInet4)(unsafe.Pointer(&b[0]))
|
||||
sa := new(SockaddrInet4)
|
||||
for j := 0; rsa4.Len > 0 && j < int(rsa4.Len)-int(unsafe.Offsetof(rsa4.Addr)); j++ {
|
||||
sa.Addr[j] = rsa4.Addr[j]
|
||||
}
|
||||
sas[i] = sa
|
||||
case AF_INET6:
|
||||
rsa6 := (*RawSockaddrInet6)(unsafe.Pointer(&b[0]))
|
||||
sa := new(SockaddrInet6)
|
||||
for j := 0; rsa6.Len > 0 && j < int(rsa6.Len)-int(unsafe.Offsetof(rsa6.Addr)); j++ {
|
||||
sa.Addr[j] = rsa6.Addr[j]
|
||||
}
|
||||
sas[i] = sa
|
||||
}
|
||||
}
|
||||
b = b[rsaAlignOf(int(rsa.Len)):]
|
||||
}
|
||||
return sas[:]
|
||||
}
|
||||
|
||||
// InterfaceMessage represents a routing message containing
|
||||
// network interface entries.
|
||||
type InterfaceMessage struct {
|
||||
Header IfMsghdr
|
||||
Data []byte
|
||||
}
|
||||
|
||||
func (m *InterfaceMessage) sockaddr() (sas []Sockaddr) {
|
||||
if m.Header.Addrs&RTA_IFP == 0 {
|
||||
return nil
|
||||
}
|
||||
sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(&m.Data[0])))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return append(sas, sa)
|
||||
}
|
||||
|
||||
// InterfaceAddrMessage represents a routing message containing
|
||||
// network interface address entries.
|
||||
type InterfaceAddrMessage struct {
|
||||
Header IfaMsghdr
|
||||
Data []byte
|
||||
}
|
||||
|
||||
const rtaIfaMask = RTA_IFA | RTA_NETMASK | RTA_BRD
|
||||
|
||||
func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) {
|
||||
if m.Header.Addrs&rtaIfaMask == 0 {
|
||||
return nil
|
||||
}
|
||||
b := m.Data[:]
|
||||
// We still see AF_UNSPEC in socket addresses on some
|
||||
// platforms. To identify each address family correctly, we
|
||||
// will use the address family of RTAX_NETMASK as a preferred
|
||||
// one on the 32-bit NetBSD kernel, also use the length of
|
||||
// RTAX_NETMASK socket address on the FreeBSD kernel.
|
||||
preferredFamily := uint8(AF_UNSPEC)
|
||||
for i := uint(0); i < RTAX_MAX; i++ {
|
||||
if m.Header.Addrs&rtaIfaMask&(1<<i) == 0 {
|
||||
continue
|
||||
}
|
||||
rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))
|
||||
switch i {
|
||||
case RTAX_IFA:
|
||||
if rsa.Family == AF_UNSPEC {
|
||||
rsa.Family = preferredFamily
|
||||
}
|
||||
sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
sas = append(sas, sa)
|
||||
case RTAX_NETMASK:
|
||||
switch rsa.Family {
|
||||
case AF_UNSPEC:
|
||||
switch rsa.Len {
|
||||
case SizeofSockaddrInet4:
|
||||
rsa.Family = AF_INET
|
||||
case SizeofSockaddrInet6:
|
||||
rsa.Family = AF_INET6
|
||||
default:
|
||||
rsa.Family = AF_INET // an old fashion, AF_UNSPEC means AF_INET
|
||||
}
|
||||
case AF_INET, AF_INET6:
|
||||
preferredFamily = rsa.Family
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
sas = append(sas, sa)
|
||||
case RTAX_BRD:
|
||||
// nothing to do
|
||||
}
|
||||
b = b[rsaAlignOf(int(rsa.Len)):]
|
||||
}
|
||||
return sas
|
||||
}
|
||||
|
||||
// ParseRoutingMessage parses b as routing messages and returns the
|
||||
// slice containing the RoutingMessage interfaces.
|
||||
func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) {
|
||||
msgCount := 0
|
||||
for len(b) >= anyMessageLen {
|
||||
msgCount++
|
||||
any := (*anyMessage)(unsafe.Pointer(&b[0]))
|
||||
if any.Version != RTM_VERSION {
|
||||
b = b[any.Msglen:]
|
||||
continue
|
||||
}
|
||||
msgs = append(msgs, any.toRoutingMessage(b))
|
||||
b = b[any.Msglen:]
|
||||
}
|
||||
// We failed to parse any of the messages - version mismatch?
|
||||
if msgCount > 0 && len(msgs) == 0 {
|
||||
return nil, EINVAL
|
||||
}
|
||||
return msgs, nil
|
||||
}
|
||||
|
||||
// ParseRoutingMessage parses msg's payload as raw sockaddrs and
|
||||
// returns the slice containing the Sockaddr interfaces.
|
||||
func ParseRoutingSockaddr(msg RoutingMessage) (sas []Sockaddr, err error) {
|
||||
return append(sas, msg.sockaddr()...), nil
|
||||
}
|
||||
61
unix/route_darwin.go
Normal file
61
unix/route_darwin.go
Normal file
@@ -0,0 +1,61 @@
|
||||
// Copyright 2011 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.
|
||||
|
||||
// Routing sockets and messages for Darwin
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
|
||||
switch any.Type {
|
||||
case RTM_ADD, RTM_DELETE, RTM_CHANGE, RTM_GET, RTM_LOSING, RTM_REDIRECT, RTM_MISS, RTM_LOCK, RTM_RESOLVE:
|
||||
p := (*RouteMessage)(unsafe.Pointer(any))
|
||||
return &RouteMessage{Header: p.Header, Data: b[SizeofRtMsghdr:any.Msglen]}
|
||||
case RTM_IFINFO:
|
||||
p := (*InterfaceMessage)(unsafe.Pointer(any))
|
||||
return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]}
|
||||
case RTM_NEWADDR, RTM_DELADDR:
|
||||
p := (*InterfaceAddrMessage)(unsafe.Pointer(any))
|
||||
return &InterfaceAddrMessage{Header: p.Header, Data: b[SizeofIfaMsghdr:any.Msglen]}
|
||||
case RTM_NEWMADDR2, RTM_DELMADDR:
|
||||
p := (*InterfaceMulticastAddrMessage)(unsafe.Pointer(any))
|
||||
return &InterfaceMulticastAddrMessage{Header: p.Header, Data: b[SizeofIfmaMsghdr2:any.Msglen]}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InterfaceMulticastAddrMessage represents a routing message
|
||||
// containing network interface address entries.
|
||||
type InterfaceMulticastAddrMessage struct {
|
||||
Header IfmaMsghdr2
|
||||
Data []byte
|
||||
}
|
||||
|
||||
const rtaIfmaMask = RTA_GATEWAY | RTA_IFP | RTA_IFA
|
||||
|
||||
func (m *InterfaceMulticastAddrMessage) sockaddr() (sas []Sockaddr) {
|
||||
if m.Header.Addrs&rtaIfmaMask == 0 {
|
||||
return nil
|
||||
}
|
||||
b := m.Data[:]
|
||||
for i := uint(0); i < RTAX_MAX; i++ {
|
||||
if m.Header.Addrs&rtaIfmaMask&(1<<i) == 0 {
|
||||
continue
|
||||
}
|
||||
rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))
|
||||
switch i {
|
||||
case RTAX_IFA:
|
||||
sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
|
||||
if e != nil {
|
||||
return nil
|
||||
}
|
||||
sas = append(sas, sa)
|
||||
case RTAX_GATEWAY, RTAX_IFP:
|
||||
// nothing to do
|
||||
}
|
||||
b = b[rsaAlignOf(int(rsa.Len)):]
|
||||
}
|
||||
return sas
|
||||
}
|
||||
72
unix/route_dragonfly.go
Normal file
72
unix/route_dragonfly.go
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright 2011 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.
|
||||
|
||||
// Routing sockets and messages for Dragonfly
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
|
||||
switch any.Type {
|
||||
case RTM_ADD, RTM_DELETE, RTM_CHANGE, RTM_GET, RTM_LOSING, RTM_REDIRECT, RTM_MISS, RTM_LOCK, RTM_RESOLVE:
|
||||
p := (*RouteMessage)(unsafe.Pointer(any))
|
||||
return &RouteMessage{Header: p.Header, Data: b[SizeofRtMsghdr:any.Msglen]}
|
||||
case RTM_IFINFO:
|
||||
p := (*InterfaceMessage)(unsafe.Pointer(any))
|
||||
return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]}
|
||||
case RTM_IFANNOUNCE:
|
||||
p := (*InterfaceAnnounceMessage)(unsafe.Pointer(any))
|
||||
return &InterfaceAnnounceMessage{Header: p.Header}
|
||||
case RTM_NEWADDR, RTM_DELADDR:
|
||||
p := (*InterfaceAddrMessage)(unsafe.Pointer(any))
|
||||
return &InterfaceAddrMessage{Header: p.Header, Data: b[SizeofIfaMsghdr:any.Msglen]}
|
||||
case RTM_NEWMADDR, RTM_DELMADDR:
|
||||
p := (*InterfaceMulticastAddrMessage)(unsafe.Pointer(any))
|
||||
return &InterfaceMulticastAddrMessage{Header: p.Header, Data: b[SizeofIfmaMsghdr:any.Msglen]}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InterfaceAnnounceMessage represents a routing message containing
|
||||
// network interface arrival and departure information.
|
||||
type InterfaceAnnounceMessage struct {
|
||||
Header IfAnnounceMsghdr
|
||||
}
|
||||
|
||||
func (m *InterfaceAnnounceMessage) sockaddr() (sas []Sockaddr) { return nil }
|
||||
|
||||
// InterfaceMulticastAddrMessage represents a routing message
|
||||
// containing network interface address entries.
|
||||
type InterfaceMulticastAddrMessage struct {
|
||||
Header IfmaMsghdr
|
||||
Data []byte
|
||||
}
|
||||
|
||||
const rtaIfmaMask = RTA_GATEWAY | RTA_IFP | RTA_IFA
|
||||
|
||||
func (m *InterfaceMulticastAddrMessage) sockaddr() (sas []Sockaddr) {
|
||||
if m.Header.Addrs&rtaIfmaMask == 0 {
|
||||
return nil
|
||||
}
|
||||
b := m.Data[:]
|
||||
for i := uint(0); i < RTAX_MAX; i++ {
|
||||
if m.Header.Addrs&rtaIfmaMask&(1<<i) == 0 {
|
||||
continue
|
||||
}
|
||||
rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))
|
||||
switch i {
|
||||
case RTAX_IFA:
|
||||
sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
|
||||
if e != nil {
|
||||
return nil
|
||||
}
|
||||
sas = append(sas, sa)
|
||||
case RTAX_GATEWAY, RTAX_IFP:
|
||||
// nothing to do
|
||||
}
|
||||
b = b[rsaAlignOf(int(rsa.Len)):]
|
||||
}
|
||||
return sas
|
||||
}
|
||||
78
unix/route_freebsd.go
Normal file
78
unix/route_freebsd.go
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright 2011 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.
|
||||
|
||||
// Routing sockets and messages for FreeBSD
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html.
|
||||
var freebsdVersion uint32
|
||||
|
||||
func init() {
|
||||
freebsdVersion, _ = SysctlUint32("kern.osreldate")
|
||||
}
|
||||
|
||||
func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
|
||||
switch any.Type {
|
||||
case RTM_ADD, RTM_DELETE, RTM_CHANGE, RTM_GET, RTM_LOSING, RTM_REDIRECT, RTM_MISS, RTM_LOCK, RTM_RESOLVE:
|
||||
p := (*RouteMessage)(unsafe.Pointer(any))
|
||||
return &RouteMessage{Header: p.Header, Data: b[SizeofRtMsghdr:any.Msglen]}
|
||||
case RTM_IFINFO:
|
||||
return any.parseInterfaceMessage(b)
|
||||
case RTM_IFANNOUNCE:
|
||||
p := (*InterfaceAnnounceMessage)(unsafe.Pointer(any))
|
||||
return &InterfaceAnnounceMessage{Header: p.Header}
|
||||
case RTM_NEWADDR, RTM_DELADDR:
|
||||
p := (*InterfaceAddrMessage)(unsafe.Pointer(any))
|
||||
return &InterfaceAddrMessage{Header: p.Header, Data: b[SizeofIfaMsghdr:any.Msglen]}
|
||||
case RTM_NEWMADDR, RTM_DELMADDR:
|
||||
p := (*InterfaceMulticastAddrMessage)(unsafe.Pointer(any))
|
||||
return &InterfaceMulticastAddrMessage{Header: p.Header, Data: b[SizeofIfmaMsghdr:any.Msglen]}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InterfaceAnnounceMessage represents a routing message containing
|
||||
// network interface arrival and departure information.
|
||||
type InterfaceAnnounceMessage struct {
|
||||
Header IfAnnounceMsghdr
|
||||
}
|
||||
|
||||
func (m *InterfaceAnnounceMessage) sockaddr() (sas []Sockaddr) { return nil }
|
||||
|
||||
// InterfaceMulticastAddrMessage represents a routing message
|
||||
// containing network interface address entries.
|
||||
type InterfaceMulticastAddrMessage struct {
|
||||
Header IfmaMsghdr
|
||||
Data []byte
|
||||
}
|
||||
|
||||
const rtaIfmaMask = RTA_GATEWAY | RTA_IFP | RTA_IFA
|
||||
|
||||
func (m *InterfaceMulticastAddrMessage) sockaddr() (sas []Sockaddr) {
|
||||
if m.Header.Addrs&rtaIfmaMask == 0 {
|
||||
return nil
|
||||
}
|
||||
b := m.Data[:]
|
||||
for i := uint(0); i < RTAX_MAX; i++ {
|
||||
if m.Header.Addrs&rtaIfmaMask&(1<<i) == 0 {
|
||||
continue
|
||||
}
|
||||
rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))
|
||||
switch i {
|
||||
case RTAX_IFA:
|
||||
sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
|
||||
if e != nil {
|
||||
return nil
|
||||
}
|
||||
sas = append(sas, sa)
|
||||
case RTAX_GATEWAY, RTAX_IFP:
|
||||
// nothing to do
|
||||
}
|
||||
b = b[rsaAlignOf(int(rsa.Len)):]
|
||||
}
|
||||
return sas
|
||||
}
|
||||
24
unix/route_freebsd_32bit.go
Normal file
24
unix/route_freebsd_32bit.go
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2014 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 freebsd,386 freebsd,arm
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func (any *anyMessage) parseInterfaceMessage(b []byte) *InterfaceMessage {
|
||||
p := (*InterfaceMessage)(unsafe.Pointer(any))
|
||||
// FreeBSD 10 and beyond have a restructured mbuf
|
||||
// packet header view.
|
||||
// See http://svnweb.freebsd.org/base?view=revision&revision=254804.
|
||||
if freebsdVersion >= 1000000 {
|
||||
m := (*ifMsghdr)(unsafe.Pointer(any))
|
||||
p.Header.Data.Hwassist = uint32(m.Data.Hwassist)
|
||||
p.Header.Data.Epoch = m.Data.Epoch
|
||||
p.Header.Data.Lastchange = m.Data.Lastchange
|
||||
return &InterfaceMessage{Header: p.Header, Data: b[sizeofIfMsghdr:any.Msglen]}
|
||||
}
|
||||
return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]}
|
||||
}
|
||||
14
unix/route_freebsd_64bit.go
Normal file
14
unix/route_freebsd_64bit.go
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright 2014 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 freebsd,amd64
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func (any *anyMessage) parseInterfaceMessage(b []byte) *InterfaceMessage {
|
||||
p := (*InterfaceMessage)(unsafe.Pointer(any))
|
||||
return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]}
|
||||
}
|
||||
35
unix/route_netbsd.go
Normal file
35
unix/route_netbsd.go
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright 2011 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.
|
||||
|
||||
// Routing sockets and messages for NetBSD
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
|
||||
switch any.Type {
|
||||
case RTM_ADD, RTM_DELETE, RTM_CHANGE, RTM_GET, RTM_LOSING, RTM_REDIRECT, RTM_MISS, RTM_LOCK, RTM_RESOLVE:
|
||||
p := (*RouteMessage)(unsafe.Pointer(any))
|
||||
return &RouteMessage{Header: p.Header, Data: b[SizeofRtMsghdr:any.Msglen]}
|
||||
case RTM_IFINFO:
|
||||
p := (*InterfaceMessage)(unsafe.Pointer(any))
|
||||
return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]}
|
||||
case RTM_IFANNOUNCE:
|
||||
p := (*InterfaceAnnounceMessage)(unsafe.Pointer(any))
|
||||
return &InterfaceAnnounceMessage{Header: p.Header}
|
||||
case RTM_NEWADDR, RTM_DELADDR:
|
||||
p := (*InterfaceAddrMessage)(unsafe.Pointer(any))
|
||||
return &InterfaceAddrMessage{Header: p.Header, Data: b[SizeofIfaMsghdr:any.Msglen]}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InterfaceAnnounceMessage represents a routing message containing
|
||||
// network interface arrival and departure information.
|
||||
type InterfaceAnnounceMessage struct {
|
||||
Header IfAnnounceMsghdr
|
||||
}
|
||||
|
||||
func (m *InterfaceAnnounceMessage) sockaddr() (sas []Sockaddr) { return nil }
|
||||
35
unix/route_openbsd.go
Normal file
35
unix/route_openbsd.go
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright 2011 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.
|
||||
|
||||
// Routing sockets and messages for OpenBSD
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
|
||||
switch any.Type {
|
||||
case RTM_ADD, RTM_DELETE, RTM_CHANGE, RTM_GET, RTM_LOSING, RTM_REDIRECT, RTM_MISS, RTM_LOCK, RTM_RESOLVE:
|
||||
p := (*RouteMessage)(unsafe.Pointer(any))
|
||||
return &RouteMessage{Header: p.Header, Data: b[SizeofRtMsghdr:any.Msglen]}
|
||||
case RTM_IFINFO:
|
||||
p := (*InterfaceMessage)(unsafe.Pointer(any))
|
||||
return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]}
|
||||
case RTM_IFANNOUNCE:
|
||||
p := (*InterfaceAnnounceMessage)(unsafe.Pointer(any))
|
||||
return &InterfaceAnnounceMessage{Header: p.Header}
|
||||
case RTM_NEWADDR, RTM_DELADDR:
|
||||
p := (*InterfaceAddrMessage)(unsafe.Pointer(any))
|
||||
return &InterfaceAddrMessage{Header: p.Header, Data: b[SizeofIfaMsghdr:any.Msglen]}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InterfaceAnnounceMessage represents a routing message containing
|
||||
// network interface arrival and departure information.
|
||||
type InterfaceAnnounceMessage struct {
|
||||
Header IfAnnounceMsghdr
|
||||
}
|
||||
|
||||
func (m *InterfaceAnnounceMessage) sockaddr() (sas []Sockaddr) { return nil }
|
||||
260
unix/so_solaris.go
Normal file
260
unix/so_solaris.go
Normal file
@@ -0,0 +1,260 @@
|
||||
// Copyright 2011 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.
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// soError describes reasons for shared library load failures.
|
||||
type soError struct {
|
||||
Err error
|
||||
ObjName string
|
||||
Msg string
|
||||
}
|
||||
|
||||
func (e *soError) Error() string { return e.Msg }
|
||||
|
||||
// Implemented in ../runtime/syscall_solaris.goc.
|
||||
func rawSysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
|
||||
func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
|
||||
func dlclose(handle uintptr) (err Errno)
|
||||
func dlopen(name *uint8, mode uintptr) (handle uintptr, err Errno)
|
||||
func dlsym(handle uintptr, name *uint8) (proc uintptr, err Errno)
|
||||
|
||||
// A so implements access to a single shared library object.
|
||||
type so struct {
|
||||
Name string
|
||||
Handle uintptr
|
||||
}
|
||||
|
||||
// loadSO loads shared library file into memory.
|
||||
func loadSO(name string) (*so, error) {
|
||||
namep, err := BytePtrFromString(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h, e := dlopen(namep, 1) // RTLD_LAZY
|
||||
if e != 0 {
|
||||
return nil, &soError{
|
||||
Err: e,
|
||||
ObjName: name,
|
||||
Msg: "Failed to load " + name + ": " + e.Error(),
|
||||
}
|
||||
}
|
||||
d := &so{
|
||||
Name: name,
|
||||
Handle: uintptr(h),
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// mustLoadSO is like loadSO but panics if load operation fails.
|
||||
func mustLoadSO(name string) *so {
|
||||
d, e := loadSO(name)
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// FindProc searches shared library d for procedure named name and returns
|
||||
// *proc if found. It returns an error if the search fails.
|
||||
func (d *so) FindProc(name string) (*proc, error) {
|
||||
namep, err := BytePtrFromString(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
a, _ := dlsym(uintptr(d.Handle), namep)
|
||||
if a == 0 {
|
||||
return nil, &soError{
|
||||
Err: ENOSYS,
|
||||
ObjName: name,
|
||||
Msg: "Failed to find " + name + " procedure in " + d.Name,
|
||||
}
|
||||
}
|
||||
p := &proc{
|
||||
SO: d,
|
||||
Name: name,
|
||||
addr: a,
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// MustFindProc is like FindProc but panics if search fails.
|
||||
func (d *so) MustFindProc(name string) *proc {
|
||||
p, e := d.FindProc(name)
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Release unloads shared library d from memory.
|
||||
func (d *so) Release() (err error) {
|
||||
return dlclose(d.Handle)
|
||||
}
|
||||
|
||||
// A proc implements access to a procedure inside a shared library.
|
||||
type proc struct {
|
||||
SO *so
|
||||
Name string
|
||||
addr uintptr
|
||||
}
|
||||
|
||||
// Addr returns the address of the procedure represented by p.
|
||||
// The return value can be passed to Syscall to run the procedure.
|
||||
func (p *proc) Addr() uintptr {
|
||||
return p.addr
|
||||
}
|
||||
|
||||
// Call executes procedure p with arguments a. It will panic, if more then
|
||||
// 6 arguments are supplied.
|
||||
//
|
||||
// The returned error is always non-nil, constructed from the result of
|
||||
// GetLastError. Callers must inspect the primary return value to decide
|
||||
// whether an error occurred (according to the semantics of the specific
|
||||
// function being called) before consulting the error. The error will be
|
||||
// guaranteed to contain syscall.Errno.
|
||||
func (p *proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
|
||||
switch len(a) {
|
||||
case 0:
|
||||
return sysvicall6(p.Addr(), uintptr(len(a)), 0, 0, 0, 0, 0, 0)
|
||||
case 1:
|
||||
return sysvicall6(p.Addr(), uintptr(len(a)), a[0], 0, 0, 0, 0, 0)
|
||||
case 2:
|
||||
return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], 0, 0, 0, 0)
|
||||
case 3:
|
||||
return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], 0, 0, 0)
|
||||
case 4:
|
||||
return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
|
||||
case 5:
|
||||
return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
|
||||
case 6:
|
||||
return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
|
||||
default:
|
||||
panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// A lazySO implements access to a single shared library. It will delay
|
||||
// the load of the shared library until the first call to its Handle method
|
||||
// or to one of its lazyProc's Addr method.
|
||||
type lazySO struct {
|
||||
mu sync.Mutex
|
||||
so *so // non nil once SO is loaded
|
||||
Name string
|
||||
}
|
||||
|
||||
// Load loads single shared file d.Name into memory. It returns an error if
|
||||
// fails. Load will not try to load SO, if it is already loaded into memory.
|
||||
func (d *lazySO) Load() error {
|
||||
// Non-racy version of:
|
||||
// if d.so == nil {
|
||||
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.so))) == nil {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
if d.so == nil {
|
||||
so, e := loadSO(d.Name)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
// Non-racy version of:
|
||||
// d.so = so
|
||||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.so)), unsafe.Pointer(so))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// mustLoad is like Load but panics if search fails.
|
||||
func (d *lazySO) mustLoad() {
|
||||
e := d.Load()
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle returns d's module handle.
|
||||
func (d *lazySO) Handle() uintptr {
|
||||
d.mustLoad()
|
||||
return uintptr(d.so.Handle)
|
||||
}
|
||||
|
||||
// NewProc returns a lazyProc for accessing the named procedure in the SO d.
|
||||
func (d *lazySO) NewProc(name string) *lazyProc {
|
||||
return &lazyProc{l: d, Name: name}
|
||||
}
|
||||
|
||||
// newLazySO creates new lazySO associated with SO file.
|
||||
func newLazySO(name string) *lazySO {
|
||||
return &lazySO{Name: name}
|
||||
}
|
||||
|
||||
// A lazyProc implements access to a procedure inside a lazySO.
|
||||
// It delays the lookup until the Addr method is called.
|
||||
type lazyProc struct {
|
||||
mu sync.Mutex
|
||||
Name string
|
||||
l *lazySO
|
||||
proc *proc
|
||||
}
|
||||
|
||||
// Find searches the shared library for procedure named p.Name. It returns an
|
||||
// error if search fails. Find will not search procedure, if it is already
|
||||
// found and loaded into memory.
|
||||
func (p *lazyProc) Find() error {
|
||||
// Non-racy version of:
|
||||
// if p.proc == nil {
|
||||
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
if p.proc == nil {
|
||||
e := p.l.Load()
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
proc, e := p.l.so.FindProc(p.Name)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
// Non-racy version of:
|
||||
// p.proc = proc
|
||||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// mustFind is like Find but panics if search fails.
|
||||
func (p *lazyProc) mustFind() {
|
||||
e := p.Find()
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
}
|
||||
|
||||
// Addr returns the address of the procedure represented by p.
|
||||
// The return value can be passed to Syscall to run the procedure.
|
||||
func (p *lazyProc) Addr() uintptr {
|
||||
p.mustFind()
|
||||
return p.proc.Addr()
|
||||
}
|
||||
|
||||
// Call executes procedure p with arguments a. It will panic, if more then
|
||||
// 6 arguments are supplied.
|
||||
//
|
||||
// The returned error is always non-nil, constructed from the result of
|
||||
// GetLastError. Callers must inspect the primary return value to decide
|
||||
// whether an error occurred (according to the semantics of the specific
|
||||
// function being called) before consulting the error. The error will be
|
||||
// guaranteed to contain syscall.Errno.
|
||||
func (p *lazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
|
||||
p.mustFind()
|
||||
return p.proc.Call(a...)
|
||||
}
|
||||
36
unix/sockcmsg_linux.go
Normal file
36
unix/sockcmsg_linux.go
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright 2011 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.
|
||||
|
||||
// Socket control messages
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// UnixCredentials encodes credentials into a socket control message
|
||||
// for sending to another process. This can be used for
|
||||
// authentication.
|
||||
func UnixCredentials(ucred *Ucred) []byte {
|
||||
b := make([]byte, CmsgSpace(SizeofUcred))
|
||||
h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
|
||||
h.Level = SOL_SOCKET
|
||||
h.Type = SCM_CREDENTIALS
|
||||
h.SetLen(CmsgLen(SizeofUcred))
|
||||
*((*Ucred)(cmsgData(h))) = *ucred
|
||||
return b
|
||||
}
|
||||
|
||||
// ParseUnixCredentials decodes a socket control message that contains
|
||||
// credentials in a Ucred structure. To receive such a message, the
|
||||
// SO_PASSCRED option must be enabled on the socket.
|
||||
func ParseUnixCredentials(m *SocketControlMessage) (*Ucred, error) {
|
||||
if m.Header.Level != SOL_SOCKET {
|
||||
return nil, EINVAL
|
||||
}
|
||||
if m.Header.Type != SCM_CREDENTIALS {
|
||||
return nil, EINVAL
|
||||
}
|
||||
ucred := *(*Ucred)(unsafe.Pointer(&m.Data[0]))
|
||||
return &ucred, nil
|
||||
}
|
||||
103
unix/sockcmsg_unix.go
Normal file
103
unix/sockcmsg_unix.go
Normal file
@@ -0,0 +1,103 @@
|
||||
// Copyright 2011 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 darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
|
||||
// Socket control messages
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// Round the length of a raw sockaddr up to align it properly.
|
||||
func cmsgAlignOf(salen int) int {
|
||||
salign := sizeofPtr
|
||||
// NOTE: It seems like 64-bit Darwin and DragonFly BSD kernels
|
||||
// still require 32-bit aligned access to network subsystem.
|
||||
if darwin64Bit || dragonfly64Bit {
|
||||
salign = 4
|
||||
}
|
||||
return (salen + salign - 1) & ^(salign - 1)
|
||||
}
|
||||
|
||||
// CmsgLen returns the value to store in the Len field of the Cmsghdr
|
||||
// structure, taking into account any necessary alignment.
|
||||
func CmsgLen(datalen int) int {
|
||||
return cmsgAlignOf(SizeofCmsghdr) + datalen
|
||||
}
|
||||
|
||||
// CmsgSpace returns the number of bytes an ancillary element with
|
||||
// payload of the passed data length occupies.
|
||||
func CmsgSpace(datalen int) int {
|
||||
return cmsgAlignOf(SizeofCmsghdr) + cmsgAlignOf(datalen)
|
||||
}
|
||||
|
||||
func cmsgData(h *Cmsghdr) unsafe.Pointer {
|
||||
return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(cmsgAlignOf(SizeofCmsghdr)))
|
||||
}
|
||||
|
||||
// SocketControlMessage represents a socket control message.
|
||||
type SocketControlMessage struct {
|
||||
Header Cmsghdr
|
||||
Data []byte
|
||||
}
|
||||
|
||||
// ParseSocketControlMessage parses b as an array of socket control
|
||||
// messages.
|
||||
func ParseSocketControlMessage(b []byte) ([]SocketControlMessage, error) {
|
||||
var msgs []SocketControlMessage
|
||||
i := 0
|
||||
for i+CmsgLen(0) <= len(b) {
|
||||
h, dbuf, err := socketControlMessageHeaderAndData(b[i:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m := SocketControlMessage{Header: *h, Data: dbuf}
|
||||
msgs = append(msgs, m)
|
||||
i += cmsgAlignOf(int(h.Len))
|
||||
}
|
||||
return msgs, nil
|
||||
}
|
||||
|
||||
func socketControlMessageHeaderAndData(b []byte) (*Cmsghdr, []byte, error) {
|
||||
h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
|
||||
if h.Len < SizeofCmsghdr || int(h.Len) > len(b) {
|
||||
return nil, nil, EINVAL
|
||||
}
|
||||
return h, b[cmsgAlignOf(SizeofCmsghdr):h.Len], nil
|
||||
}
|
||||
|
||||
// UnixRights encodes a set of open file descriptors into a socket
|
||||
// control message for sending to another process.
|
||||
func UnixRights(fds ...int) []byte {
|
||||
datalen := len(fds) * 4
|
||||
b := make([]byte, CmsgSpace(datalen))
|
||||
h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
|
||||
h.Level = SOL_SOCKET
|
||||
h.Type = SCM_RIGHTS
|
||||
h.SetLen(CmsgLen(datalen))
|
||||
data := uintptr(cmsgData(h))
|
||||
for _, fd := range fds {
|
||||
*(*int32)(unsafe.Pointer(data)) = int32(fd)
|
||||
data += 4
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// ParseUnixRights decodes a socket control message that contains an
|
||||
// integer array of open file descriptors from another process.
|
||||
func ParseUnixRights(m *SocketControlMessage) ([]int, error) {
|
||||
if m.Header.Level != SOL_SOCKET {
|
||||
return nil, EINVAL
|
||||
}
|
||||
if m.Header.Type != SCM_RIGHTS {
|
||||
return nil, EINVAL
|
||||
}
|
||||
fds := make([]int, len(m.Data)>>2)
|
||||
for i, j := 0, 0; i < len(m.Data); i += 4 {
|
||||
fds[j] = int(*(*int32)(unsafe.Pointer(&m.Data[i])))
|
||||
j++
|
||||
}
|
||||
return fds, nil
|
||||
}
|
||||
822
unix/srpc_nacl.go
Normal file
822
unix/srpc_nacl.go
Normal file
@@ -0,0 +1,822 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
// Native Client SRPC message passing.
|
||||
// This code is needed to invoke SecureRandom, the NaCl equivalent of /dev/random.
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// An srpcClient represents the client side of an SRPC connection.
|
||||
type srpcClient struct {
|
||||
fd int // to server
|
||||
r msgReceiver
|
||||
s msgSender
|
||||
service map[string]srpcService // services by name
|
||||
|
||||
outMu sync.Mutex // protects writing to connection
|
||||
|
||||
mu sync.Mutex // protects following fields
|
||||
muxer bool // is someone reading and muxing responses
|
||||
pending map[uint32]*srpc
|
||||
idGen uint32 // generator for request IDs
|
||||
}
|
||||
|
||||
// An srpcService is a single method that the server offers.
|
||||
type srpcService struct {
|
||||
num uint32 // method number
|
||||
fmt string // argument format; see "parsing of RPC messages" below
|
||||
}
|
||||
|
||||
// An srpc represents a single srpc issued by a client.
|
||||
type srpc struct {
|
||||
Ret []interface{}
|
||||
Done chan *srpc
|
||||
Err error
|
||||
c *srpcClient
|
||||
id uint32
|
||||
}
|
||||
|
||||
// newClient allocates a new SRPC client using the file descriptor fd.
|
||||
func newClient(fd int) (*srpcClient, error) {
|
||||
c := new(srpcClient)
|
||||
c.fd = fd
|
||||
c.r.fd = fd
|
||||
c.s.fd = fd
|
||||
c.service = make(map[string]srpcService)
|
||||
c.pending = make(map[uint32]*srpc)
|
||||
|
||||
// service discovery request
|
||||
m := &msg{
|
||||
isRequest: 1,
|
||||
template: []interface{}{[]byte(nil)},
|
||||
size: []int{4000}, // max size to accept for returned byte slice
|
||||
}
|
||||
if err := m.pack(); err != nil {
|
||||
return nil, errors.New("Native Client SRPC service_discovery: preparing request: " + err.Error())
|
||||
}
|
||||
c.s.send(m)
|
||||
m, err := c.r.recv()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.unpack()
|
||||
if m.status != uint32(srpcOK) {
|
||||
return nil, errors.New("Native Client SRPC service_discovery: " + srpcErrno(m.status).Error())
|
||||
}
|
||||
list := m.value[0].([]byte)
|
||||
var n uint32
|
||||
for len(list) > 0 {
|
||||
var line []byte
|
||||
i := byteIndex(list, '\n')
|
||||
if i < 0 {
|
||||
line, list = list, nil
|
||||
} else {
|
||||
line, list = list[:i], list[i+1:]
|
||||
}
|
||||
i = byteIndex(line, ':')
|
||||
if i >= 0 {
|
||||
c.service[string(line)] = srpcService{n, string(line[i+1:])}
|
||||
}
|
||||
n++
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func byteIndex(b []byte, c byte) int {
|
||||
for i, bi := range b {
|
||||
if bi == c {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
var yourTurn srpc
|
||||
|
||||
func (c *srpcClient) wait(r *srpc) {
|
||||
var rx *srpc
|
||||
for rx = range r.Done {
|
||||
if rx != &yourTurn {
|
||||
break
|
||||
}
|
||||
c.input()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *srpcClient) input() {
|
||||
// read message
|
||||
m, err := c.r.recv()
|
||||
if err != nil {
|
||||
println("Native Client SRPC receive error:", err.Error())
|
||||
return
|
||||
}
|
||||
if m.unpack(); m.status != uint32(srpcOK) {
|
||||
println("Native Client SRPC receive error: invalid message: ", srpcErrno(m.status).Error())
|
||||
return
|
||||
}
|
||||
|
||||
// deliver to intended recipient
|
||||
c.mu.Lock()
|
||||
rpc, ok := c.pending[m.id]
|
||||
if ok {
|
||||
delete(c.pending, m.id)
|
||||
}
|
||||
|
||||
// wake a new muxer if there are more RPCs to read
|
||||
c.muxer = false
|
||||
for _, rpc := range c.pending {
|
||||
c.muxer = true
|
||||
rpc.Done <- &yourTurn
|
||||
break
|
||||
}
|
||||
c.mu.Unlock()
|
||||
if !ok {
|
||||
println("Native Client: unexpected response for ID", m.id)
|
||||
return
|
||||
}
|
||||
rpc.Ret = m.value
|
||||
rpc.Done <- rpc
|
||||
}
|
||||
|
||||
// Wait blocks until the RPC has finished.
|
||||
func (r *srpc) Wait() {
|
||||
r.c.wait(r)
|
||||
}
|
||||
|
||||
// Start issues an RPC request for method name with the given arguments.
|
||||
// The RPC r must not be in use for another pending request.
|
||||
// To wait for the RPC to finish, receive from r.Done and then
|
||||
// inspect r.Ret and r.Errno.
|
||||
func (r *srpc) Start(name string, arg []interface{}) {
|
||||
r.Err = nil
|
||||
r.c.mu.Lock()
|
||||
srv, ok := r.c.service[name]
|
||||
if !ok {
|
||||
r.c.mu.Unlock()
|
||||
r.Err = srpcErrBadRPCNumber
|
||||
r.Done <- r
|
||||
return
|
||||
}
|
||||
r.c.pending[r.id] = r
|
||||
if !r.c.muxer {
|
||||
r.c.muxer = true
|
||||
r.Done <- &yourTurn
|
||||
}
|
||||
r.c.mu.Unlock()
|
||||
|
||||
var m msg
|
||||
m.id = r.id
|
||||
m.isRequest = 1
|
||||
m.rpc = srv.num
|
||||
m.value = arg
|
||||
|
||||
// Fill in the return values and sizes to generate
|
||||
// the right type chars. We'll take most any size.
|
||||
|
||||
// Skip over input arguments.
|
||||
// We could check them against arg, but the server
|
||||
// will do that anyway.
|
||||
i := 0
|
||||
for srv.fmt[i] != ':' {
|
||||
i++
|
||||
}
|
||||
format := srv.fmt[i+1:]
|
||||
|
||||
// Now the return prototypes.
|
||||
m.template = make([]interface{}, len(format))
|
||||
m.size = make([]int, len(format))
|
||||
for i := 0; i < len(format); i++ {
|
||||
switch format[i] {
|
||||
default:
|
||||
println("Native Client SRPC: unexpected service type " + string(format[i]))
|
||||
r.Err = srpcErrBadRPCNumber
|
||||
r.Done <- r
|
||||
return
|
||||
case 'b':
|
||||
m.template[i] = false
|
||||
case 'C':
|
||||
m.template[i] = []byte(nil)
|
||||
m.size[i] = 1 << 30
|
||||
case 'd':
|
||||
m.template[i] = float64(0)
|
||||
case 'D':
|
||||
m.template[i] = []float64(nil)
|
||||
m.size[i] = 1 << 30
|
||||
case 'h':
|
||||
m.template[i] = int(-1)
|
||||
case 'i':
|
||||
m.template[i] = int32(0)
|
||||
case 'I':
|
||||
m.template[i] = []int32(nil)
|
||||
m.size[i] = 1 << 30
|
||||
case 's':
|
||||
m.template[i] = ""
|
||||
m.size[i] = 1 << 30
|
||||
}
|
||||
}
|
||||
|
||||
if err := m.pack(); err != nil {
|
||||
r.Err = errors.New("Native Client RPC Start " + name + ": preparing request: " + err.Error())
|
||||
r.Done <- r
|
||||
return
|
||||
}
|
||||
|
||||
r.c.outMu.Lock()
|
||||
r.c.s.send(&m)
|
||||
r.c.outMu.Unlock()
|
||||
}
|
||||
|
||||
// Call is a convenience wrapper that starts the RPC request,
|
||||
// waits for it to finish, and then returns the results.
|
||||
// Its implementation is:
|
||||
//
|
||||
// r.Start(name, arg)
|
||||
// r.Wait()
|
||||
// return r.Ret, r.Errno
|
||||
//
|
||||
func (c *srpcClient) Call(name string, arg ...interface{}) (ret []interface{}, err error) {
|
||||
r := c.NewRPC(nil)
|
||||
r.Start(name, arg)
|
||||
r.Wait()
|
||||
return r.Ret, r.Err
|
||||
}
|
||||
|
||||
// NewRPC creates a new RPC on the client connection.
|
||||
func (c *srpcClient) NewRPC(done chan *srpc) *srpc {
|
||||
if done == nil {
|
||||
done = make(chan *srpc, 1)
|
||||
}
|
||||
c.mu.Lock()
|
||||
id := c.idGen
|
||||
c.idGen++
|
||||
c.mu.Unlock()
|
||||
return &srpc{Done: done, c: c, id: id}
|
||||
}
|
||||
|
||||
// The current protocol number.
|
||||
// Kind of useless, since there have been backwards-incompatible changes
|
||||
// to the wire protocol that did not update the protocol number.
|
||||
// At this point it's really just a sanity check.
|
||||
const protocol = 0xc0da0002
|
||||
|
||||
// An srpcErrno is an SRPC status code.
|
||||
type srpcErrno uint32
|
||||
|
||||
const (
|
||||
srpcOK srpcErrno = 256 + iota
|
||||
srpcErrBreak
|
||||
srpcErrMessageTruncated
|
||||
srpcErrNoMemory
|
||||
srpcErrProtocolMismatch
|
||||
srpcErrBadRPCNumber
|
||||
srpcErrBadArgType
|
||||
srpcErrTooFewArgs
|
||||
srpcErrTooManyArgs
|
||||
srpcErrInArgTypeMismatch
|
||||
srpcErrOutArgTypeMismatch
|
||||
srpcErrInternalError
|
||||
srpcErrAppError
|
||||
)
|
||||
|
||||
var srpcErrstr = [...]string{
|
||||
srpcOK - srpcOK: "ok",
|
||||
srpcErrBreak - srpcOK: "break",
|
||||
srpcErrMessageTruncated - srpcOK: "message truncated",
|
||||
srpcErrNoMemory - srpcOK: "out of memory",
|
||||
srpcErrProtocolMismatch - srpcOK: "protocol mismatch",
|
||||
srpcErrBadRPCNumber - srpcOK: "invalid RPC method number",
|
||||
srpcErrBadArgType - srpcOK: "unexpected argument type",
|
||||
srpcErrTooFewArgs - srpcOK: "too few arguments",
|
||||
srpcErrTooManyArgs - srpcOK: "too many arguments",
|
||||
srpcErrInArgTypeMismatch - srpcOK: "input argument type mismatch",
|
||||
srpcErrOutArgTypeMismatch - srpcOK: "output argument type mismatch",
|
||||
srpcErrInternalError - srpcOK: "internal error",
|
||||
srpcErrAppError - srpcOK: "application error",
|
||||
}
|
||||
|
||||
func (e srpcErrno) Error() string {
|
||||
if e < srpcOK || int(e-srpcOK) >= len(srpcErrstr) {
|
||||
return "srpcErrno(" + itoa(int(e)) + ")"
|
||||
}
|
||||
return srpcErrstr[e-srpcOK]
|
||||
}
|
||||
|
||||
// A msgHdr is the data argument to the imc_recvmsg
|
||||
// and imc_sendmsg system calls.
|
||||
type msgHdr struct {
|
||||
iov *iov
|
||||
niov int32
|
||||
desc *int32
|
||||
ndesc int32
|
||||
flags uint32
|
||||
}
|
||||
|
||||
// A single region for I/O.
|
||||
type iov struct {
|
||||
base *byte
|
||||
len int32
|
||||
}
|
||||
|
||||
const maxMsgSize = 1<<16 - 4*4
|
||||
|
||||
// A msgReceiver receives messages from a file descriptor.
|
||||
type msgReceiver struct {
|
||||
fd int
|
||||
data [maxMsgSize]byte
|
||||
desc [8]int32
|
||||
hdr msgHdr
|
||||
iov iov
|
||||
}
|
||||
|
||||
func (r *msgReceiver) recv() (*msg, error) {
|
||||
// Init pointers to buffers where syscall recvmsg can write.
|
||||
r.iov.base = &r.data[0]
|
||||
r.iov.len = int32(len(r.data))
|
||||
r.hdr.iov = &r.iov
|
||||
r.hdr.niov = 1
|
||||
r.hdr.desc = &r.desc[0]
|
||||
r.hdr.ndesc = int32(len(r.desc))
|
||||
n, _, e := Syscall(sys_imc_recvmsg, uintptr(r.fd), uintptr(unsafe.Pointer(&r.hdr)), 0)
|
||||
if e != 0 {
|
||||
println("Native Client imc_recvmsg: ", e.Error())
|
||||
return nil, e
|
||||
}
|
||||
|
||||
// Make a copy of the data so that the next recvmsg doesn't
|
||||
// smash it. The system call did not update r.iov.len. Instead it
|
||||
// returned the total byte count as n.
|
||||
m := new(msg)
|
||||
m.data = make([]byte, n)
|
||||
copy(m.data, r.data[0:])
|
||||
|
||||
// Make a copy of the desc too.
|
||||
// The system call *did* update r.hdr.ndesc.
|
||||
if r.hdr.ndesc > 0 {
|
||||
m.desc = make([]int32, r.hdr.ndesc)
|
||||
copy(m.desc, r.desc[:])
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// A msgSender sends messages on a file descriptor.
|
||||
type msgSender struct {
|
||||
fd int
|
||||
hdr msgHdr
|
||||
iov iov
|
||||
}
|
||||
|
||||
func (s *msgSender) send(m *msg) error {
|
||||
if len(m.data) > 0 {
|
||||
s.iov.base = &m.data[0]
|
||||
}
|
||||
s.iov.len = int32(len(m.data))
|
||||
s.hdr.iov = &s.iov
|
||||
s.hdr.niov = 1
|
||||
s.hdr.desc = nil
|
||||
s.hdr.ndesc = 0
|
||||
_, _, e := Syscall(sys_imc_sendmsg, uintptr(s.fd), uintptr(unsafe.Pointer(&s.hdr)), 0)
|
||||
if e != 0 {
|
||||
println("Native Client imc_sendmsg: ", e.Error())
|
||||
return e
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// A msg is the Go representation of an SRPC message.
|
||||
type msg struct {
|
||||
data []byte // message data
|
||||
desc []int32 // message file descriptors
|
||||
|
||||
// parsed version of message
|
||||
id uint32
|
||||
isRequest uint32
|
||||
rpc uint32
|
||||
status uint32
|
||||
value []interface{}
|
||||
template []interface{}
|
||||
size []int
|
||||
format string
|
||||
broken bool
|
||||
}
|
||||
|
||||
// reading from a msg
|
||||
|
||||
func (m *msg) uint32() uint32 {
|
||||
if m.broken {
|
||||
return 0
|
||||
}
|
||||
if len(m.data) < 4 {
|
||||
m.broken = true
|
||||
return 0
|
||||
}
|
||||
b := m.data[:4]
|
||||
x := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
|
||||
m.data = m.data[4:]
|
||||
return x
|
||||
}
|
||||
|
||||
func (m *msg) uint64() uint64 {
|
||||
x := uint64(m.uint32()) | uint64(m.uint32())<<32
|
||||
if m.broken {
|
||||
return 0
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func (m *msg) bytes(n int) []byte {
|
||||
if m.broken {
|
||||
return nil
|
||||
}
|
||||
if len(m.data) < n {
|
||||
m.broken = true
|
||||
return nil
|
||||
}
|
||||
x := m.data[0:n]
|
||||
m.data = m.data[n:]
|
||||
return x
|
||||
}
|
||||
|
||||
// writing to a msg
|
||||
|
||||
func (m *msg) wuint32(x uint32) {
|
||||
m.data = append(m.data, byte(x), byte(x>>8), byte(x>>16), byte(x>>24))
|
||||
}
|
||||
|
||||
func (m *msg) wuint64(x uint64) {
|
||||
lo := uint32(x)
|
||||
hi := uint32(x >> 32)
|
||||
m.data = append(m.data, byte(lo), byte(lo>>8), byte(lo>>16), byte(lo>>24), byte(hi), byte(hi>>8), byte(hi>>16), byte(hi>>24))
|
||||
}
|
||||
|
||||
func (m *msg) wbytes(p []byte) {
|
||||
m.data = append(m.data, p...)
|
||||
}
|
||||
|
||||
func (m *msg) wstring(s string) {
|
||||
m.data = append(m.data, s...)
|
||||
}
|
||||
|
||||
// Parsing of RPC messages.
|
||||
//
|
||||
// Each message begins with
|
||||
// total_size uint32
|
||||
// total_descs uint32
|
||||
// fragment_size uint32
|
||||
// fragment_descs uint32
|
||||
//
|
||||
// If fragment_size < total_size or fragment_descs < total_descs, the actual
|
||||
// message is broken up in multiple messages; follow-up messages omit
|
||||
// the "total" fields and begin with the "fragment" fields.
|
||||
// We do not support putting fragmented messages back together.
|
||||
// To do this we would need to change the message receiver.
|
||||
//
|
||||
// After that size information, the message header follows:
|
||||
// protocol uint32
|
||||
// requestID uint32
|
||||
// isRequest uint32
|
||||
// rpcNumber uint32
|
||||
// status uint32
|
||||
// numValue uint32
|
||||
// numTemplate uint32
|
||||
//
|
||||
// After the header come numTemplate fixed-size arguments,
|
||||
// numValue fixed-size arguments, and then the variable-sized
|
||||
// part of the values. The templates describe the expected results
|
||||
// and have no associated variable sized data in the request.
|
||||
//
|
||||
// Each fixed-size argument has the form:
|
||||
// tag uint32 // really a char, like 'b' or 'C'
|
||||
// pad uint32 // unused
|
||||
// val1 uint32
|
||||
// val2 uint32
|
||||
//
|
||||
// The tags are:
|
||||
// 'b': bool; val1 == 0 or 1
|
||||
// 'C': []byte; val1 == len, data in variable-sized section
|
||||
// 'd': float64; (val1, val2) is data
|
||||
// 'D': []float64; val1 == len, data in variable-sized section
|
||||
// 'h': int; val1 == file descriptor
|
||||
// 'i': int32; descriptor in next entry in m.desc
|
||||
// 'I': []int; val1 == len, data in variable-sized section
|
||||
// 's': string; val1 == len, data in variable-sized section
|
||||
//
|
||||
|
||||
func (m *msg) pack() error {
|
||||
m.data = m.data[:0]
|
||||
m.desc = m.desc[:0]
|
||||
|
||||
// sizes, to fill in later
|
||||
m.wuint32(0)
|
||||
m.wuint32(0)
|
||||
m.wuint32(0)
|
||||
m.wuint32(0)
|
||||
|
||||
// message header
|
||||
m.wuint32(protocol)
|
||||
m.wuint32(m.id)
|
||||
m.wuint32(m.isRequest)
|
||||
m.wuint32(m.rpc)
|
||||
m.wuint32(m.status)
|
||||
m.wuint32(uint32(len(m.value)))
|
||||
m.wuint32(uint32(len(m.template)))
|
||||
|
||||
// fixed-size templates
|
||||
for i, x := range m.template {
|
||||
var tag, val1, val2 uint32
|
||||
switch x.(type) {
|
||||
default:
|
||||
return errors.New("unexpected template type")
|
||||
case bool:
|
||||
tag = 'b'
|
||||
case []byte:
|
||||
tag = 'C'
|
||||
val1 = uint32(m.size[i])
|
||||
case float64:
|
||||
tag = 'd'
|
||||
case []float64:
|
||||
tag = 'D'
|
||||
val1 = uint32(m.size[i])
|
||||
case int:
|
||||
tag = 'h'
|
||||
case int32:
|
||||
tag = 'i'
|
||||
case []int32:
|
||||
tag = 'I'
|
||||
val1 = uint32(m.size[i])
|
||||
case string:
|
||||
tag = 's'
|
||||
val1 = uint32(m.size[i])
|
||||
}
|
||||
m.wuint32(tag)
|
||||
m.wuint32(0)
|
||||
m.wuint32(val1)
|
||||
m.wuint32(val2)
|
||||
}
|
||||
|
||||
// fixed-size values
|
||||
for _, x := range m.value {
|
||||
var tag, val1, val2 uint32
|
||||
switch x := x.(type) {
|
||||
default:
|
||||
return errors.New("unexpected value type")
|
||||
case bool:
|
||||
tag = 'b'
|
||||
if x {
|
||||
val1 = 1
|
||||
}
|
||||
case []byte:
|
||||
tag = 'C'
|
||||
val1 = uint32(len(x))
|
||||
case float64:
|
||||
tag = 'd'
|
||||
v := float64bits(x)
|
||||
val1 = uint32(v)
|
||||
val2 = uint32(v >> 32)
|
||||
case []float64:
|
||||
tag = 'D'
|
||||
val1 = uint32(len(x))
|
||||
case int32:
|
||||
tag = 'i'
|
||||
m.desc = append(m.desc, x)
|
||||
case []int32:
|
||||
tag = 'I'
|
||||
val1 = uint32(len(x))
|
||||
case string:
|
||||
tag = 's'
|
||||
val1 = uint32(len(x) + 1)
|
||||
}
|
||||
m.wuint32(tag)
|
||||
m.wuint32(0)
|
||||
m.wuint32(val1)
|
||||
m.wuint32(val2)
|
||||
}
|
||||
|
||||
// variable-length data for values
|
||||
for _, x := range m.value {
|
||||
switch x := x.(type) {
|
||||
case []byte:
|
||||
m.wbytes(x)
|
||||
case []float64:
|
||||
for _, f := range x {
|
||||
m.wuint64(float64bits(f))
|
||||
}
|
||||
case []int32:
|
||||
for _, j := range x {
|
||||
m.wuint32(uint32(j))
|
||||
}
|
||||
case string:
|
||||
m.wstring(x)
|
||||
m.wstring("\x00")
|
||||
}
|
||||
}
|
||||
|
||||
// fill in sizes
|
||||
data := m.data
|
||||
m.data = m.data[:0]
|
||||
m.wuint32(uint32(len(data)))
|
||||
m.wuint32(uint32(len(m.desc)))
|
||||
m.wuint32(uint32(len(data)))
|
||||
m.wuint32(uint32(len(m.desc)))
|
||||
m.data = data
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *msg) unpack() error {
|
||||
totalSize := m.uint32()
|
||||
totalDesc := m.uint32()
|
||||
fragSize := m.uint32()
|
||||
fragDesc := m.uint32()
|
||||
if totalSize != fragSize || totalDesc != fragDesc {
|
||||
return errors.New("Native Client: fragmented RPC messages not supported")
|
||||
}
|
||||
if m.uint32() != protocol {
|
||||
return errors.New("Native Client: RPC protocol mismatch")
|
||||
}
|
||||
|
||||
// message header
|
||||
m.id = m.uint32()
|
||||
m.isRequest = m.uint32()
|
||||
m.rpc = m.uint32()
|
||||
m.status = m.uint32()
|
||||
m.value = make([]interface{}, m.uint32())
|
||||
m.template = make([]interface{}, m.uint32())
|
||||
m.size = make([]int, len(m.template))
|
||||
if m.broken {
|
||||
return errors.New("Native Client: malformed message")
|
||||
}
|
||||
|
||||
// fixed-size templates
|
||||
for i := range m.template {
|
||||
tag := m.uint32()
|
||||
m.uint32() // padding
|
||||
val1 := m.uint32()
|
||||
m.uint32() // val2
|
||||
switch tag {
|
||||
default:
|
||||
return errors.New("Native Client: unexpected template type " + string(rune(tag)))
|
||||
case 'b':
|
||||
m.template[i] = false
|
||||
case 'C':
|
||||
m.template[i] = []byte(nil)
|
||||
m.size[i] = int(val1)
|
||||
case 'd':
|
||||
m.template[i] = float64(0)
|
||||
case 'D':
|
||||
m.template[i] = []float64(nil)
|
||||
m.size[i] = int(val1)
|
||||
case 'i':
|
||||
m.template[i] = int32(0)
|
||||
case 'I':
|
||||
m.template[i] = []int32(nil)
|
||||
m.size[i] = int(val1)
|
||||
case 'h':
|
||||
m.template[i] = int(0)
|
||||
case 's':
|
||||
m.template[i] = ""
|
||||
m.size[i] = int(val1)
|
||||
}
|
||||
}
|
||||
|
||||
// fixed-size values
|
||||
var (
|
||||
strsize []uint32
|
||||
d int
|
||||
)
|
||||
for i := range m.value {
|
||||
tag := m.uint32()
|
||||
m.uint32() // padding
|
||||
val1 := m.uint32()
|
||||
val2 := m.uint32()
|
||||
switch tag {
|
||||
default:
|
||||
return errors.New("Native Client: unexpected value type " + string(rune(tag)))
|
||||
case 'b':
|
||||
m.value[i] = val1 > 0
|
||||
case 'C':
|
||||
m.value[i] = []byte(nil)
|
||||
strsize = append(strsize, val1)
|
||||
case 'd':
|
||||
m.value[i] = float64frombits(uint64(val1) | uint64(val2)<<32)
|
||||
case 'D':
|
||||
m.value[i] = make([]float64, val1)
|
||||
case 'i':
|
||||
m.value[i] = int32(val1)
|
||||
case 'I':
|
||||
m.value[i] = make([]int32, val1)
|
||||
case 'h':
|
||||
m.value[i] = int(m.desc[d])
|
||||
d++
|
||||
case 's':
|
||||
m.value[i] = ""
|
||||
strsize = append(strsize, val1)
|
||||
}
|
||||
}
|
||||
|
||||
// variable-sized parts of values
|
||||
for i, x := range m.value {
|
||||
switch x := x.(type) {
|
||||
case []byte:
|
||||
m.value[i] = m.bytes(int(strsize[0]))
|
||||
strsize = strsize[1:]
|
||||
case []float64:
|
||||
for i := range x {
|
||||
x[i] = float64frombits(m.uint64())
|
||||
}
|
||||
case []int32:
|
||||
for i := range x {
|
||||
x[i] = int32(m.uint32())
|
||||
}
|
||||
case string:
|
||||
m.value[i] = string(m.bytes(int(strsize[0])))
|
||||
strsize = strsize[1:]
|
||||
}
|
||||
}
|
||||
|
||||
if len(m.data) > 0 {
|
||||
return errors.New("Native Client: junk at end of message")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func float64bits(x float64) uint64 {
|
||||
return *(*uint64)(unsafe.Pointer(&x))
|
||||
}
|
||||
|
||||
func float64frombits(x uint64) float64 {
|
||||
return *(*float64)(unsafe.Pointer(&x))
|
||||
}
|
||||
|
||||
// At startup, connect to the name service.
|
||||
var nsClient = nsConnect()
|
||||
|
||||
func nsConnect() *srpcClient {
|
||||
var ns int32 = -1
|
||||
_, _, errno := Syscall(sys_nameservice, uintptr(unsafe.Pointer(&ns)), 0, 0)
|
||||
if errno != 0 {
|
||||
println("Native Client nameservice:", errno.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
sock, _, errno := Syscall(sys_imc_connect, uintptr(ns), 0, 0)
|
||||
if errno != 0 {
|
||||
println("Native Client nameservice connect:", errno.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
c, err := newClient(int(sock))
|
||||
if err != nil {
|
||||
println("Native Client nameservice init:", err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
const (
|
||||
nsSuccess = 0
|
||||
nsNameNotFound = 1
|
||||
nsDuplicateName = 2
|
||||
nsInsufficientResources = 3
|
||||
nsPermissionDenied = 4
|
||||
nsInvalidArgument = 5
|
||||
)
|
||||
|
||||
func openNamedService(name string, mode int32) (fd int, err error) {
|
||||
if nsClient == nil {
|
||||
return 0, errors.New("no name service")
|
||||
}
|
||||
ret, err := nsClient.Call("lookup:si:ih", name, int32(mode))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
status := ret[0].(int32)
|
||||
fd = ret[1].(int)
|
||||
switch status {
|
||||
case nsSuccess:
|
||||
// ok
|
||||
case nsNameNotFound:
|
||||
return -1, ENOENT
|
||||
case nsDuplicateName:
|
||||
return -1, EEXIST
|
||||
case nsInsufficientResources:
|
||||
return -1, EWOULDBLOCK
|
||||
case nsPermissionDenied:
|
||||
return -1, EPERM
|
||||
case nsInvalidArgument:
|
||||
return -1, EINVAL
|
||||
default:
|
||||
return -1, EINVAL
|
||||
}
|
||||
return fd, nil
|
||||
}
|
||||
20
unix/str.go
Normal file
20
unix/str.go
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
package syscall
|
||||
|
||||
func itoa(val int) string { // do it here rather than with fmt to avoid dependency
|
||||
if val < 0 {
|
||||
return "-" + itoa(-val)
|
||||
}
|
||||
var buf [32]byte // big enough for int64
|
||||
i := len(buf) - 1
|
||||
for val >= 10 {
|
||||
buf[i] = byte(val%10 + '0')
|
||||
i--
|
||||
val /= 10
|
||||
}
|
||||
buf[i] = byte(val + '0')
|
||||
return string(buf[i:])
|
||||
}
|
||||
81
unix/syscall.go
Normal file
81
unix/syscall.go
Normal file
@@ -0,0 +1,81 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
// Package syscall contains an interface to the low-level operating system
|
||||
// primitives. The details vary depending on the underlying system, and
|
||||
// by default, godoc will display the syscall documentation for the current
|
||||
// system. If you want godoc to display syscall documentation for another
|
||||
// system, set $GOOS and $GOARCH to the desired system. For example, if
|
||||
// you want to view documentation for freebsd/arm on linux/amd64, set $GOOS
|
||||
// to freebsd and $GOARCH to arm.
|
||||
// The primary use of syscall is inside other packages that provide a more
|
||||
// portable interface to the system, such as "os", "time" and "net". Use
|
||||
// those packages rather than this one if you can.
|
||||
// For details of the functions and data types in this package consult
|
||||
// the manuals for the appropriate operating system.
|
||||
// These calls return err == nil to indicate success; otherwise
|
||||
// err is an operating system error describing the failure.
|
||||
// On most systems, that error has type syscall.Errno.
|
||||
package syscall
|
||||
|
||||
// StringByteSlice is deprecated. Use ByteSliceFromString instead.
|
||||
// If s contains a NUL byte this function panics instead of
|
||||
// returning an error.
|
||||
func StringByteSlice(s string) []byte {
|
||||
a, err := ByteSliceFromString(s)
|
||||
if err != nil {
|
||||
panic("syscall: string with NUL passed to StringByteSlice")
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// ByteSliceFromString returns a NUL-terminated slice of bytes
|
||||
// containing the text of s. If s contains a NUL byte at any
|
||||
// location, it returns (nil, EINVAL).
|
||||
func ByteSliceFromString(s string) ([]byte, error) {
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] == 0 {
|
||||
return nil, EINVAL
|
||||
}
|
||||
}
|
||||
a := make([]byte, len(s)+1)
|
||||
copy(a, s)
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// StringBytePtr is deprecated. Use BytePtrFromString instead.
|
||||
// If s contains a NUL byte this function panics instead of
|
||||
// returning an error.
|
||||
func StringBytePtr(s string) *byte { return &StringByteSlice(s)[0] }
|
||||
|
||||
// BytePtrFromString returns a pointer to a NUL-terminated array of
|
||||
// bytes containing the text of s. If s contains a NUL byte at any
|
||||
// location, it returns (nil, EINVAL).
|
||||
func BytePtrFromString(s string) (*byte, error) {
|
||||
a, err := ByteSliceFromString(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &a[0], nil
|
||||
}
|
||||
|
||||
// Single-word zero for use when we need a valid pointer to 0 bytes.
|
||||
// See mksyscall.pl.
|
||||
var _zero uintptr
|
||||
|
||||
func (ts *Timespec) Unix() (sec int64, nsec int64) {
|
||||
return int64(ts.Sec), int64(ts.Nsec)
|
||||
}
|
||||
|
||||
func (tv *Timeval) Unix() (sec int64, nsec int64) {
|
||||
return int64(tv.Sec), int64(tv.Usec) * 1000
|
||||
}
|
||||
|
||||
func (ts *Timespec) Nano() int64 {
|
||||
return int64(ts.Sec)*1e9 + int64(ts.Nsec)
|
||||
}
|
||||
|
||||
func (tv *Timeval) Nano() int64 {
|
||||
return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000
|
||||
}
|
||||
588
unix/syscall_bsd.go
Normal file
588
unix/syscall_bsd.go
Normal file
@@ -0,0 +1,588 @@
|
||||
// Copyright 2009 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 darwin dragonfly freebsd netbsd openbsd
|
||||
|
||||
// BSD system call wrappers shared by *BSD based systems
|
||||
// including OS X (Darwin) and FreeBSD. Like the other
|
||||
// syscall_*.go files it is compiled as Go code but also
|
||||
// used as input to mksyscall which parses the //sys
|
||||
// lines and generates system call stubs.
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
/*
|
||||
* Wrapped
|
||||
*/
|
||||
|
||||
//sysnb getgroups(ngid int, gid *_Gid_t) (n int, err error)
|
||||
//sysnb setgroups(ngid int, gid *_Gid_t) (err error)
|
||||
|
||||
func Getgroups() (gids []int, err error) {
|
||||
n, err := getgroups(0, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Sanity check group count. Max is 16 on BSD.
|
||||
if n < 0 || n > 1000 {
|
||||
return nil, EINVAL
|
||||
}
|
||||
|
||||
a := make([]_Gid_t, n)
|
||||
n, err = getgroups(n, &a[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gids = make([]int, n)
|
||||
for i, v := range a[0:n] {
|
||||
gids[i] = int(v)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Setgroups(gids []int) (err error) {
|
||||
if len(gids) == 0 {
|
||||
return setgroups(0, nil)
|
||||
}
|
||||
|
||||
a := make([]_Gid_t, len(gids))
|
||||
for i, v := range gids {
|
||||
a[i] = _Gid_t(v)
|
||||
}
|
||||
return setgroups(len(a), &a[0])
|
||||
}
|
||||
|
||||
func ReadDirent(fd int, buf []byte) (n int, err error) {
|
||||
// Final argument is (basep *uintptr) and the syscall doesn't take nil.
|
||||
// 64 bits should be enough. (32 bits isn't even on 386). Since the
|
||||
// actual system call is getdirentries64, 64 is a good guess.
|
||||
// TODO(rsc): Can we use a single global basep for all calls?
|
||||
var base = (*uintptr)(unsafe.Pointer(new(uint64)))
|
||||
n, err = Getdirentries(fd, buf, base)
|
||||
|
||||
// On OS X 10.10 Yosemite, if you have a directory that can be returned
|
||||
// in a single getdirentries64 call (for example, a directory with one file),
|
||||
// and you read from the directory at EOF twice, you get EOF both times:
|
||||
// fd = open("dir")
|
||||
// getdirentries64(fd) // returns data
|
||||
// getdirentries64(fd) // returns 0 (EOF)
|
||||
// getdirentries64(fd) // returns 0 (EOF)
|
||||
//
|
||||
// But if you remove the file in the middle between the two calls, the
|
||||
// second call returns an error instead.
|
||||
// fd = open("dir")
|
||||
// getdirentries64(fd) // returns data
|
||||
// getdirentries64(fd) // returns 0 (EOF)
|
||||
// remove("dir/file")
|
||||
// getdirentries64(fd) // returns ENOENT/EINVAL
|
||||
//
|
||||
// Whether you get ENOENT or EINVAL depends on exactly what was
|
||||
// in the directory. It is deterministic, just data-dependent.
|
||||
//
|
||||
// This only happens in small directories. A directory containing more data
|
||||
// than fits in a 4k getdirentries64 call will return EOF correctly.
|
||||
// (It's not clear if the criteria is that the directory be split across multiple
|
||||
// getdirentries64 calls or that it be split across multiple file system blocks.)
|
||||
//
|
||||
// We could change package os to avoid the second read at EOF,
|
||||
// and maybe we should, but that's a bit involved.
|
||||
// For now, treat the EINVAL/ENOENT as EOF.
|
||||
if runtime.GOOS == "darwin" && (err == EINVAL || err == ENOENT) {
|
||||
err = nil
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Wait status is 7 bits at bottom, either 0 (exited),
|
||||
// 0x7F (stopped), or a signal number that caused an exit.
|
||||
// The 0x80 bit is whether there was a core dump.
|
||||
// An extra number (exit code, signal causing a stop)
|
||||
// is in the high bits.
|
||||
|
||||
type WaitStatus uint32
|
||||
|
||||
const (
|
||||
mask = 0x7F
|
||||
core = 0x80
|
||||
shift = 8
|
||||
|
||||
exited = 0
|
||||
stopped = 0x7F
|
||||
)
|
||||
|
||||
func (w WaitStatus) Exited() bool { return w&mask == exited }
|
||||
|
||||
func (w WaitStatus) ExitStatus() int {
|
||||
if w&mask != exited {
|
||||
return -1
|
||||
}
|
||||
return int(w >> shift)
|
||||
}
|
||||
|
||||
func (w WaitStatus) Signaled() bool { return w&mask != stopped && w&mask != 0 }
|
||||
|
||||
func (w WaitStatus) Signal() Signal {
|
||||
sig := Signal(w & mask)
|
||||
if sig == stopped || sig == 0 {
|
||||
return -1
|
||||
}
|
||||
return sig
|
||||
}
|
||||
|
||||
func (w WaitStatus) CoreDump() bool { return w.Signaled() && w&core != 0 }
|
||||
|
||||
func (w WaitStatus) Stopped() bool { return w&mask == stopped && Signal(w>>shift) != SIGSTOP }
|
||||
|
||||
func (w WaitStatus) Continued() bool { return w&mask == stopped && Signal(w>>shift) == SIGSTOP }
|
||||
|
||||
func (w WaitStatus) StopSignal() Signal {
|
||||
if !w.Stopped() {
|
||||
return -1
|
||||
}
|
||||
return Signal(w>>shift) & 0xFF
|
||||
}
|
||||
|
||||
func (w WaitStatus) TrapCause() int { return -1 }
|
||||
|
||||
//sys wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error)
|
||||
|
||||
func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
|
||||
var status _C_int
|
||||
wpid, err = wait4(pid, &status, options, rusage)
|
||||
if wstatus != nil {
|
||||
*wstatus = WaitStatus(status)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
|
||||
//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
|
||||
//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
|
||||
//sysnb socket(domain int, typ int, proto int) (fd int, err error)
|
||||
//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error)
|
||||
//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error)
|
||||
//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
|
||||
//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
|
||||
//sys Shutdown(s int, how int) (err error)
|
||||
|
||||
func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) {
|
||||
if sa.Port < 0 || sa.Port > 0xFFFF {
|
||||
return nil, 0, EINVAL
|
||||
}
|
||||
sa.raw.Len = SizeofSockaddrInet4
|
||||
sa.raw.Family = AF_INET
|
||||
p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
|
||||
p[0] = byte(sa.Port >> 8)
|
||||
p[1] = byte(sa.Port)
|
||||
for i := 0; i < len(sa.Addr); i++ {
|
||||
sa.raw.Addr[i] = sa.Addr[i]
|
||||
}
|
||||
return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil
|
||||
}
|
||||
|
||||
func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) {
|
||||
if sa.Port < 0 || sa.Port > 0xFFFF {
|
||||
return nil, 0, EINVAL
|
||||
}
|
||||
sa.raw.Len = SizeofSockaddrInet6
|
||||
sa.raw.Family = AF_INET6
|
||||
p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
|
||||
p[0] = byte(sa.Port >> 8)
|
||||
p[1] = byte(sa.Port)
|
||||
sa.raw.Scope_id = sa.ZoneId
|
||||
for i := 0; i < len(sa.Addr); i++ {
|
||||
sa.raw.Addr[i] = sa.Addr[i]
|
||||
}
|
||||
return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil
|
||||
}
|
||||
|
||||
func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) {
|
||||
name := sa.Name
|
||||
n := len(name)
|
||||
if n >= len(sa.raw.Path) || n == 0 {
|
||||
return nil, 0, EINVAL
|
||||
}
|
||||
sa.raw.Len = byte(3 + n) // 2 for Family, Len; 1 for NUL
|
||||
sa.raw.Family = AF_UNIX
|
||||
for i := 0; i < n; i++ {
|
||||
sa.raw.Path[i] = int8(name[i])
|
||||
}
|
||||
return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil
|
||||
}
|
||||
|
||||
func (sa *SockaddrDatalink) sockaddr() (unsafe.Pointer, _Socklen, error) {
|
||||
if sa.Index == 0 {
|
||||
return nil, 0, EINVAL
|
||||
}
|
||||
sa.raw.Len = sa.Len
|
||||
sa.raw.Family = AF_LINK
|
||||
sa.raw.Index = sa.Index
|
||||
sa.raw.Type = sa.Type
|
||||
sa.raw.Nlen = sa.Nlen
|
||||
sa.raw.Alen = sa.Alen
|
||||
sa.raw.Slen = sa.Slen
|
||||
for i := 0; i < len(sa.raw.Data); i++ {
|
||||
sa.raw.Data[i] = sa.Data[i]
|
||||
}
|
||||
return unsafe.Pointer(&sa.raw), SizeofSockaddrDatalink, nil
|
||||
}
|
||||
|
||||
func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
|
||||
switch rsa.Addr.Family {
|
||||
case AF_LINK:
|
||||
pp := (*RawSockaddrDatalink)(unsafe.Pointer(rsa))
|
||||
sa := new(SockaddrDatalink)
|
||||
sa.Len = pp.Len
|
||||
sa.Family = pp.Family
|
||||
sa.Index = pp.Index
|
||||
sa.Type = pp.Type
|
||||
sa.Nlen = pp.Nlen
|
||||
sa.Alen = pp.Alen
|
||||
sa.Slen = pp.Slen
|
||||
for i := 0; i < len(sa.Data); i++ {
|
||||
sa.Data[i] = pp.Data[i]
|
||||
}
|
||||
return sa, nil
|
||||
|
||||
case AF_UNIX:
|
||||
pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
|
||||
if pp.Len < 2 || pp.Len > SizeofSockaddrUnix {
|
||||
return nil, EINVAL
|
||||
}
|
||||
sa := new(SockaddrUnix)
|
||||
|
||||
// Some BSDs include the trailing NUL in the length, whereas
|
||||
// others do not. Work around this by subtracting the leading
|
||||
// family and len. The path is then scanned to see if a NUL
|
||||
// terminator still exists within the length.
|
||||
n := int(pp.Len) - 2 // subtract leading Family, Len
|
||||
for i := 0; i < n; i++ {
|
||||
if pp.Path[i] == 0 {
|
||||
// found early NUL; assume Len included the NUL
|
||||
// or was overestimating.
|
||||
n = i
|
||||
break
|
||||
}
|
||||
}
|
||||
bytes := (*[10000]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
|
||||
sa.Name = string(bytes)
|
||||
return sa, nil
|
||||
|
||||
case AF_INET:
|
||||
pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))
|
||||
sa := new(SockaddrInet4)
|
||||
p := (*[2]byte)(unsafe.Pointer(&pp.Port))
|
||||
sa.Port = int(p[0])<<8 + int(p[1])
|
||||
for i := 0; i < len(sa.Addr); i++ {
|
||||
sa.Addr[i] = pp.Addr[i]
|
||||
}
|
||||
return sa, nil
|
||||
|
||||
case AF_INET6:
|
||||
pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa))
|
||||
sa := new(SockaddrInet6)
|
||||
p := (*[2]byte)(unsafe.Pointer(&pp.Port))
|
||||
sa.Port = int(p[0])<<8 + int(p[1])
|
||||
sa.ZoneId = pp.Scope_id
|
||||
for i := 0; i < len(sa.Addr); i++ {
|
||||
sa.Addr[i] = pp.Addr[i]
|
||||
}
|
||||
return sa, nil
|
||||
}
|
||||
return nil, EAFNOSUPPORT
|
||||
}
|
||||
|
||||
func Accept(fd int) (nfd int, sa Sockaddr, err error) {
|
||||
var rsa RawSockaddrAny
|
||||
var len _Socklen = SizeofSockaddrAny
|
||||
nfd, err = accept(fd, &rsa, &len)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if runtime.GOOS == "darwin" && len == 0 {
|
||||
// Accepted socket has no address.
|
||||
// This is likely due to a bug in xnu kernels,
|
||||
// where instead of ECONNABORTED error socket
|
||||
// is accepted, but has no address.
|
||||
Close(nfd)
|
||||
return 0, nil, ECONNABORTED
|
||||
}
|
||||
sa, err = anyToSockaddr(&rsa)
|
||||
if err != nil {
|
||||
Close(nfd)
|
||||
nfd = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Getsockname(fd int) (sa Sockaddr, err error) {
|
||||
var rsa RawSockaddrAny
|
||||
var len _Socklen = SizeofSockaddrAny
|
||||
if err = getsockname(fd, &rsa, &len); err != nil {
|
||||
return
|
||||
}
|
||||
// TODO(jsing): DragonFly has a "bug" (see issue 3349), which should be
|
||||
// reported upstream.
|
||||
if runtime.GOOS == "dragonfly" && rsa.Addr.Family == AF_UNSPEC && rsa.Addr.Len == 0 {
|
||||
rsa.Addr.Family = AF_UNIX
|
||||
rsa.Addr.Len = SizeofSockaddrUnix
|
||||
}
|
||||
return anyToSockaddr(&rsa)
|
||||
}
|
||||
|
||||
//sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error)
|
||||
|
||||
func GetsockoptByte(fd, level, opt int) (value byte, err error) {
|
||||
var n byte
|
||||
vallen := _Socklen(1)
|
||||
err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func GetsockoptInet4Addr(fd, level, opt int) (value [4]byte, err error) {
|
||||
vallen := _Socklen(4)
|
||||
err = getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen)
|
||||
return value, err
|
||||
}
|
||||
|
||||
func GetsockoptIPMreq(fd, level, opt int) (*IPMreq, error) {
|
||||
var value IPMreq
|
||||
vallen := _Socklen(SizeofIPMreq)
|
||||
err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
|
||||
return &value, err
|
||||
}
|
||||
|
||||
func GetsockoptIPv6Mreq(fd, level, opt int) (*IPv6Mreq, error) {
|
||||
var value IPv6Mreq
|
||||
vallen := _Socklen(SizeofIPv6Mreq)
|
||||
err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
|
||||
return &value, err
|
||||
}
|
||||
|
||||
func GetsockoptIPv6MTUInfo(fd, level, opt int) (*IPv6MTUInfo, error) {
|
||||
var value IPv6MTUInfo
|
||||
vallen := _Socklen(SizeofIPv6MTUInfo)
|
||||
err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
|
||||
return &value, err
|
||||
}
|
||||
|
||||
func GetsockoptICMPv6Filter(fd, level, opt int) (*ICMPv6Filter, error) {
|
||||
var value ICMPv6Filter
|
||||
vallen := _Socklen(SizeofICMPv6Filter)
|
||||
err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
|
||||
return &value, err
|
||||
}
|
||||
|
||||
//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
|
||||
//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error)
|
||||
//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
|
||||
|
||||
func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
|
||||
var msg Msghdr
|
||||
var rsa RawSockaddrAny
|
||||
msg.Name = (*byte)(unsafe.Pointer(&rsa))
|
||||
msg.Namelen = uint32(SizeofSockaddrAny)
|
||||
var iov Iovec
|
||||
if len(p) > 0 {
|
||||
iov.Base = (*byte)(unsafe.Pointer(&p[0]))
|
||||
iov.SetLen(len(p))
|
||||
}
|
||||
var dummy byte
|
||||
if len(oob) > 0 {
|
||||
// receive at least one normal byte
|
||||
if len(p) == 0 {
|
||||
iov.Base = &dummy
|
||||
iov.SetLen(1)
|
||||
}
|
||||
msg.Control = (*byte)(unsafe.Pointer(&oob[0]))
|
||||
msg.SetControllen(len(oob))
|
||||
}
|
||||
msg.Iov = &iov
|
||||
msg.Iovlen = 1
|
||||
if n, err = recvmsg(fd, &msg, flags); err != nil {
|
||||
return
|
||||
}
|
||||
oobn = int(msg.Controllen)
|
||||
recvflags = int(msg.Flags)
|
||||
// source address is only specified if the socket is unconnected
|
||||
if rsa.Addr.Family != AF_UNSPEC {
|
||||
from, err = anyToSockaddr(&rsa)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
|
||||
|
||||
func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
|
||||
_, err = SendmsgN(fd, p, oob, to, flags)
|
||||
return
|
||||
}
|
||||
|
||||
func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
|
||||
var ptr unsafe.Pointer
|
||||
var salen _Socklen
|
||||
if to != nil {
|
||||
ptr, salen, err = to.sockaddr()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
var msg Msghdr
|
||||
msg.Name = (*byte)(unsafe.Pointer(ptr))
|
||||
msg.Namelen = uint32(salen)
|
||||
var iov Iovec
|
||||
if len(p) > 0 {
|
||||
iov.Base = (*byte)(unsafe.Pointer(&p[0]))
|
||||
iov.SetLen(len(p))
|
||||
}
|
||||
var dummy byte
|
||||
if len(oob) > 0 {
|
||||
// send at least one normal byte
|
||||
if len(p) == 0 {
|
||||
iov.Base = &dummy
|
||||
iov.SetLen(1)
|
||||
}
|
||||
msg.Control = (*byte)(unsafe.Pointer(&oob[0]))
|
||||
msg.SetControllen(len(oob))
|
||||
}
|
||||
msg.Iov = &iov
|
||||
msg.Iovlen = 1
|
||||
if n, err = sendmsg(fd, &msg, flags); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if len(oob) > 0 && len(p) == 0 {
|
||||
n = 0
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
//sys kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error)
|
||||
|
||||
func Kevent(kq int, changes, events []Kevent_t, timeout *Timespec) (n int, err error) {
|
||||
var change, event unsafe.Pointer
|
||||
if len(changes) > 0 {
|
||||
change = unsafe.Pointer(&changes[0])
|
||||
}
|
||||
if len(events) > 0 {
|
||||
event = unsafe.Pointer(&events[0])
|
||||
}
|
||||
return kevent(kq, change, len(changes), event, len(events), timeout)
|
||||
}
|
||||
|
||||
//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL
|
||||
|
||||
func Sysctl(name string) (value string, err error) {
|
||||
// Translate name to mib number.
|
||||
mib, err := nametomib(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Find size.
|
||||
n := uintptr(0)
|
||||
if err = sysctl(mib, nil, &n, nil, 0); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if n == 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// Read into buffer of that size.
|
||||
buf := make([]byte, n)
|
||||
if err = sysctl(mib, &buf[0], &n, nil, 0); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Throw away terminating NUL.
|
||||
if n > 0 && buf[n-1] == '\x00' {
|
||||
n--
|
||||
}
|
||||
return string(buf[0:n]), nil
|
||||
}
|
||||
|
||||
func SysctlUint32(name string) (value uint32, err error) {
|
||||
// Translate name to mib number.
|
||||
mib, err := nametomib(name)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Read into buffer of that size.
|
||||
n := uintptr(4)
|
||||
buf := make([]byte, 4)
|
||||
if err = sysctl(mib, &buf[0], &n, nil, 0); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if n != 4 {
|
||||
return 0, EIO
|
||||
}
|
||||
return *(*uint32)(unsafe.Pointer(&buf[0])), nil
|
||||
}
|
||||
|
||||
//sys utimes(path string, timeval *[2]Timeval) (err error)
|
||||
|
||||
func Utimes(path string, tv []Timeval) (err error) {
|
||||
if len(tv) != 2 {
|
||||
return EINVAL
|
||||
}
|
||||
return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
|
||||
}
|
||||
|
||||
func UtimesNano(path string, ts []Timespec) error {
|
||||
// TODO: The BSDs can do utimensat with SYS_UTIMENSAT but it
|
||||
// isn't supported by darwin so this uses utimes instead
|
||||
if len(ts) != 2 {
|
||||
return EINVAL
|
||||
}
|
||||
// Not as efficient as it could be because Timespec and
|
||||
// Timeval have different types in the different OSes
|
||||
tv := [2]Timeval{
|
||||
NsecToTimeval(TimespecToNsec(ts[0])),
|
||||
NsecToTimeval(TimespecToNsec(ts[1])),
|
||||
}
|
||||
return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
|
||||
}
|
||||
|
||||
//sys futimes(fd int, timeval *[2]Timeval) (err error)
|
||||
|
||||
func Futimes(fd int, tv []Timeval) (err error) {
|
||||
if len(tv) != 2 {
|
||||
return EINVAL
|
||||
}
|
||||
return futimes(fd, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
|
||||
}
|
||||
|
||||
//sys fcntl(fd int, cmd int, arg int) (val int, err error)
|
||||
|
||||
// TODO: wrap
|
||||
// Acct(name nil-string) (err error)
|
||||
// Gethostuuid(uuid *byte, timeout *Timespec) (err error)
|
||||
// Madvise(addr *byte, len int, behav int) (err error)
|
||||
// Mprotect(addr *byte, len int, prot int) (err error)
|
||||
// Msync(addr *byte, len int, flags int) (err error)
|
||||
// Ptrace(req int, pid int, addr uintptr, data int) (ret uintptr, err error)
|
||||
|
||||
var mapper = &mmapper{
|
||||
active: make(map[*byte][]byte),
|
||||
mmap: mmap,
|
||||
munmap: munmap,
|
||||
}
|
||||
|
||||
func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
|
||||
return mapper.Mmap(fd, offset, length, prot, flags)
|
||||
}
|
||||
|
||||
func Munmap(b []byte) (err error) {
|
||||
return mapper.Munmap(b)
|
||||
}
|
||||
34
unix/syscall_bsd_test.go
Normal file
34
unix/syscall_bsd_test.go
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright 2014 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 darwin dragonfly freebsd openbsd
|
||||
|
||||
package syscall_test
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const MNT_WAIT = 1
|
||||
|
||||
func TestGetfsstat(t *testing.T) {
|
||||
n, err := syscall.Getfsstat(nil, MNT_WAIT)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
data := make([]syscall.Statfs_t, n)
|
||||
n, err = syscall.Getfsstat(data, MNT_WAIT)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
empty := syscall.Statfs_t{}
|
||||
for _, stat := range data {
|
||||
if stat == empty {
|
||||
t.Fatal("an empty Statfs_t struct was returned")
|
||||
}
|
||||
}
|
||||
}
|
||||
508
unix/syscall_darwin.go
Normal file
508
unix/syscall_darwin.go
Normal file
@@ -0,0 +1,508 @@
|
||||
// Copyright 2009,2010 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.
|
||||
|
||||
// Darwin system calls.
|
||||
// This file is compiled as ordinary Go code,
|
||||
// but it is also input to mksyscall,
|
||||
// which parses the //sys lines and generates system call stubs.
|
||||
// Note that sometimes we use a lowercase //sys name and wrap
|
||||
// it in our own nicer implementation, either here or in
|
||||
// syscall_bsd.go or syscall_unix.go.
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
errorspkg "errors"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const ImplementsGetwd = true
|
||||
|
||||
func Getwd() (string, error) {
|
||||
buf := make([]byte, 2048)
|
||||
attrs, err := getAttrList(".", attrList{CommonAttr: attrCmnFullpath}, buf, 0)
|
||||
if err == nil && len(attrs) == 1 && len(attrs[0]) >= 2 {
|
||||
wd := string(attrs[0])
|
||||
// Sanity check that it's an absolute path and ends
|
||||
// in a null byte, which we then strip.
|
||||
if wd[0] == '/' && wd[len(wd)-1] == 0 {
|
||||
return wd[:len(wd)-1], nil
|
||||
}
|
||||
}
|
||||
// If pkg/os/getwd.go gets ENOTSUP, it will fall back to the
|
||||
// slow algorithm.
|
||||
return "", ENOTSUP
|
||||
}
|
||||
|
||||
type SockaddrDatalink struct {
|
||||
Len uint8
|
||||
Family uint8
|
||||
Index uint16
|
||||
Type uint8
|
||||
Nlen uint8
|
||||
Alen uint8
|
||||
Slen uint8
|
||||
Data [12]int8
|
||||
raw RawSockaddrDatalink
|
||||
}
|
||||
|
||||
// Translate "kern.hostname" to []_C_int{0,1,2,3}.
|
||||
func nametomib(name string) (mib []_C_int, err error) {
|
||||
const siz = unsafe.Sizeof(mib[0])
|
||||
|
||||
// NOTE(rsc): It seems strange to set the buffer to have
|
||||
// size CTL_MAXNAME+2 but use only CTL_MAXNAME
|
||||
// as the size. I don't know why the +2 is here, but the
|
||||
// kernel uses +2 for its own implementation of this function.
|
||||
// I am scared that if we don't include the +2 here, the kernel
|
||||
// will silently write 2 words farther than we specify
|
||||
// and we'll get memory corruption.
|
||||
var buf [CTL_MAXNAME + 2]_C_int
|
||||
n := uintptr(CTL_MAXNAME) * siz
|
||||
|
||||
p := (*byte)(unsafe.Pointer(&buf[0]))
|
||||
bytes, err := ByteSliceFromString(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Magic sysctl: "setting" 0.3 to a string name
|
||||
// lets you read back the array of integers form.
|
||||
if err = sysctl([]_C_int{0, 3}, p, &n, &bytes[0], uintptr(len(name))); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf[0 : n/siz], nil
|
||||
}
|
||||
|
||||
// ParseDirent parses up to max directory entries in buf,
|
||||
// appending the names to names. It returns the number
|
||||
// bytes consumed from buf, the number of entries added
|
||||
// to names, and the new names slice.
|
||||
func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
|
||||
origlen := len(buf)
|
||||
for max != 0 && len(buf) > 0 {
|
||||
dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
|
||||
if dirent.Reclen == 0 {
|
||||
buf = nil
|
||||
break
|
||||
}
|
||||
buf = buf[dirent.Reclen:]
|
||||
if dirent.Ino == 0 { // File absent in directory.
|
||||
continue
|
||||
}
|
||||
bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
|
||||
var name = string(bytes[0:dirent.Namlen])
|
||||
if name == "." || name == ".." { // Useless names
|
||||
continue
|
||||
}
|
||||
max--
|
||||
count++
|
||||
names = append(names, name)
|
||||
}
|
||||
return origlen - len(buf), count, names
|
||||
}
|
||||
|
||||
//sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error)
|
||||
func PtraceAttach(pid int) (err error) { return ptrace(PT_ATTACH, pid, 0, 0) }
|
||||
func PtraceDetach(pid int) (err error) { return ptrace(PT_DETACH, pid, 0, 0) }
|
||||
|
||||
const (
|
||||
attrBitMapCount = 5
|
||||
attrCmnFullpath = 0x08000000
|
||||
)
|
||||
|
||||
type attrList struct {
|
||||
bitmapCount uint16
|
||||
_ uint16
|
||||
CommonAttr uint32
|
||||
VolAttr uint32
|
||||
DirAttr uint32
|
||||
FileAttr uint32
|
||||
Forkattr uint32
|
||||
}
|
||||
|
||||
func getAttrList(path string, attrList attrList, attrBuf []byte, options uint) (attrs [][]byte, err error) {
|
||||
if len(attrBuf) < 4 {
|
||||
return nil, errorspkg.New("attrBuf too small")
|
||||
}
|
||||
attrList.bitmapCount = attrBitMapCount
|
||||
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, _, e1 := Syscall6(
|
||||
SYS_GETATTRLIST,
|
||||
uintptr(unsafe.Pointer(_p0)),
|
||||
uintptr(unsafe.Pointer(&attrList)),
|
||||
uintptr(unsafe.Pointer(&attrBuf[0])),
|
||||
uintptr(len(attrBuf)),
|
||||
uintptr(options),
|
||||
0,
|
||||
)
|
||||
if e1 != 0 {
|
||||
return nil, e1
|
||||
}
|
||||
size := *(*uint32)(unsafe.Pointer(&attrBuf[0]))
|
||||
|
||||
// dat is the section of attrBuf that contains valid data,
|
||||
// without the 4 byte length header. All attribute offsets
|
||||
// are relative to dat.
|
||||
dat := attrBuf
|
||||
if int(size) < len(attrBuf) {
|
||||
dat = dat[:size]
|
||||
}
|
||||
dat = dat[4:] // remove length prefix
|
||||
|
||||
for i := uint32(0); int(i) < len(dat); {
|
||||
header := dat[i:]
|
||||
if len(header) < 8 {
|
||||
return attrs, errorspkg.New("truncated attribute header")
|
||||
}
|
||||
datOff := *(*int32)(unsafe.Pointer(&header[0]))
|
||||
attrLen := *(*uint32)(unsafe.Pointer(&header[4]))
|
||||
if datOff < 0 || uint32(datOff)+attrLen > uint32(len(dat)) {
|
||||
return attrs, errorspkg.New("truncated results; attrBuf too small")
|
||||
}
|
||||
end := uint32(datOff) + attrLen
|
||||
attrs = append(attrs, dat[datOff:end])
|
||||
i = end
|
||||
if r := i % 4; r != 0 {
|
||||
i += (4 - r)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//sysnb pipe() (r int, w int, err error)
|
||||
|
||||
func Pipe(p []int) (err error) {
|
||||
if len(p) != 2 {
|
||||
return EINVAL
|
||||
}
|
||||
p[0], p[1], err = pipe()
|
||||
return
|
||||
}
|
||||
|
||||
func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
var bufsize uintptr
|
||||
if len(buf) > 0 {
|
||||
_p0 = unsafe.Pointer(&buf[0])
|
||||
bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_GETFSSTAT64, uintptr(_p0), bufsize, uintptr(flags))
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapped
|
||||
*/
|
||||
|
||||
//sys kill(pid int, signum int, posix int) (err error)
|
||||
|
||||
func Kill(pid int, signum Signal) (err error) { return kill(pid, int(signum), 1) }
|
||||
|
||||
/*
|
||||
* Exposed directly
|
||||
*/
|
||||
//sys Access(path string, mode uint32) (err error)
|
||||
//sys Adjtime(delta *Timeval, olddelta *Timeval) (err error)
|
||||
//sys Chdir(path string) (err error)
|
||||
//sys Chflags(path string, flags int) (err error)
|
||||
//sys Chmod(path string, mode uint32) (err error)
|
||||
//sys Chown(path string, uid int, gid int) (err error)
|
||||
//sys Chroot(path string) (err error)
|
||||
//sys Close(fd int) (err error)
|
||||
//sysnb Dup(fd int) (nfd int, err error)
|
||||
//sysnb Dup2(from int, to int) (err error)
|
||||
//sys Exchangedata(path1 string, path2 string, options int) (err error)
|
||||
//sys Exit(code int)
|
||||
//sys Fchdir(fd int) (err error)
|
||||
//sys Fchflags(fd int, flags int) (err error)
|
||||
//sys Fchmod(fd int, mode uint32) (err error)
|
||||
//sys Fchown(fd int, uid int, gid int) (err error)
|
||||
//sys Flock(fd int, how int) (err error)
|
||||
//sys Fpathconf(fd int, name int) (val int, err error)
|
||||
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
|
||||
//sys Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_FSTATFS64
|
||||
//sys Fsync(fd int) (err error)
|
||||
//sys Ftruncate(fd int, length int64) (err error)
|
||||
//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) = SYS_GETDIRENTRIES64
|
||||
//sys Getdtablesize() (size int)
|
||||
//sysnb Getegid() (egid int)
|
||||
//sysnb Geteuid() (uid int)
|
||||
//sysnb Getgid() (gid int)
|
||||
//sysnb Getpgid(pid int) (pgid int, err error)
|
||||
//sysnb Getpgrp() (pgrp int)
|
||||
//sysnb Getpid() (pid int)
|
||||
//sysnb Getppid() (ppid int)
|
||||
//sys Getpriority(which int, who int) (prio int, err error)
|
||||
//sysnb Getrlimit(which int, lim *Rlimit) (err error)
|
||||
//sysnb Getrusage(who int, rusage *Rusage) (err error)
|
||||
//sysnb Getsid(pid int) (sid int, err error)
|
||||
//sysnb Getuid() (uid int)
|
||||
//sysnb Issetugid() (tainted bool)
|
||||
//sys Kqueue() (fd int, err error)
|
||||
//sys Lchown(path string, uid int, gid int) (err error)
|
||||
//sys Link(path string, link string) (err error)
|
||||
//sys Listen(s int, backlog int) (err error)
|
||||
//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
|
||||
//sys Mkdir(path string, mode uint32) (err error)
|
||||
//sys Mkfifo(path string, mode uint32) (err error)
|
||||
//sys Mknod(path string, mode uint32, dev int) (err error)
|
||||
//sys Mlock(b []byte) (err error)
|
||||
//sys Mlockall(flags int) (err error)
|
||||
//sys Mprotect(b []byte, prot int) (err error)
|
||||
//sys Munlock(b []byte) (err error)
|
||||
//sys Munlockall() (err error)
|
||||
//sys Open(path string, mode int, perm uint32) (fd int, err error)
|
||||
//sys Pathconf(path string, name int) (val int, err error)
|
||||
//sys Pread(fd int, p []byte, offset int64) (n int, err error)
|
||||
//sys Pwrite(fd int, p []byte, offset int64) (n int, err error)
|
||||
//sys read(fd int, p []byte) (n int, err error)
|
||||
//sys Readlink(path string, buf []byte) (n int, err error)
|
||||
//sys Rename(from string, to string) (err error)
|
||||
//sys Revoke(path string) (err error)
|
||||
//sys Rmdir(path string) (err error)
|
||||
//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK
|
||||
//sys Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error)
|
||||
//sys Setegid(egid int) (err error)
|
||||
//sysnb Seteuid(euid int) (err error)
|
||||
//sysnb Setgid(gid int) (err error)
|
||||
//sys Setlogin(name string) (err error)
|
||||
//sysnb Setpgid(pid int, pgid int) (err error)
|
||||
//sys Setpriority(which int, who int, prio int) (err error)
|
||||
//sys Setprivexec(flag int) (err error)
|
||||
//sysnb Setregid(rgid int, egid int) (err error)
|
||||
//sysnb Setreuid(ruid int, euid int) (err error)
|
||||
//sysnb Setrlimit(which int, lim *Rlimit) (err error)
|
||||
//sysnb Setsid() (pid int, err error)
|
||||
//sysnb Settimeofday(tp *Timeval) (err error)
|
||||
//sysnb Setuid(uid int) (err error)
|
||||
//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
|
||||
//sys Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64
|
||||
//sys Symlink(path string, link string) (err error)
|
||||
//sys Sync() (err error)
|
||||
//sys Truncate(path string, length int64) (err error)
|
||||
//sys Umask(newmask int) (oldmask int)
|
||||
//sys Undelete(path string) (err error)
|
||||
//sys Unlink(path string) (err error)
|
||||
//sys Unmount(path string, flags int) (err error)
|
||||
//sys write(fd int, p []byte) (n int, err error)
|
||||
//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
|
||||
//sys munmap(addr uintptr, length uintptr) (err error)
|
||||
//sys readlen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_READ
|
||||
//sys writelen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_WRITE
|
||||
|
||||
/*
|
||||
* Unimplemented
|
||||
*/
|
||||
// Profil
|
||||
// Sigaction
|
||||
// Sigprocmask
|
||||
// Getlogin
|
||||
// Sigpending
|
||||
// Sigaltstack
|
||||
// Ioctl
|
||||
// Reboot
|
||||
// Execve
|
||||
// Vfork
|
||||
// Sbrk
|
||||
// Sstk
|
||||
// Ovadvise
|
||||
// Mincore
|
||||
// Setitimer
|
||||
// Swapon
|
||||
// Select
|
||||
// Sigsuspend
|
||||
// Readv
|
||||
// Writev
|
||||
// Nfssvc
|
||||
// Getfh
|
||||
// Quotactl
|
||||
// Mount
|
||||
// Csops
|
||||
// Waitid
|
||||
// Add_profil
|
||||
// Kdebug_trace
|
||||
// Sigreturn
|
||||
// Mmap
|
||||
// Mlock
|
||||
// Munlock
|
||||
// Atsocket
|
||||
// Kqueue_from_portset_np
|
||||
// Kqueue_portset
|
||||
// Getattrlist
|
||||
// Setattrlist
|
||||
// Getdirentriesattr
|
||||
// Searchfs
|
||||
// Delete
|
||||
// Copyfile
|
||||
// Poll
|
||||
// Watchevent
|
||||
// Waitevent
|
||||
// Modwatch
|
||||
// Getxattr
|
||||
// Fgetxattr
|
||||
// Setxattr
|
||||
// Fsetxattr
|
||||
// Removexattr
|
||||
// Fremovexattr
|
||||
// Listxattr
|
||||
// Flistxattr
|
||||
// Fsctl
|
||||
// Initgroups
|
||||
// Posix_spawn
|
||||
// Nfsclnt
|
||||
// Fhopen
|
||||
// Minherit
|
||||
// Semsys
|
||||
// Msgsys
|
||||
// Shmsys
|
||||
// Semctl
|
||||
// Semget
|
||||
// Semop
|
||||
// Msgctl
|
||||
// Msgget
|
||||
// Msgsnd
|
||||
// Msgrcv
|
||||
// Shmat
|
||||
// Shmctl
|
||||
// Shmdt
|
||||
// Shmget
|
||||
// Shm_open
|
||||
// Shm_unlink
|
||||
// Sem_open
|
||||
// Sem_close
|
||||
// Sem_unlink
|
||||
// Sem_wait
|
||||
// Sem_trywait
|
||||
// Sem_post
|
||||
// Sem_getvalue
|
||||
// Sem_init
|
||||
// Sem_destroy
|
||||
// Open_extended
|
||||
// Umask_extended
|
||||
// Stat_extended
|
||||
// Lstat_extended
|
||||
// Fstat_extended
|
||||
// Chmod_extended
|
||||
// Fchmod_extended
|
||||
// Access_extended
|
||||
// Settid
|
||||
// Gettid
|
||||
// Setsgroups
|
||||
// Getsgroups
|
||||
// Setwgroups
|
||||
// Getwgroups
|
||||
// Mkfifo_extended
|
||||
// Mkdir_extended
|
||||
// Identitysvc
|
||||
// Shared_region_check_np
|
||||
// Shared_region_map_np
|
||||
// __pthread_mutex_destroy
|
||||
// __pthread_mutex_init
|
||||
// __pthread_mutex_lock
|
||||
// __pthread_mutex_trylock
|
||||
// __pthread_mutex_unlock
|
||||
// __pthread_cond_init
|
||||
// __pthread_cond_destroy
|
||||
// __pthread_cond_broadcast
|
||||
// __pthread_cond_signal
|
||||
// Setsid_with_pid
|
||||
// __pthread_cond_timedwait
|
||||
// Aio_fsync
|
||||
// Aio_return
|
||||
// Aio_suspend
|
||||
// Aio_cancel
|
||||
// Aio_error
|
||||
// Aio_read
|
||||
// Aio_write
|
||||
// Lio_listio
|
||||
// __pthread_cond_wait
|
||||
// Iopolicysys
|
||||
// Mlockall
|
||||
// Munlockall
|
||||
// __pthread_kill
|
||||
// __pthread_sigmask
|
||||
// __sigwait
|
||||
// __disable_threadsignal
|
||||
// __pthread_markcancel
|
||||
// __pthread_canceled
|
||||
// __semwait_signal
|
||||
// Proc_info
|
||||
// sendfile
|
||||
// Stat64_extended
|
||||
// Lstat64_extended
|
||||
// Fstat64_extended
|
||||
// __pthread_chdir
|
||||
// __pthread_fchdir
|
||||
// Audit
|
||||
// Auditon
|
||||
// Getauid
|
||||
// Setauid
|
||||
// Getaudit
|
||||
// Setaudit
|
||||
// Getaudit_addr
|
||||
// Setaudit_addr
|
||||
// Auditctl
|
||||
// Bsdthread_create
|
||||
// Bsdthread_terminate
|
||||
// Stack_snapshot
|
||||
// Bsdthread_register
|
||||
// Workq_open
|
||||
// Workq_ops
|
||||
// __mac_execve
|
||||
// __mac_syscall
|
||||
// __mac_get_file
|
||||
// __mac_set_file
|
||||
// __mac_get_link
|
||||
// __mac_set_link
|
||||
// __mac_get_proc
|
||||
// __mac_set_proc
|
||||
// __mac_get_fd
|
||||
// __mac_set_fd
|
||||
// __mac_get_pid
|
||||
// __mac_get_lcid
|
||||
// __mac_get_lctx
|
||||
// __mac_set_lctx
|
||||
// Setlcid
|
||||
// Read_nocancel
|
||||
// Write_nocancel
|
||||
// Open_nocancel
|
||||
// Close_nocancel
|
||||
// Wait4_nocancel
|
||||
// Recvmsg_nocancel
|
||||
// Sendmsg_nocancel
|
||||
// Recvfrom_nocancel
|
||||
// Accept_nocancel
|
||||
// Msync_nocancel
|
||||
// Fcntl_nocancel
|
||||
// Select_nocancel
|
||||
// Fsync_nocancel
|
||||
// Connect_nocancel
|
||||
// Sigsuspend_nocancel
|
||||
// Readv_nocancel
|
||||
// Writev_nocancel
|
||||
// Sendto_nocancel
|
||||
// Pread_nocancel
|
||||
// Pwrite_nocancel
|
||||
// Waitid_nocancel
|
||||
// Poll_nocancel
|
||||
// Msgsnd_nocancel
|
||||
// Msgrcv_nocancel
|
||||
// Sem_wait_nocancel
|
||||
// Aio_suspend_nocancel
|
||||
// __sigwait_nocancel
|
||||
// __semwait_signal_nocancel
|
||||
// __mac_mount
|
||||
// __mac_get_mount
|
||||
// __mac_getfsstat
|
||||
70
unix/syscall_darwin_386.go
Normal file
70
unix/syscall_darwin_386.go
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func Getpagesize() int { return 4096 }
|
||||
|
||||
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
|
||||
|
||||
func NsecToTimespec(nsec int64) (ts Timespec) {
|
||||
ts.Sec = int32(nsec / 1e9)
|
||||
ts.Nsec = int32(nsec % 1e9)
|
||||
return
|
||||
}
|
||||
|
||||
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
|
||||
|
||||
func NsecToTimeval(nsec int64) (tv Timeval) {
|
||||
nsec += 999 // round up to microsecond
|
||||
tv.Usec = int32(nsec % 1e9 / 1e3)
|
||||
tv.Sec = int32(nsec / 1e9)
|
||||
return
|
||||
}
|
||||
|
||||
//sysnb gettimeofday(tp *Timeval) (sec int32, usec int32, err error)
|
||||
func Gettimeofday(tv *Timeval) (err error) {
|
||||
// The tv passed to gettimeofday must be non-nil
|
||||
// but is otherwise unused. The answers come back
|
||||
// in the two registers.
|
||||
sec, usec, err := gettimeofday(tv)
|
||||
tv.Sec = int32(sec)
|
||||
tv.Usec = int32(usec)
|
||||
return err
|
||||
}
|
||||
|
||||
func SetKevent(k *Kevent_t, fd, mode, flags int) {
|
||||
k.Ident = uint32(fd)
|
||||
k.Filter = int16(mode)
|
||||
k.Flags = uint16(flags)
|
||||
}
|
||||
|
||||
func (iov *Iovec) SetLen(length int) {
|
||||
iov.Len = uint32(length)
|
||||
}
|
||||
|
||||
func (msghdr *Msghdr) SetControllen(length int) {
|
||||
msghdr.Controllen = uint32(length)
|
||||
}
|
||||
|
||||
func (cmsg *Cmsghdr) SetLen(length int) {
|
||||
cmsg.Len = uint32(length)
|
||||
}
|
||||
|
||||
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
|
||||
var length = uint64(count)
|
||||
|
||||
_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(*offset>>32), uintptr(unsafe.Pointer(&length)), 0, 0, 0, 0)
|
||||
|
||||
written = int(length)
|
||||
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) // sic
|
||||
70
unix/syscall_darwin_amd64.go
Normal file
70
unix/syscall_darwin_amd64.go
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func Getpagesize() int { return 4096 }
|
||||
|
||||
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
|
||||
|
||||
func NsecToTimespec(nsec int64) (ts Timespec) {
|
||||
ts.Sec = nsec / 1e9
|
||||
ts.Nsec = nsec % 1e9
|
||||
return
|
||||
}
|
||||
|
||||
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
|
||||
|
||||
func NsecToTimeval(nsec int64) (tv Timeval) {
|
||||
nsec += 999 // round up to microsecond
|
||||
tv.Usec = int32(nsec % 1e9 / 1e3)
|
||||
tv.Sec = int64(nsec / 1e9)
|
||||
return
|
||||
}
|
||||
|
||||
//sysnb gettimeofday(tp *Timeval) (sec int64, usec int32, err error)
|
||||
func Gettimeofday(tv *Timeval) (err error) {
|
||||
// The tv passed to gettimeofday must be non-nil
|
||||
// but is otherwise unused. The answers come back
|
||||
// in the two registers.
|
||||
sec, usec, err := gettimeofday(tv)
|
||||
tv.Sec = sec
|
||||
tv.Usec = usec
|
||||
return err
|
||||
}
|
||||
|
||||
func SetKevent(k *Kevent_t, fd, mode, flags int) {
|
||||
k.Ident = uint64(fd)
|
||||
k.Filter = int16(mode)
|
||||
k.Flags = uint16(flags)
|
||||
}
|
||||
|
||||
func (iov *Iovec) SetLen(length int) {
|
||||
iov.Len = uint64(length)
|
||||
}
|
||||
|
||||
func (msghdr *Msghdr) SetControllen(length int) {
|
||||
msghdr.Controllen = uint32(length)
|
||||
}
|
||||
|
||||
func (cmsg *Cmsghdr) SetLen(length int) {
|
||||
cmsg.Len = uint32(length)
|
||||
}
|
||||
|
||||
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
|
||||
var length = uint64(count)
|
||||
|
||||
_, _, e1 := Syscall6(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(unsafe.Pointer(&length)), 0, 0)
|
||||
|
||||
written = int(length)
|
||||
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) // sic
|
||||
410
unix/syscall_dragonfly.go
Normal file
410
unix/syscall_dragonfly.go
Normal file
@@ -0,0 +1,410 @@
|
||||
// Copyright 2009,2010 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.
|
||||
|
||||
// FreeBSD system calls.
|
||||
// This file is compiled as ordinary Go code,
|
||||
// but it is also input to mksyscall,
|
||||
// which parses the //sys lines and generates system call stubs.
|
||||
// Note that sometimes we use a lowercase //sys name and wrap
|
||||
// it in our own nicer implementation, either here or in
|
||||
// syscall_bsd.go or syscall_unix.go.
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
type SockaddrDatalink struct {
|
||||
Len uint8
|
||||
Family uint8
|
||||
Index uint16
|
||||
Type uint8
|
||||
Nlen uint8
|
||||
Alen uint8
|
||||
Slen uint8
|
||||
Data [12]int8
|
||||
Rcf uint16
|
||||
Route [16]uint16
|
||||
raw RawSockaddrDatalink
|
||||
}
|
||||
|
||||
// Translate "kern.hostname" to []_C_int{0,1,2,3}.
|
||||
func nametomib(name string) (mib []_C_int, err error) {
|
||||
const siz = unsafe.Sizeof(mib[0])
|
||||
|
||||
// NOTE(rsc): It seems strange to set the buffer to have
|
||||
// size CTL_MAXNAME+2 but use only CTL_MAXNAME
|
||||
// as the size. I don't know why the +2 is here, but the
|
||||
// kernel uses +2 for its own implementation of this function.
|
||||
// I am scared that if we don't include the +2 here, the kernel
|
||||
// will silently write 2 words farther than we specify
|
||||
// and we'll get memory corruption.
|
||||
var buf [CTL_MAXNAME + 2]_C_int
|
||||
n := uintptr(CTL_MAXNAME) * siz
|
||||
|
||||
p := (*byte)(unsafe.Pointer(&buf[0]))
|
||||
bytes, err := ByteSliceFromString(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Magic sysctl: "setting" 0.3 to a string name
|
||||
// lets you read back the array of integers form.
|
||||
if err = sysctl([]_C_int{0, 3}, p, &n, &bytes[0], uintptr(len(name))); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf[0 : n/siz], nil
|
||||
}
|
||||
|
||||
// ParseDirent parses up to max directory entries in buf,
|
||||
// appending the names to names. It returns the number
|
||||
// bytes consumed from buf, the number of entries added
|
||||
// to names, and the new names slice.
|
||||
func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
|
||||
origlen := len(buf)
|
||||
for max != 0 && len(buf) > 0 {
|
||||
dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
|
||||
reclen := int(16+dirent.Namlen+1+7) & ^7
|
||||
buf = buf[reclen:]
|
||||
if dirent.Fileno == 0 { // File absent in directory.
|
||||
continue
|
||||
}
|
||||
bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
|
||||
var name = string(bytes[0:dirent.Namlen])
|
||||
if name == "." || name == ".." { // Useless names
|
||||
continue
|
||||
}
|
||||
max--
|
||||
count++
|
||||
names = append(names, name)
|
||||
}
|
||||
return origlen - len(buf), count, names
|
||||
}
|
||||
|
||||
//sysnb pipe() (r int, w int, err error)
|
||||
|
||||
func Pipe(p []int) (err error) {
|
||||
if len(p) != 2 {
|
||||
return EINVAL
|
||||
}
|
||||
p[0], p[1], err = pipe()
|
||||
return
|
||||
}
|
||||
|
||||
//sys extpread(fd int, p []byte, flags int, offset int64) (n int, err error)
|
||||
func Pread(fd int, p []byte, offset int64) (n int, err error) {
|
||||
return extpread(fd, p, 0, offset)
|
||||
}
|
||||
|
||||
//sys extpwrite(fd int, p []byte, flags int, offset int64) (n int, err error)
|
||||
func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
|
||||
return extpwrite(fd, p, 0, offset)
|
||||
}
|
||||
|
||||
func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
var bufsize uintptr
|
||||
if len(buf) > 0 {
|
||||
_p0 = unsafe.Pointer(&buf[0])
|
||||
bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), bufsize, uintptr(flags))
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
* Exposed directly
|
||||
*/
|
||||
//sys Access(path string, mode uint32) (err error)
|
||||
//sys Adjtime(delta *Timeval, olddelta *Timeval) (err error)
|
||||
//sys Chdir(path string) (err error)
|
||||
//sys Chflags(path string, flags int) (err error)
|
||||
//sys Chmod(path string, mode uint32) (err error)
|
||||
//sys Chown(path string, uid int, gid int) (err error)
|
||||
//sys Chroot(path string) (err error)
|
||||
//sys Close(fd int) (err error)
|
||||
//sysnb Dup(fd int) (nfd int, err error)
|
||||
//sysnb Dup2(from int, to int) (err error)
|
||||
//sys Exit(code int)
|
||||
//sys Fchdir(fd int) (err error)
|
||||
//sys Fchflags(fd int, flags int) (err error)
|
||||
//sys Fchmod(fd int, mode uint32) (err error)
|
||||
//sys Fchown(fd int, uid int, gid int) (err error)
|
||||
//sys Flock(fd int, how int) (err error)
|
||||
//sys Fpathconf(fd int, name int) (val int, err error)
|
||||
//sys Fstat(fd int, stat *Stat_t) (err error)
|
||||
//sys Fstatfs(fd int, stat *Statfs_t) (err error)
|
||||
//sys Fsync(fd int) (err error)
|
||||
//sys Ftruncate(fd int, length int64) (err error)
|
||||
//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error)
|
||||
//sys Getdtablesize() (size int)
|
||||
//sysnb Getegid() (egid int)
|
||||
//sysnb Geteuid() (uid int)
|
||||
//sysnb Getgid() (gid int)
|
||||
//sysnb Getpgid(pid int) (pgid int, err error)
|
||||
//sysnb Getpgrp() (pgrp int)
|
||||
//sysnb Getpid() (pid int)
|
||||
//sysnb Getppid() (ppid int)
|
||||
//sys Getpriority(which int, who int) (prio int, err error)
|
||||
//sysnb Getrlimit(which int, lim *Rlimit) (err error)
|
||||
//sysnb Getrusage(who int, rusage *Rusage) (err error)
|
||||
//sysnb Getsid(pid int) (sid int, err error)
|
||||
//sysnb Gettimeofday(tv *Timeval) (err error)
|
||||
//sysnb Getuid() (uid int)
|
||||
//sys Issetugid() (tainted bool)
|
||||
//sys Kill(pid int, signum Signal) (err error)
|
||||
//sys Kqueue() (fd int, err error)
|
||||
//sys Lchown(path string, uid int, gid int) (err error)
|
||||
//sys Link(path string, link string) (err error)
|
||||
//sys Listen(s int, backlog int) (err error)
|
||||
//sys Lstat(path string, stat *Stat_t) (err error)
|
||||
//sys Mkdir(path string, mode uint32) (err error)
|
||||
//sys Mkfifo(path string, mode uint32) (err error)
|
||||
//sys Mknod(path string, mode uint32, dev int) (err error)
|
||||
//sys Nanosleep(time *Timespec, leftover *Timespec) (err error)
|
||||
//sys Open(path string, mode int, perm uint32) (fd int, err error)
|
||||
//sys Pathconf(path string, name int) (val int, err error)
|
||||
//sys read(fd int, p []byte) (n int, err error)
|
||||
//sys Readlink(path string, buf []byte) (n int, err error)
|
||||
//sys Rename(from string, to string) (err error)
|
||||
//sys Revoke(path string) (err error)
|
||||
//sys Rmdir(path string) (err error)
|
||||
//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK
|
||||
//sys Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error)
|
||||
//sysnb Setegid(egid int) (err error)
|
||||
//sysnb Seteuid(euid int) (err error)
|
||||
//sysnb Setgid(gid int) (err error)
|
||||
//sys Setlogin(name string) (err error)
|
||||
//sysnb Setpgid(pid int, pgid int) (err error)
|
||||
//sys Setpriority(which int, who int, prio int) (err error)
|
||||
//sysnb Setregid(rgid int, egid int) (err error)
|
||||
//sysnb Setreuid(ruid int, euid int) (err error)
|
||||
//sysnb Setresgid(rgid int, egid int, sgid int) (err error)
|
||||
//sysnb Setresuid(ruid int, euid int, suid int) (err error)
|
||||
//sysnb Setrlimit(which int, lim *Rlimit) (err error)
|
||||
//sysnb Setsid() (pid int, err error)
|
||||
//sysnb Settimeofday(tp *Timeval) (err error)
|
||||
//sysnb Setuid(uid int) (err error)
|
||||
//sys Stat(path string, stat *Stat_t) (err error)
|
||||
//sys Statfs(path string, stat *Statfs_t) (err error)
|
||||
//sys Symlink(path string, link string) (err error)
|
||||
//sys Sync() (err error)
|
||||
//sys Truncate(path string, length int64) (err error)
|
||||
//sys Umask(newmask int) (oldmask int)
|
||||
//sys Undelete(path string) (err error)
|
||||
//sys Unlink(path string) (err error)
|
||||
//sys Unmount(path string, flags int) (err error)
|
||||
//sys write(fd int, p []byte) (n int, err error)
|
||||
//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
|
||||
//sys munmap(addr uintptr, length uintptr) (err error)
|
||||
//sys readlen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_READ
|
||||
//sys writelen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_WRITE
|
||||
|
||||
/*
|
||||
* Unimplemented
|
||||
* TODO(jsing): Update this list for DragonFly.
|
||||
*/
|
||||
// Profil
|
||||
// Sigaction
|
||||
// Sigprocmask
|
||||
// Getlogin
|
||||
// Sigpending
|
||||
// Sigaltstack
|
||||
// Ioctl
|
||||
// Reboot
|
||||
// Execve
|
||||
// Vfork
|
||||
// Sbrk
|
||||
// Sstk
|
||||
// Ovadvise
|
||||
// Mincore
|
||||
// Setitimer
|
||||
// Swapon
|
||||
// Select
|
||||
// Sigsuspend
|
||||
// Readv
|
||||
// Writev
|
||||
// Nfssvc
|
||||
// Getfh
|
||||
// Quotactl
|
||||
// Mount
|
||||
// Csops
|
||||
// Waitid
|
||||
// Add_profil
|
||||
// Kdebug_trace
|
||||
// Sigreturn
|
||||
// Mmap
|
||||
// Mlock
|
||||
// Munlock
|
||||
// Atsocket
|
||||
// Kqueue_from_portset_np
|
||||
// Kqueue_portset
|
||||
// Getattrlist
|
||||
// Setattrlist
|
||||
// Getdirentriesattr
|
||||
// Searchfs
|
||||
// Delete
|
||||
// Copyfile
|
||||
// Poll
|
||||
// Watchevent
|
||||
// Waitevent
|
||||
// Modwatch
|
||||
// Getxattr
|
||||
// Fgetxattr
|
||||
// Setxattr
|
||||
// Fsetxattr
|
||||
// Removexattr
|
||||
// Fremovexattr
|
||||
// Listxattr
|
||||
// Flistxattr
|
||||
// Fsctl
|
||||
// Initgroups
|
||||
// Posix_spawn
|
||||
// Nfsclnt
|
||||
// Fhopen
|
||||
// Minherit
|
||||
// Semsys
|
||||
// Msgsys
|
||||
// Shmsys
|
||||
// Semctl
|
||||
// Semget
|
||||
// Semop
|
||||
// Msgctl
|
||||
// Msgget
|
||||
// Msgsnd
|
||||
// Msgrcv
|
||||
// Shmat
|
||||
// Shmctl
|
||||
// Shmdt
|
||||
// Shmget
|
||||
// Shm_open
|
||||
// Shm_unlink
|
||||
// Sem_open
|
||||
// Sem_close
|
||||
// Sem_unlink
|
||||
// Sem_wait
|
||||
// Sem_trywait
|
||||
// Sem_post
|
||||
// Sem_getvalue
|
||||
// Sem_init
|
||||
// Sem_destroy
|
||||
// Open_extended
|
||||
// Umask_extended
|
||||
// Stat_extended
|
||||
// Lstat_extended
|
||||
// Fstat_extended
|
||||
// Chmod_extended
|
||||
// Fchmod_extended
|
||||
// Access_extended
|
||||
// Settid
|
||||
// Gettid
|
||||
// Setsgroups
|
||||
// Getsgroups
|
||||
// Setwgroups
|
||||
// Getwgroups
|
||||
// Mkfifo_extended
|
||||
// Mkdir_extended
|
||||
// Identitysvc
|
||||
// Shared_region_check_np
|
||||
// Shared_region_map_np
|
||||
// __pthread_mutex_destroy
|
||||
// __pthread_mutex_init
|
||||
// __pthread_mutex_lock
|
||||
// __pthread_mutex_trylock
|
||||
// __pthread_mutex_unlock
|
||||
// __pthread_cond_init
|
||||
// __pthread_cond_destroy
|
||||
// __pthread_cond_broadcast
|
||||
// __pthread_cond_signal
|
||||
// Setsid_with_pid
|
||||
// __pthread_cond_timedwait
|
||||
// Aio_fsync
|
||||
// Aio_return
|
||||
// Aio_suspend
|
||||
// Aio_cancel
|
||||
// Aio_error
|
||||
// Aio_read
|
||||
// Aio_write
|
||||
// Lio_listio
|
||||
// __pthread_cond_wait
|
||||
// Iopolicysys
|
||||
// Mlockall
|
||||
// Munlockall
|
||||
// __pthread_kill
|
||||
// __pthread_sigmask
|
||||
// __sigwait
|
||||
// __disable_threadsignal
|
||||
// __pthread_markcancel
|
||||
// __pthread_canceled
|
||||
// __semwait_signal
|
||||
// Proc_info
|
||||
// Stat64_extended
|
||||
// Lstat64_extended
|
||||
// Fstat64_extended
|
||||
// __pthread_chdir
|
||||
// __pthread_fchdir
|
||||
// Audit
|
||||
// Auditon
|
||||
// Getauid
|
||||
// Setauid
|
||||
// Getaudit
|
||||
// Setaudit
|
||||
// Getaudit_addr
|
||||
// Setaudit_addr
|
||||
// Auditctl
|
||||
// Bsdthread_create
|
||||
// Bsdthread_terminate
|
||||
// Stack_snapshot
|
||||
// Bsdthread_register
|
||||
// Workq_open
|
||||
// Workq_ops
|
||||
// __mac_execve
|
||||
// __mac_syscall
|
||||
// __mac_get_file
|
||||
// __mac_set_file
|
||||
// __mac_get_link
|
||||
// __mac_set_link
|
||||
// __mac_get_proc
|
||||
// __mac_set_proc
|
||||
// __mac_get_fd
|
||||
// __mac_set_fd
|
||||
// __mac_get_pid
|
||||
// __mac_get_lcid
|
||||
// __mac_get_lctx
|
||||
// __mac_set_lctx
|
||||
// Setlcid
|
||||
// Read_nocancel
|
||||
// Write_nocancel
|
||||
// Open_nocancel
|
||||
// Close_nocancel
|
||||
// Wait4_nocancel
|
||||
// Recvmsg_nocancel
|
||||
// Sendmsg_nocancel
|
||||
// Recvfrom_nocancel
|
||||
// Accept_nocancel
|
||||
// Msync_nocancel
|
||||
// Fcntl_nocancel
|
||||
// Select_nocancel
|
||||
// Fsync_nocancel
|
||||
// Connect_nocancel
|
||||
// Sigsuspend_nocancel
|
||||
// Readv_nocancel
|
||||
// Writev_nocancel
|
||||
// Sendto_nocancel
|
||||
// Pread_nocancel
|
||||
// Pwrite_nocancel
|
||||
// Waitid_nocancel
|
||||
// Poll_nocancel
|
||||
// Msgsnd_nocancel
|
||||
// Msgrcv_nocancel
|
||||
// Sem_wait_nocancel
|
||||
// Aio_suspend_nocancel
|
||||
// __sigwait_nocancel
|
||||
// __semwait_signal_nocancel
|
||||
// __mac_mount
|
||||
// __mac_get_mount
|
||||
// __mac_getfsstat
|
||||
58
unix/syscall_dragonfly_386.go
Normal file
58
unix/syscall_dragonfly_386.go
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func Getpagesize() int { return 4096 }
|
||||
|
||||
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
|
||||
|
||||
func NsecToTimespec(nsec int64) (ts Timespec) {
|
||||
ts.Sec = int32(nsec / 1e9)
|
||||
ts.Nsec = int32(nsec % 1e9)
|
||||
return
|
||||
}
|
||||
|
||||
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
|
||||
|
||||
func NsecToTimeval(nsec int64) (tv Timeval) {
|
||||
nsec += 999 // round up to microsecond
|
||||
tv.Usec = int32(nsec % 1e9 / 1e3)
|
||||
tv.Sec = int32(nsec / 1e9)
|
||||
return
|
||||
}
|
||||
|
||||
func SetKevent(k *Kevent_t, fd, mode, flags int) {
|
||||
k.Ident = uint32(fd)
|
||||
k.Filter = int16(mode)
|
||||
k.Flags = uint16(flags)
|
||||
}
|
||||
|
||||
func (iov *Iovec) SetLen(length int) {
|
||||
iov.Len = uint32(length)
|
||||
}
|
||||
|
||||
func (msghdr *Msghdr) SetControllen(length int) {
|
||||
msghdr.Controllen = uint32(length)
|
||||
}
|
||||
|
||||
func (cmsg *Cmsghdr) SetLen(length int) {
|
||||
cmsg.Len = uint32(length)
|
||||
}
|
||||
|
||||
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
|
||||
var writtenOut uint64 = 0
|
||||
_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr((*offset)>>32), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0)
|
||||
|
||||
written = int(writtenOut)
|
||||
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) // sic
|
||||
58
unix/syscall_dragonfly_amd64.go
Normal file
58
unix/syscall_dragonfly_amd64.go
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func Getpagesize() int { return 4096 }
|
||||
|
||||
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
|
||||
|
||||
func NsecToTimespec(nsec int64) (ts Timespec) {
|
||||
ts.Sec = nsec / 1e9
|
||||
ts.Nsec = nsec % 1e9
|
||||
return
|
||||
}
|
||||
|
||||
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
|
||||
|
||||
func NsecToTimeval(nsec int64) (tv Timeval) {
|
||||
nsec += 999 // round up to microsecond
|
||||
tv.Usec = nsec % 1e9 / 1e3
|
||||
tv.Sec = int64(nsec / 1e9)
|
||||
return
|
||||
}
|
||||
|
||||
func SetKevent(k *Kevent_t, fd, mode, flags int) {
|
||||
k.Ident = uint64(fd)
|
||||
k.Filter = int16(mode)
|
||||
k.Flags = uint16(flags)
|
||||
}
|
||||
|
||||
func (iov *Iovec) SetLen(length int) {
|
||||
iov.Len = uint64(length)
|
||||
}
|
||||
|
||||
func (msghdr *Msghdr) SetControllen(length int) {
|
||||
msghdr.Controllen = uint32(length)
|
||||
}
|
||||
|
||||
func (cmsg *Cmsghdr) SetLen(length int) {
|
||||
cmsg.Len = uint32(length)
|
||||
}
|
||||
|
||||
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
|
||||
var writtenOut uint64 = 0
|
||||
_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0, 0)
|
||||
|
||||
written = int(writtenOut)
|
||||
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
|
||||
432
unix/syscall_freebsd.go
Normal file
432
unix/syscall_freebsd.go
Normal file
@@ -0,0 +1,432 @@
|
||||
// Copyright 2009,2010 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.
|
||||
|
||||
// FreeBSD system calls.
|
||||
// This file is compiled as ordinary Go code,
|
||||
// but it is also input to mksyscall,
|
||||
// which parses the //sys lines and generates system call stubs.
|
||||
// Note that sometimes we use a lowercase //sys name and wrap
|
||||
// it in our own nicer implementation, either here or in
|
||||
// syscall_bsd.go or syscall_unix.go.
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
type SockaddrDatalink struct {
|
||||
Len uint8
|
||||
Family uint8
|
||||
Index uint16
|
||||
Type uint8
|
||||
Nlen uint8
|
||||
Alen uint8
|
||||
Slen uint8
|
||||
Data [46]int8
|
||||
raw RawSockaddrDatalink
|
||||
}
|
||||
|
||||
// Translate "kern.hostname" to []_C_int{0,1,2,3}.
|
||||
func nametomib(name string) (mib []_C_int, err error) {
|
||||
const siz = unsafe.Sizeof(mib[0])
|
||||
|
||||
// NOTE(rsc): It seems strange to set the buffer to have
|
||||
// size CTL_MAXNAME+2 but use only CTL_MAXNAME
|
||||
// as the size. I don't know why the +2 is here, but the
|
||||
// kernel uses +2 for its own implementation of this function.
|
||||
// I am scared that if we don't include the +2 here, the kernel
|
||||
// will silently write 2 words farther than we specify
|
||||
// and we'll get memory corruption.
|
||||
var buf [CTL_MAXNAME + 2]_C_int
|
||||
n := uintptr(CTL_MAXNAME) * siz
|
||||
|
||||
p := (*byte)(unsafe.Pointer(&buf[0]))
|
||||
bytes, err := ByteSliceFromString(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Magic sysctl: "setting" 0.3 to a string name
|
||||
// lets you read back the array of integers form.
|
||||
if err = sysctl([]_C_int{0, 3}, p, &n, &bytes[0], uintptr(len(name))); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf[0 : n/siz], nil
|
||||
}
|
||||
|
||||
// ParseDirent parses up to max directory entries in buf,
|
||||
// appending the names to names. It returns the number
|
||||
// bytes consumed from buf, the number of entries added
|
||||
// to names, and the new names slice.
|
||||
func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
|
||||
origlen := len(buf)
|
||||
for max != 0 && len(buf) > 0 {
|
||||
dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
|
||||
if dirent.Reclen == 0 {
|
||||
buf = nil
|
||||
break
|
||||
}
|
||||
buf = buf[dirent.Reclen:]
|
||||
if dirent.Fileno == 0 { // File absent in directory.
|
||||
continue
|
||||
}
|
||||
bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
|
||||
var name = string(bytes[0:dirent.Namlen])
|
||||
if name == "." || name == ".." { // Useless names
|
||||
continue
|
||||
}
|
||||
max--
|
||||
count++
|
||||
names = append(names, name)
|
||||
}
|
||||
return origlen - len(buf), count, names
|
||||
}
|
||||
|
||||
//sysnb pipe() (r int, w int, err error)
|
||||
|
||||
func Pipe(p []int) (err error) {
|
||||
if len(p) != 2 {
|
||||
return EINVAL
|
||||
}
|
||||
p[0], p[1], err = pipe()
|
||||
return
|
||||
}
|
||||
|
||||
func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) {
|
||||
var value IPMreqn
|
||||
vallen := _Socklen(SizeofIPMreqn)
|
||||
errno := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
|
||||
return &value, errno
|
||||
}
|
||||
|
||||
func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) {
|
||||
return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq))
|
||||
}
|
||||
|
||||
func Accept4(fd, flags int) (nfd int, sa Sockaddr, err error) {
|
||||
var rsa RawSockaddrAny
|
||||
var len _Socklen = SizeofSockaddrAny
|
||||
nfd, err = accept4(fd, &rsa, &len, flags)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len > SizeofSockaddrAny {
|
||||
panic("RawSockaddrAny too small")
|
||||
}
|
||||
sa, err = anyToSockaddr(&rsa)
|
||||
if err != nil {
|
||||
Close(nfd)
|
||||
nfd = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
var bufsize uintptr
|
||||
if len(buf) > 0 {
|
||||
_p0 = unsafe.Pointer(&buf[0])
|
||||
bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), bufsize, uintptr(flags))
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
* Exposed directly
|
||||
*/
|
||||
//sys Access(path string, mode uint32) (err error)
|
||||
//sys Adjtime(delta *Timeval, olddelta *Timeval) (err error)
|
||||
//sys Chdir(path string) (err error)
|
||||
//sys Chflags(path string, flags int) (err error)
|
||||
//sys Chmod(path string, mode uint32) (err error)
|
||||
//sys Chown(path string, uid int, gid int) (err error)
|
||||
//sys Chroot(path string) (err error)
|
||||
//sys Close(fd int) (err error)
|
||||
//sysnb Dup(fd int) (nfd int, err error)
|
||||
//sysnb Dup2(from int, to int) (err error)
|
||||
//sys Exit(code int)
|
||||
//sys Fchdir(fd int) (err error)
|
||||
//sys Fchflags(fd int, flags int) (err error)
|
||||
//sys Fchmod(fd int, mode uint32) (err error)
|
||||
//sys Fchown(fd int, uid int, gid int) (err error)
|
||||
//sys Flock(fd int, how int) (err error)
|
||||
//sys Fpathconf(fd int, name int) (val int, err error)
|
||||
//sys Fstat(fd int, stat *Stat_t) (err error)
|
||||
//sys Fstatfs(fd int, stat *Statfs_t) (err error)
|
||||
//sys Fsync(fd int) (err error)
|
||||
//sys Ftruncate(fd int, length int64) (err error)
|
||||
//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error)
|
||||
//sys Getdtablesize() (size int)
|
||||
//sysnb Getegid() (egid int)
|
||||
//sysnb Geteuid() (uid int)
|
||||
//sysnb Getgid() (gid int)
|
||||
//sysnb Getpgid(pid int) (pgid int, err error)
|
||||
//sysnb Getpgrp() (pgrp int)
|
||||
//sysnb Getpid() (pid int)
|
||||
//sysnb Getppid() (ppid int)
|
||||
//sys Getpriority(which int, who int) (prio int, err error)
|
||||
//sysnb Getrlimit(which int, lim *Rlimit) (err error)
|
||||
//sysnb Getrusage(who int, rusage *Rusage) (err error)
|
||||
//sysnb Getsid(pid int) (sid int, err error)
|
||||
//sysnb Gettimeofday(tv *Timeval) (err error)
|
||||
//sysnb Getuid() (uid int)
|
||||
//sys Issetugid() (tainted bool)
|
||||
//sys Kill(pid int, signum Signal) (err error)
|
||||
//sys Kqueue() (fd int, err error)
|
||||
//sys Lchown(path string, uid int, gid int) (err error)
|
||||
//sys Link(path string, link string) (err error)
|
||||
//sys Listen(s int, backlog int) (err error)
|
||||
//sys Lstat(path string, stat *Stat_t) (err error)
|
||||
//sys Mkdir(path string, mode uint32) (err error)
|
||||
//sys Mkfifo(path string, mode uint32) (err error)
|
||||
//sys Mknod(path string, mode uint32, dev int) (err error)
|
||||
//sys Nanosleep(time *Timespec, leftover *Timespec) (err error)
|
||||
//sys Open(path string, mode int, perm uint32) (fd int, err error)
|
||||
//sys Pathconf(path string, name int) (val int, err error)
|
||||
//sys Pread(fd int, p []byte, offset int64) (n int, err error)
|
||||
//sys Pwrite(fd int, p []byte, offset int64) (n int, err error)
|
||||
//sys read(fd int, p []byte) (n int, err error)
|
||||
//sys Readlink(path string, buf []byte) (n int, err error)
|
||||
//sys Rename(from string, to string) (err error)
|
||||
//sys Revoke(path string) (err error)
|
||||
//sys Rmdir(path string) (err error)
|
||||
//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK
|
||||
//sys Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error)
|
||||
//sysnb Setegid(egid int) (err error)
|
||||
//sysnb Seteuid(euid int) (err error)
|
||||
//sysnb Setgid(gid int) (err error)
|
||||
//sys Setlogin(name string) (err error)
|
||||
//sysnb Setpgid(pid int, pgid int) (err error)
|
||||
//sys Setpriority(which int, who int, prio int) (err error)
|
||||
//sysnb Setregid(rgid int, egid int) (err error)
|
||||
//sysnb Setreuid(ruid int, euid int) (err error)
|
||||
//sysnb Setresgid(rgid int, egid int, sgid int) (err error)
|
||||
//sysnb Setresuid(ruid int, euid int, suid int) (err error)
|
||||
//sysnb Setrlimit(which int, lim *Rlimit) (err error)
|
||||
//sysnb Setsid() (pid int, err error)
|
||||
//sysnb Settimeofday(tp *Timeval) (err error)
|
||||
//sysnb Setuid(uid int) (err error)
|
||||
//sys Stat(path string, stat *Stat_t) (err error)
|
||||
//sys Statfs(path string, stat *Statfs_t) (err error)
|
||||
//sys Symlink(path string, link string) (err error)
|
||||
//sys Sync() (err error)
|
||||
//sys Truncate(path string, length int64) (err error)
|
||||
//sys Umask(newmask int) (oldmask int)
|
||||
//sys Undelete(path string) (err error)
|
||||
//sys Unlink(path string) (err error)
|
||||
//sys Unmount(path string, flags int) (err error)
|
||||
//sys write(fd int, p []byte) (n int, err error)
|
||||
//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
|
||||
//sys munmap(addr uintptr, length uintptr) (err error)
|
||||
//sys readlen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_READ
|
||||
//sys writelen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_WRITE
|
||||
//sys accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int, err error)
|
||||
|
||||
/*
|
||||
* Unimplemented
|
||||
*/
|
||||
// Profil
|
||||
// Sigaction
|
||||
// Sigprocmask
|
||||
// Getlogin
|
||||
// Sigpending
|
||||
// Sigaltstack
|
||||
// Ioctl
|
||||
// Reboot
|
||||
// Execve
|
||||
// Vfork
|
||||
// Sbrk
|
||||
// Sstk
|
||||
// Ovadvise
|
||||
// Mincore
|
||||
// Setitimer
|
||||
// Swapon
|
||||
// Select
|
||||
// Sigsuspend
|
||||
// Readv
|
||||
// Writev
|
||||
// Nfssvc
|
||||
// Getfh
|
||||
// Quotactl
|
||||
// Mount
|
||||
// Csops
|
||||
// Waitid
|
||||
// Add_profil
|
||||
// Kdebug_trace
|
||||
// Sigreturn
|
||||
// Mmap
|
||||
// Mlock
|
||||
// Munlock
|
||||
// Atsocket
|
||||
// Kqueue_from_portset_np
|
||||
// Kqueue_portset
|
||||
// Getattrlist
|
||||
// Setattrlist
|
||||
// Getdirentriesattr
|
||||
// Searchfs
|
||||
// Delete
|
||||
// Copyfile
|
||||
// Poll
|
||||
// Watchevent
|
||||
// Waitevent
|
||||
// Modwatch
|
||||
// Getxattr
|
||||
// Fgetxattr
|
||||
// Setxattr
|
||||
// Fsetxattr
|
||||
// Removexattr
|
||||
// Fremovexattr
|
||||
// Listxattr
|
||||
// Flistxattr
|
||||
// Fsctl
|
||||
// Initgroups
|
||||
// Posix_spawn
|
||||
// Nfsclnt
|
||||
// Fhopen
|
||||
// Minherit
|
||||
// Semsys
|
||||
// Msgsys
|
||||
// Shmsys
|
||||
// Semctl
|
||||
// Semget
|
||||
// Semop
|
||||
// Msgctl
|
||||
// Msgget
|
||||
// Msgsnd
|
||||
// Msgrcv
|
||||
// Shmat
|
||||
// Shmctl
|
||||
// Shmdt
|
||||
// Shmget
|
||||
// Shm_open
|
||||
// Shm_unlink
|
||||
// Sem_open
|
||||
// Sem_close
|
||||
// Sem_unlink
|
||||
// Sem_wait
|
||||
// Sem_trywait
|
||||
// Sem_post
|
||||
// Sem_getvalue
|
||||
// Sem_init
|
||||
// Sem_destroy
|
||||
// Open_extended
|
||||
// Umask_extended
|
||||
// Stat_extended
|
||||
// Lstat_extended
|
||||
// Fstat_extended
|
||||
// Chmod_extended
|
||||
// Fchmod_extended
|
||||
// Access_extended
|
||||
// Settid
|
||||
// Gettid
|
||||
// Setsgroups
|
||||
// Getsgroups
|
||||
// Setwgroups
|
||||
// Getwgroups
|
||||
// Mkfifo_extended
|
||||
// Mkdir_extended
|
||||
// Identitysvc
|
||||
// Shared_region_check_np
|
||||
// Shared_region_map_np
|
||||
// __pthread_mutex_destroy
|
||||
// __pthread_mutex_init
|
||||
// __pthread_mutex_lock
|
||||
// __pthread_mutex_trylock
|
||||
// __pthread_mutex_unlock
|
||||
// __pthread_cond_init
|
||||
// __pthread_cond_destroy
|
||||
// __pthread_cond_broadcast
|
||||
// __pthread_cond_signal
|
||||
// Setsid_with_pid
|
||||
// __pthread_cond_timedwait
|
||||
// Aio_fsync
|
||||
// Aio_return
|
||||
// Aio_suspend
|
||||
// Aio_cancel
|
||||
// Aio_error
|
||||
// Aio_read
|
||||
// Aio_write
|
||||
// Lio_listio
|
||||
// __pthread_cond_wait
|
||||
// Iopolicysys
|
||||
// Mlockall
|
||||
// Munlockall
|
||||
// __pthread_kill
|
||||
// __pthread_sigmask
|
||||
// __sigwait
|
||||
// __disable_threadsignal
|
||||
// __pthread_markcancel
|
||||
// __pthread_canceled
|
||||
// __semwait_signal
|
||||
// Proc_info
|
||||
// Stat64_extended
|
||||
// Lstat64_extended
|
||||
// Fstat64_extended
|
||||
// __pthread_chdir
|
||||
// __pthread_fchdir
|
||||
// Audit
|
||||
// Auditon
|
||||
// Getauid
|
||||
// Setauid
|
||||
// Getaudit
|
||||
// Setaudit
|
||||
// Getaudit_addr
|
||||
// Setaudit_addr
|
||||
// Auditctl
|
||||
// Bsdthread_create
|
||||
// Bsdthread_terminate
|
||||
// Stack_snapshot
|
||||
// Bsdthread_register
|
||||
// Workq_open
|
||||
// Workq_ops
|
||||
// __mac_execve
|
||||
// __mac_syscall
|
||||
// __mac_get_file
|
||||
// __mac_set_file
|
||||
// __mac_get_link
|
||||
// __mac_set_link
|
||||
// __mac_get_proc
|
||||
// __mac_set_proc
|
||||
// __mac_get_fd
|
||||
// __mac_set_fd
|
||||
// __mac_get_pid
|
||||
// __mac_get_lcid
|
||||
// __mac_get_lctx
|
||||
// __mac_set_lctx
|
||||
// Setlcid
|
||||
// Read_nocancel
|
||||
// Write_nocancel
|
||||
// Open_nocancel
|
||||
// Close_nocancel
|
||||
// Wait4_nocancel
|
||||
// Recvmsg_nocancel
|
||||
// Sendmsg_nocancel
|
||||
// Recvfrom_nocancel
|
||||
// Accept_nocancel
|
||||
// Msync_nocancel
|
||||
// Fcntl_nocancel
|
||||
// Select_nocancel
|
||||
// Fsync_nocancel
|
||||
// Connect_nocancel
|
||||
// Sigsuspend_nocancel
|
||||
// Readv_nocancel
|
||||
// Writev_nocancel
|
||||
// Sendto_nocancel
|
||||
// Pread_nocancel
|
||||
// Pwrite_nocancel
|
||||
// Waitid_nocancel
|
||||
// Poll_nocancel
|
||||
// Msgsnd_nocancel
|
||||
// Msgrcv_nocancel
|
||||
// Sem_wait_nocancel
|
||||
// Aio_suspend_nocancel
|
||||
// __sigwait_nocancel
|
||||
// __semwait_signal_nocancel
|
||||
// __mac_mount
|
||||
// __mac_get_mount
|
||||
// __mac_getfsstat
|
||||
58
unix/syscall_freebsd_386.go
Normal file
58
unix/syscall_freebsd_386.go
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func Getpagesize() int { return 4096 }
|
||||
|
||||
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
|
||||
|
||||
func NsecToTimespec(nsec int64) (ts Timespec) {
|
||||
ts.Sec = int32(nsec / 1e9)
|
||||
ts.Nsec = int32(nsec % 1e9)
|
||||
return
|
||||
}
|
||||
|
||||
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
|
||||
|
||||
func NsecToTimeval(nsec int64) (tv Timeval) {
|
||||
nsec += 999 // round up to microsecond
|
||||
tv.Usec = int32(nsec % 1e9 / 1e3)
|
||||
tv.Sec = int32(nsec / 1e9)
|
||||
return
|
||||
}
|
||||
|
||||
func SetKevent(k *Kevent_t, fd, mode, flags int) {
|
||||
k.Ident = uint32(fd)
|
||||
k.Filter = int16(mode)
|
||||
k.Flags = uint16(flags)
|
||||
}
|
||||
|
||||
func (iov *Iovec) SetLen(length int) {
|
||||
iov.Len = uint32(length)
|
||||
}
|
||||
|
||||
func (msghdr *Msghdr) SetControllen(length int) {
|
||||
msghdr.Controllen = uint32(length)
|
||||
}
|
||||
|
||||
func (cmsg *Cmsghdr) SetLen(length int) {
|
||||
cmsg.Len = uint32(length)
|
||||
}
|
||||
|
||||
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
|
||||
var writtenOut uint64 = 0
|
||||
_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr((*offset)>>32), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0)
|
||||
|
||||
written = int(writtenOut)
|
||||
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) // sic
|
||||
58
unix/syscall_freebsd_amd64.go
Normal file
58
unix/syscall_freebsd_amd64.go
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func Getpagesize() int { return 4096 }
|
||||
|
||||
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
|
||||
|
||||
func NsecToTimespec(nsec int64) (ts Timespec) {
|
||||
ts.Sec = nsec / 1e9
|
||||
ts.Nsec = nsec % 1e9
|
||||
return
|
||||
}
|
||||
|
||||
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
|
||||
|
||||
func NsecToTimeval(nsec int64) (tv Timeval) {
|
||||
nsec += 999 // round up to microsecond
|
||||
tv.Usec = nsec % 1e9 / 1e3
|
||||
tv.Sec = int64(nsec / 1e9)
|
||||
return
|
||||
}
|
||||
|
||||
func SetKevent(k *Kevent_t, fd, mode, flags int) {
|
||||
k.Ident = uint64(fd)
|
||||
k.Filter = int16(mode)
|
||||
k.Flags = uint16(flags)
|
||||
}
|
||||
|
||||
func (iov *Iovec) SetLen(length int) {
|
||||
iov.Len = uint64(length)
|
||||
}
|
||||
|
||||
func (msghdr *Msghdr) SetControllen(length int) {
|
||||
msghdr.Controllen = uint32(length)
|
||||
}
|
||||
|
||||
func (cmsg *Cmsghdr) SetLen(length int) {
|
||||
cmsg.Len = uint32(length)
|
||||
}
|
||||
|
||||
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
|
||||
var writtenOut uint64 = 0
|
||||
_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0, 0)
|
||||
|
||||
written = int(writtenOut)
|
||||
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
|
||||
58
unix/syscall_freebsd_arm.go
Normal file
58
unix/syscall_freebsd_arm.go
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright 2012 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.
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func Getpagesize() int { return 4096 }
|
||||
|
||||
func TimespecToNsec(ts Timespec) int64 { return ts.Sec*1e9 + int64(ts.Nsec) }
|
||||
|
||||
func NsecToTimespec(nsec int64) (ts Timespec) {
|
||||
ts.Sec = nsec / 1e9
|
||||
ts.Nsec = int32(nsec % 1e9)
|
||||
return
|
||||
}
|
||||
|
||||
func TimevalToNsec(tv Timeval) int64 { return tv.Sec*1e9 + int64(tv.Usec)*1e3 }
|
||||
|
||||
func NsecToTimeval(nsec int64) (tv Timeval) {
|
||||
nsec += 999 // round up to microsecond
|
||||
tv.Usec = int32(nsec % 1e9 / 1e3)
|
||||
tv.Sec = nsec / 1e9
|
||||
return
|
||||
}
|
||||
|
||||
func SetKevent(k *Kevent_t, fd, mode, flags int) {
|
||||
k.Ident = uint32(fd)
|
||||
k.Filter = int16(mode)
|
||||
k.Flags = uint16(flags)
|
||||
}
|
||||
|
||||
func (iov *Iovec) SetLen(length int) {
|
||||
iov.Len = uint32(length)
|
||||
}
|
||||
|
||||
func (msghdr *Msghdr) SetControllen(length int) {
|
||||
msghdr.Controllen = uint32(length)
|
||||
}
|
||||
|
||||
func (cmsg *Cmsghdr) SetLen(length int) {
|
||||
cmsg.Len = uint32(length)
|
||||
}
|
||||
|
||||
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
|
||||
var writtenOut uint64 = 0
|
||||
_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr((*offset)>>32), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0)
|
||||
|
||||
written = int(writtenOut)
|
||||
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) // sic
|
||||
1038
unix/syscall_linux.go
Normal file
1038
unix/syscall_linux.go
Normal file
File diff suppressed because it is too large
Load Diff
355
unix/syscall_linux_386.go
Normal file
355
unix/syscall_linux_386.go
Normal file
@@ -0,0 +1,355 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
|
||||
// so that go vet can check that they are correct.
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func Getpagesize() int { return 4096 }
|
||||
|
||||
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
|
||||
|
||||
func NsecToTimespec(nsec int64) (ts Timespec) {
|
||||
ts.Sec = int32(nsec / 1e9)
|
||||
ts.Nsec = int32(nsec % 1e9)
|
||||
return
|
||||
}
|
||||
|
||||
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
|
||||
|
||||
func NsecToTimeval(nsec int64) (tv Timeval) {
|
||||
nsec += 999 // round up to microsecond
|
||||
tv.Sec = int32(nsec / 1e9)
|
||||
tv.Usec = int32(nsec % 1e9 / 1e3)
|
||||
return
|
||||
}
|
||||
|
||||
// 64-bit file system and 32-bit uid calls
|
||||
// (386 default is 32-bit file system and 16-bit uid).
|
||||
//sys Chown(path string, uid int, gid int) (err error) = SYS_CHOWN32
|
||||
//sys Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32
|
||||
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
|
||||
//sys Ftruncate(fd int, length int64) (err error) = SYS_FTRUNCATE64
|
||||
//sysnb Getegid() (egid int) = SYS_GETEGID32
|
||||
//sysnb Geteuid() (euid int) = SYS_GETEUID32
|
||||
//sysnb Getgid() (gid int) = SYS_GETGID32
|
||||
//sysnb Getuid() (uid int) = SYS_GETUID32
|
||||
//sys Ioperm(from int, num int, on int) (err error)
|
||||
//sys Iopl(level int) (err error)
|
||||
//sys Lchown(path string, uid int, gid int) (err error) = SYS_LCHOWN32
|
||||
//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
|
||||
//sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
|
||||
//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
|
||||
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = SYS_SENDFILE64
|
||||
//sys Setfsgid(gid int) (err error) = SYS_SETFSGID32
|
||||
//sys Setfsuid(uid int) (err error) = SYS_SETFSUID32
|
||||
//sysnb Setregid(rgid int, egid int) (err error) = SYS_SETREGID32
|
||||
//sysnb Setresgid(rgid int, egid int, sgid int) (err error) = SYS_SETRESGID32
|
||||
//sysnb Setresuid(ruid int, euid int, suid int) (err error) = SYS_SETRESUID32
|
||||
//sysnb Setreuid(ruid int, euid int) (err error) = SYS_SETREUID32
|
||||
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error)
|
||||
//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
|
||||
//sys SyncFileRange(fd int, off int64, n int64, flags int) (err error)
|
||||
//sys Truncate(path string, length int64) (err error) = SYS_TRUNCATE64
|
||||
//sysnb getgroups(n int, list *_Gid_t) (nn int, err error) = SYS_GETGROUPS32
|
||||
//sysnb setgroups(n int, list *_Gid_t) (err error) = SYS_SETGROUPS32
|
||||
//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) = SYS__NEWSELECT
|
||||
|
||||
//sys mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error)
|
||||
|
||||
func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) {
|
||||
page := uintptr(offset / 4096)
|
||||
if offset != int64(page)*4096 {
|
||||
return 0, EINVAL
|
||||
}
|
||||
return mmap2(addr, length, prot, flags, fd, page)
|
||||
}
|
||||
|
||||
type rlimit32 struct {
|
||||
Cur uint32
|
||||
Max uint32
|
||||
}
|
||||
|
||||
//sysnb getrlimit(resource int, rlim *rlimit32) (err error) = SYS_GETRLIMIT
|
||||
|
||||
const rlimInf32 = ^uint32(0)
|
||||
const rlimInf64 = ^uint64(0)
|
||||
|
||||
func Getrlimit(resource int, rlim *Rlimit) (err error) {
|
||||
err = prlimit(0, resource, nil, rlim)
|
||||
if err != ENOSYS {
|
||||
return err
|
||||
}
|
||||
|
||||
rl := rlimit32{}
|
||||
err = getrlimit(resource, &rl)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if rl.Cur == rlimInf32 {
|
||||
rlim.Cur = rlimInf64
|
||||
} else {
|
||||
rlim.Cur = uint64(rl.Cur)
|
||||
}
|
||||
|
||||
if rl.Max == rlimInf32 {
|
||||
rlim.Max = rlimInf64
|
||||
} else {
|
||||
rlim.Max = uint64(rl.Max)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//sysnb setrlimit(resource int, rlim *rlimit32) (err error) = SYS_SETRLIMIT
|
||||
|
||||
func Setrlimit(resource int, rlim *Rlimit) (err error) {
|
||||
err = prlimit(0, resource, rlim, nil)
|
||||
if err != ENOSYS {
|
||||
return err
|
||||
}
|
||||
|
||||
rl := rlimit32{}
|
||||
if rlim.Cur == rlimInf64 {
|
||||
rl.Cur = rlimInf32
|
||||
} else if rlim.Cur < uint64(rlimInf32) {
|
||||
rl.Cur = uint32(rlim.Cur)
|
||||
} else {
|
||||
return EINVAL
|
||||
}
|
||||
if rlim.Max == rlimInf64 {
|
||||
rl.Max = rlimInf32
|
||||
} else if rlim.Max < uint64(rlimInf32) {
|
||||
rl.Max = uint32(rlim.Max)
|
||||
} else {
|
||||
return EINVAL
|
||||
}
|
||||
|
||||
return setrlimit(resource, &rl)
|
||||
}
|
||||
|
||||
// Underlying system call writes to newoffset via pointer.
|
||||
// Implemented in assembly to avoid allocation.
|
||||
func seek(fd int, offset int64, whence int) (newoffset int64, err Errno)
|
||||
|
||||
func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
|
||||
newoffset, errno := seek(fd, offset, whence)
|
||||
if errno != 0 {
|
||||
return 0, errno
|
||||
}
|
||||
return newoffset, nil
|
||||
}
|
||||
|
||||
// Vsyscalls on amd64.
|
||||
//sysnb Gettimeofday(tv *Timeval) (err error)
|
||||
//sysnb Time(t *Time_t) (tt Time_t, err error)
|
||||
|
||||
// On x86 Linux, all the socket calls go through an extra indirection,
|
||||
// I think because the 5-register system call interface can't handle
|
||||
// the 6-argument calls like sendto and recvfrom. Instead the
|
||||
// arguments to the underlying system call are the number below
|
||||
// and a pointer to an array of uintptr. We hide the pointer in the
|
||||
// socketcall assembly to avoid allocation on every system call.
|
||||
|
||||
const (
|
||||
// see linux/net.h
|
||||
_SOCKET = 1
|
||||
_BIND = 2
|
||||
_CONNECT = 3
|
||||
_LISTEN = 4
|
||||
_ACCEPT = 5
|
||||
_GETSOCKNAME = 6
|
||||
_GETPEERNAME = 7
|
||||
_SOCKETPAIR = 8
|
||||
_SEND = 9
|
||||
_RECV = 10
|
||||
_SENDTO = 11
|
||||
_RECVFROM = 12
|
||||
_SHUTDOWN = 13
|
||||
_SETSOCKOPT = 14
|
||||
_GETSOCKOPT = 15
|
||||
_SENDMSG = 16
|
||||
_RECVMSG = 17
|
||||
_ACCEPT4 = 18
|
||||
_RECVMMSG = 19
|
||||
_SENDMMSG = 20
|
||||
)
|
||||
|
||||
func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err Errno)
|
||||
func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err Errno)
|
||||
|
||||
func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
|
||||
fd, e := socketcall(_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
|
||||
if e != 0 {
|
||||
err = e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) {
|
||||
fd, e := socketcall(_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
|
||||
if e != 0 {
|
||||
err = e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getsockname(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
|
||||
_, e := rawsocketcall(_GETSOCKNAME, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
|
||||
if e != 0 {
|
||||
err = e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getpeername(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
|
||||
_, e := rawsocketcall(_GETPEERNAME, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
|
||||
if e != 0 {
|
||||
err = e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func socketpair(domain int, typ int, flags int, fd *[2]int32) (err error) {
|
||||
_, e := rawsocketcall(_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(flags), uintptr(unsafe.Pointer(fd)), 0, 0)
|
||||
if e != 0 {
|
||||
err = e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
|
||||
_, e := socketcall(_BIND, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
|
||||
if e != 0 {
|
||||
err = e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
|
||||
_, e := socketcall(_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
|
||||
if e != 0 {
|
||||
err = e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func socket(domain int, typ int, proto int) (fd int, err error) {
|
||||
fd, e := rawsocketcall(_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0)
|
||||
if e != 0 {
|
||||
err = e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
|
||||
_, e := socketcall(_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
|
||||
if e != 0 {
|
||||
err = e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
|
||||
_, e := socketcall(_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), vallen, 0)
|
||||
if e != 0 {
|
||||
err = e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func recvfrom(s int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
|
||||
var base uintptr
|
||||
if len(p) > 0 {
|
||||
base = uintptr(unsafe.Pointer(&p[0]))
|
||||
}
|
||||
n, e := socketcall(_RECVFROM, uintptr(s), base, uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
|
||||
if e != 0 {
|
||||
err = e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func sendto(s int, p []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
|
||||
var base uintptr
|
||||
if len(p) > 0 {
|
||||
base = uintptr(unsafe.Pointer(&p[0]))
|
||||
}
|
||||
_, e := socketcall(_SENDTO, uintptr(s), base, uintptr(len(p)), uintptr(flags), uintptr(to), uintptr(addrlen))
|
||||
if e != 0 {
|
||||
err = e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
|
||||
n, e := socketcall(_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
|
||||
if e != 0 {
|
||||
err = e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
|
||||
n, e := socketcall(_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
|
||||
if e != 0 {
|
||||
err = e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Listen(s int, n int) (err error) {
|
||||
_, e := socketcall(_LISTEN, uintptr(s), uintptr(n), 0, 0, 0, 0)
|
||||
if e != 0 {
|
||||
err = e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Shutdown(s, how int) (err error) {
|
||||
_, e := socketcall(_SHUTDOWN, uintptr(s), uintptr(how), 0, 0, 0, 0)
|
||||
if e != 0 {
|
||||
err = e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Fstatfs(fd int, buf *Statfs_t) (err error) {
|
||||
_, _, e := Syscall(SYS_FSTATFS64, uintptr(fd), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf)))
|
||||
if e != 0 {
|
||||
err = e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Statfs(path string, buf *Statfs_t) (err error) {
|
||||
pathp, err := BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, _, e := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(pathp)), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf)))
|
||||
if e != 0 {
|
||||
err = e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (r *PtraceRegs) PC() uint64 { return uint64(uint32(r.Eip)) }
|
||||
|
||||
func (r *PtraceRegs) SetPC(pc uint64) { r.Eip = int32(pc) }
|
||||
|
||||
func (iov *Iovec) SetLen(length int) {
|
||||
iov.Len = uint32(length)
|
||||
}
|
||||
|
||||
func (msghdr *Msghdr) SetControllen(length int) {
|
||||
msghdr.Controllen = uint32(length)
|
||||
}
|
||||
|
||||
func (cmsg *Cmsghdr) SetLen(length int) {
|
||||
cmsg.Len = uint32(length)
|
||||
}
|
||||
114
unix/syscall_linux_amd64.go
Normal file
114
unix/syscall_linux_amd64.go
Normal file
@@ -0,0 +1,114 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
package syscall
|
||||
|
||||
//sys Chown(path string, uid int, gid int) (err error)
|
||||
//sys Fchown(fd int, uid int, gid int) (err error)
|
||||
//sys Fstat(fd int, stat *Stat_t) (err error)
|
||||
//sys Fstatfs(fd int, buf *Statfs_t) (err error)
|
||||
//sys Ftruncate(fd int, length int64) (err error)
|
||||
//sysnb Getegid() (egid int)
|
||||
//sysnb Geteuid() (euid int)
|
||||
//sysnb Getgid() (gid int)
|
||||
//sysnb Getrlimit(resource int, rlim *Rlimit) (err error)
|
||||
//sysnb Getuid() (uid int)
|
||||
//sys Ioperm(from int, num int, on int) (err error)
|
||||
//sys Iopl(level int) (err error)
|
||||
//sys Lchown(path string, uid int, gid int) (err error)
|
||||
//sys Listen(s int, n int) (err error)
|
||||
//sys Lstat(path string, stat *Stat_t) (err error)
|
||||
//sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
|
||||
//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
|
||||
//sys Seek(fd int, offset int64, whence int) (off int64, err error) = SYS_LSEEK
|
||||
//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error)
|
||||
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
|
||||
//sys Setfsgid(gid int) (err error)
|
||||
//sys Setfsuid(uid int) (err error)
|
||||
//sysnb Setregid(rgid int, egid int) (err error)
|
||||
//sysnb Setresgid(rgid int, egid int, sgid int) (err error)
|
||||
//sysnb Setresuid(ruid int, euid int, suid int) (err error)
|
||||
//sysnb Setrlimit(resource int, rlim *Rlimit) (err error)
|
||||
//sysnb Setreuid(ruid int, euid int) (err error)
|
||||
//sys Shutdown(fd int, how int) (err error)
|
||||
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
|
||||
//sys Stat(path string, stat *Stat_t) (err error)
|
||||
//sys Statfs(path string, buf *Statfs_t) (err error)
|
||||
//sys SyncFileRange(fd int, off int64, n int64, flags int) (err error)
|
||||
//sys Truncate(path string, length int64) (err error)
|
||||
//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
|
||||
//sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error)
|
||||
//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
|
||||
//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
|
||||
//sysnb getgroups(n int, list *_Gid_t) (nn int, err error)
|
||||
//sysnb setgroups(n int, list *_Gid_t) (err error)
|
||||
//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error)
|
||||
//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error)
|
||||
//sysnb socket(domain int, typ int, proto int) (fd int, err error)
|
||||
//sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error)
|
||||
//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
|
||||
//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
|
||||
//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
|
||||
//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error)
|
||||
//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
|
||||
//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
|
||||
//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error)
|
||||
|
||||
func Getpagesize() int { return 4096 }
|
||||
|
||||
//go:noescape
|
||||
func gettimeofday(tv *Timeval) (err Errno)
|
||||
|
||||
func Gettimeofday(tv *Timeval) (err error) {
|
||||
errno := gettimeofday(tv)
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Time(t *Time_t) (tt Time_t, err error) {
|
||||
var tv Timeval
|
||||
errno := gettimeofday(&tv)
|
||||
if errno != 0 {
|
||||
return 0, errno
|
||||
}
|
||||
if t != nil {
|
||||
*t = Time_t(tv.Sec)
|
||||
}
|
||||
return Time_t(tv.Sec), nil
|
||||
}
|
||||
|
||||
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
|
||||
|
||||
func NsecToTimespec(nsec int64) (ts Timespec) {
|
||||
ts.Sec = nsec / 1e9
|
||||
ts.Nsec = nsec % 1e9
|
||||
return
|
||||
}
|
||||
|
||||
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
|
||||
|
||||
func NsecToTimeval(nsec int64) (tv Timeval) {
|
||||
nsec += 999 // round up to microsecond
|
||||
tv.Sec = nsec / 1e9
|
||||
tv.Usec = nsec % 1e9 / 1e3
|
||||
return
|
||||
}
|
||||
|
||||
func (r *PtraceRegs) PC() uint64 { return r.Rip }
|
||||
|
||||
func (r *PtraceRegs) SetPC(pc uint64) { r.Rip = pc }
|
||||
|
||||
func (iov *Iovec) SetLen(length int) {
|
||||
iov.Len = uint64(length)
|
||||
}
|
||||
|
||||
func (msghdr *Msghdr) SetControllen(length int) {
|
||||
msghdr.Controllen = uint64(length)
|
||||
}
|
||||
|
||||
func (cmsg *Cmsghdr) SetLen(length int) {
|
||||
cmsg.Len = uint64(length)
|
||||
}
|
||||
195
unix/syscall_linux_arm.go
Normal file
195
unix/syscall_linux_arm.go
Normal file
@@ -0,0 +1,195 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func Getpagesize() int { return 4096 }
|
||||
|
||||
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
|
||||
|
||||
func NsecToTimespec(nsec int64) (ts Timespec) {
|
||||
ts.Sec = int32(nsec / 1e9)
|
||||
ts.Nsec = int32(nsec % 1e9)
|
||||
return
|
||||
}
|
||||
|
||||
func NsecToTimeval(nsec int64) (tv Timeval) {
|
||||
nsec += 999 // round up to microsecond
|
||||
tv.Sec = int32(nsec / 1e9)
|
||||
tv.Usec = int32(nsec % 1e9 / 1e3)
|
||||
return
|
||||
}
|
||||
|
||||
// Underlying system call writes to newoffset via pointer.
|
||||
// Implemented in assembly to avoid allocation.
|
||||
func seek(fd int, offset int64, whence int) (newoffset int64, err Errno)
|
||||
|
||||
func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
|
||||
newoffset, errno := seek(fd, offset, whence)
|
||||
if errno != 0 {
|
||||
return 0, errno
|
||||
}
|
||||
return newoffset, nil
|
||||
}
|
||||
|
||||
//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
|
||||
//sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error)
|
||||
//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
|
||||
//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
|
||||
//sysnb getgroups(n int, list *_Gid_t) (nn int, err error) = SYS_GETGROUPS32
|
||||
//sysnb setgroups(n int, list *_Gid_t) (err error) = SYS_SETGROUPS32
|
||||
//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error)
|
||||
//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error)
|
||||
//sysnb socket(domain int, typ int, proto int) (fd int, err error)
|
||||
//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
|
||||
//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
|
||||
//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
|
||||
//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error)
|
||||
//sysnb socketpair(domain int, typ int, flags int, fd *[2]int32) (err error)
|
||||
//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
|
||||
//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
|
||||
|
||||
// 64-bit file system and 32-bit uid calls
|
||||
// (16-bit uid calls are not always supported in newer kernels)
|
||||
//sys Chown(path string, uid int, gid int) (err error) = SYS_CHOWN32
|
||||
//sys Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32
|
||||
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
|
||||
//sysnb Getegid() (egid int) = SYS_GETEGID32
|
||||
//sysnb Geteuid() (euid int) = SYS_GETEUID32
|
||||
//sysnb Getgid() (gid int) = SYS_GETGID32
|
||||
//sysnb Getuid() (uid int) = SYS_GETUID32
|
||||
//sys Lchown(path string, uid int, gid int) (err error) = SYS_LCHOWN32
|
||||
//sys Listen(s int, n int) (err error)
|
||||
//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
|
||||
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = SYS_SENDFILE64
|
||||
//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) = SYS__NEWSELECT
|
||||
//sys Setfsgid(gid int) (err error) = SYS_SETFSGID32
|
||||
//sys Setfsuid(uid int) (err error) = SYS_SETFSUID32
|
||||
//sysnb Setregid(rgid int, egid int) (err error) = SYS_SETREGID32
|
||||
//sysnb Setresgid(rgid int, egid int, sgid int) (err error) = SYS_SETRESGID32
|
||||
//sysnb Setresuid(ruid int, euid int, suid int) (err error) = SYS_SETRESUID32
|
||||
//sysnb Setreuid(ruid int, euid int) (err error) = SYS_SETREUID32
|
||||
//sys Shutdown(fd int, how int) (err error)
|
||||
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error)
|
||||
//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
|
||||
|
||||
// Vsyscalls on amd64.
|
||||
//sysnb Gettimeofday(tv *Timeval) (err error)
|
||||
//sysnb Time(t *Time_t) (tt Time_t, err error)
|
||||
|
||||
//sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
|
||||
//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
|
||||
//sys Truncate(path string, length int64) (err error) = SYS_TRUNCATE64
|
||||
//sys Ftruncate(fd int, length int64) (err error) = SYS_FTRUNCATE64
|
||||
|
||||
//sys mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error)
|
||||
|
||||
func Fstatfs(fd int, buf *Statfs_t) (err error) {
|
||||
_, _, e := Syscall(SYS_FSTATFS64, uintptr(fd), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf)))
|
||||
if e != 0 {
|
||||
err = e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Statfs(path string, buf *Statfs_t) (err error) {
|
||||
pathp, err := BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, _, e := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(pathp)), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf)))
|
||||
if e != 0 {
|
||||
err = e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) {
|
||||
page := uintptr(offset / 4096)
|
||||
if offset != int64(page)*4096 {
|
||||
return 0, EINVAL
|
||||
}
|
||||
return mmap2(addr, length, prot, flags, fd, page)
|
||||
}
|
||||
|
||||
type rlimit32 struct {
|
||||
Cur uint32
|
||||
Max uint32
|
||||
}
|
||||
|
||||
//sysnb getrlimit(resource int, rlim *rlimit32) (err error) = SYS_GETRLIMIT
|
||||
|
||||
const rlimInf32 = ^uint32(0)
|
||||
const rlimInf64 = ^uint64(0)
|
||||
|
||||
func Getrlimit(resource int, rlim *Rlimit) (err error) {
|
||||
err = prlimit(0, resource, nil, rlim)
|
||||
if err != ENOSYS {
|
||||
return err
|
||||
}
|
||||
|
||||
rl := rlimit32{}
|
||||
err = getrlimit(resource, &rl)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if rl.Cur == rlimInf32 {
|
||||
rlim.Cur = rlimInf64
|
||||
} else {
|
||||
rlim.Cur = uint64(rl.Cur)
|
||||
}
|
||||
|
||||
if rl.Max == rlimInf32 {
|
||||
rlim.Max = rlimInf64
|
||||
} else {
|
||||
rlim.Max = uint64(rl.Max)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//sysnb setrlimit(resource int, rlim *rlimit32) (err error) = SYS_SETRLIMIT
|
||||
|
||||
func Setrlimit(resource int, rlim *Rlimit) (err error) {
|
||||
err = prlimit(0, resource, rlim, nil)
|
||||
if err != ENOSYS {
|
||||
return err
|
||||
}
|
||||
|
||||
rl := rlimit32{}
|
||||
if rlim.Cur == rlimInf64 {
|
||||
rl.Cur = rlimInf32
|
||||
} else if rlim.Cur < uint64(rlimInf32) {
|
||||
rl.Cur = uint32(rlim.Cur)
|
||||
} else {
|
||||
return EINVAL
|
||||
}
|
||||
if rlim.Max == rlimInf64 {
|
||||
rl.Max = rlimInf32
|
||||
} else if rlim.Max < uint64(rlimInf32) {
|
||||
rl.Max = uint32(rlim.Max)
|
||||
} else {
|
||||
return EINVAL
|
||||
}
|
||||
|
||||
return setrlimit(resource, &rl)
|
||||
}
|
||||
|
||||
func (r *PtraceRegs) PC() uint64 { return uint64(r.Uregs[15]) }
|
||||
|
||||
func (r *PtraceRegs) SetPC(pc uint64) { r.Uregs[15] = uint32(pc) }
|
||||
|
||||
func (iov *Iovec) SetLen(length int) {
|
||||
iov.Len = uint32(length)
|
||||
}
|
||||
|
||||
func (msghdr *Msghdr) SetControllen(length int) {
|
||||
msghdr.Controllen = uint32(length)
|
||||
}
|
||||
|
||||
func (cmsg *Cmsghdr) SetLen(length int) {
|
||||
cmsg.Len = uint32(length)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user