diff options
author | Yuval Pavel Zholkover <paulzhol@gmail.com> | 2011-04-02 14:24:03 -0700 |
---|---|---|
committer | Rob Pike <r@golang.org> | 2011-04-02 14:24:03 -0700 |
commit | 1cc4a5cd94bd6c8fb5712defb344d81dd995f063 (patch) | |
tree | 4135aa8d35b51676ceff3468f613c057fd830a41 | |
parent | c42b3e21c30c354a5a2fdc840a0824fb71c10368 (diff) | |
download | go-1cc4a5cd94bd6c8fb5712defb344d81dd995f063.tar.gz go-1cc4a5cd94bd6c8fb5712defb344d81dd995f063.zip |
R=rsc, brainman, ality, r2, r
CC=golang-dev
https://golang.org/cl/3816043
-rw-r--r-- | src/pkg/syscall/Makefile | 3 | ||||
-rw-r--r-- | src/pkg/syscall/asm_plan9_386.s | 151 | ||||
-rw-r--r-- | src/pkg/syscall/exec_plan9.go | 521 | ||||
-rwxr-xr-x | src/pkg/syscall/mkall.sh | 6 | ||||
-rwxr-xr-x | src/pkg/syscall/mksyscall.pl | 18 | ||||
-rwxr-xr-x | src/pkg/syscall/mksysnum_plan9.sh | 25 | ||||
-rw-r--r-- | src/pkg/syscall/str.go | 4 | ||||
-rw-r--r-- | src/pkg/syscall/syscall_linux.go | 2 | ||||
-rw-r--r-- | src/pkg/syscall/syscall_plan9.go | 343 | ||||
-rw-r--r-- | src/pkg/syscall/syscall_plan9_386.go | 5 | ||||
-rw-r--r-- | src/pkg/syscall/syscall_unix.go | 2 | ||||
-rw-r--r-- | src/pkg/syscall/syscall_windows.go | 2 | ||||
-rw-r--r-- | src/pkg/syscall/types_plan9.c | 115 | ||||
-rw-r--r-- | src/pkg/syscall/zerrors_plan9_386.go | 25 | ||||
-rw-r--r-- | src/pkg/syscall/zsyscall_plan9_386.go | 267 | ||||
-rw-r--r-- | src/pkg/syscall/zsysnum_plan9_386.go | 47 | ||||
-rw-r--r-- | src/pkg/syscall/ztypes_plan9_386.go | 74 |
17 files changed, 1604 insertions, 6 deletions
diff --git a/src/pkg/syscall/Makefile b/src/pkg/syscall/Makefile index 061b0056c6..978bc94f8e 100644 --- a/src/pkg/syscall/Makefile +++ b/src/pkg/syscall/Makefile @@ -32,6 +32,9 @@ GOFILES_linux=\ GOFILES_windows=\ exec_windows.go + +GOFILES_plan9=\ + exec_plan9.go OFILES=\ asm_$(GOOS)_$(GOARCH).$O\ diff --git a/src/pkg/syscall/asm_plan9_386.s b/src/pkg/syscall/asm_plan9_386.s new file mode 100644 index 0000000000..86ebedccce --- /dev/null +++ b/src/pkg/syscall/asm_plan9_386.s @@ -0,0 +1,151 @@ +// 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. + +// +// 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),7,$0 + 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 syscall·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),7,$0 + 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 syscall·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),7,$0 + 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),7,$0 + 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),7,$0 + 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 diff --git a/src/pkg/syscall/exec_plan9.go b/src/pkg/syscall/exec_plan9.go new file mode 100644 index 0000000000..94ec395d6d --- /dev/null +++ b/src/pkg/syscall/exec_plan9.go @@ -0,0 +1,521 @@ +// 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 ( + "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 + +// Convert array of string to array +// of NUL-terminated byte pointer. +func StringArrayPtr(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 +} + +// gbit16 reads a 16-bit numeric value from a 9P protocol message strored in b, +// returning the value and the remaining slice of b. +func gbit16(b []byte) (uint16, []byte) { + return uint16(b[0]) | uint16(b[1])<<8, b[2:] +} + +// gstring reads a string from a 9P protocol message strored in b, +// returning the value as a Go string and the remaining slice of b. +func gstring(b []byte) (string, []byte) { + n, b := gbit16(b) + return string(b[0:n]), b[n:] +} + +// readdirnames returns the names of files inside the directory represented by dirfd. +func readdirnames(dirfd int) (names []string, err Error) { + result := make([]string, 0, 100) + var buf [STATMAX]byte + + for { + n, e := Read(dirfd, buf[:]) + if e != nil { + return []string{}, e + } + if n == 0 { + break + } + + for i := 0; i < n; { + m, _ := gbit16(buf[i:]) + m += 2 + + if m < STATFIXLEN { + return []string{}, NewError("malformed stat buffer") + } + + name, _ := gstring(buf[i+41:]) + result = append(result, name) + + i += int(m) + } + } + return []string{}, nil +} + +// 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) + + fileNames, err := readdirnames(dupdevfd) + if err != nil { + return + } + + fds = make([]int, 0, len(fileNames)>>1) + for _, fdstr := range fileNames { + if l := len(fdstr); l > 2 && fdstr[l-3] == 'c' && fdstr[l-2] == 't' && fdstr[l-1] == 'l' { + continue + } + + fd := int(atoi([]byte(fdstr))) + + if fd == 0 || fd == 1 || fd == 2 || fd == dupdevfd { + continue + } + + fds = append(fds, fd) + } + + return fds[0:len(fds)], nil +} + +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, chroot, dir *byte, attr *ProcAttr, fdsToClose []int, pipe 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. + fd := append([]int(nil), attr.Files...) + + 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), 0, 0) + + if r1 != 0 { + if int(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 int(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 int(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 int(r1) == -1 || int(r1) != envv[i].nvalue { + goto childerror + } + + r1, _, _ = RawSyscall(SYS_CLOSE, uintptr(envfd), 0, 0) + + if int(r1) == -1 { + goto childerror + } + } + } + + // Chdir + if dir != nil { + r1, _, _ = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)), 0, 0) + if int(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. + nextfd = int(len(fd)) + if pipe < nextfd { + r1, _, _ = RawSyscall(SYS_DUP, uintptr(pipe), uintptr(nextfd), 0) + if int(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 int(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 int(r1) == -1 { + goto childerror + } + 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 []int // File descriptors. + Chroot string // Chroot. +} + +var zeroAttributes ProcAttr + + +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 = &zeroAttributes + } + + p[0] = -1 + p[1] = -1 + + // Convert args to C form. + argv0p := StringBytePtr(argv[0]) + argvp := StringArrayPtr(argv) + + var chroot *byte + if attr.Chroot != "" { + chroot = StringBytePtr(attr.Chroot) + } + var dir *byte + if attr.Dir != "" { + dir = StringBytePtr(attr.Dir) + } + 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++ + } + + envvParsed = append(envvParsed, envItem{StringBytePtr("/env/" + v[:i]), StringBytePtr(v[i+1:]), 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)) + // exclude fds opened from startup from the list of fds to be closed. + for _, fd := range openFds { + isReserved := false + for _, reservedFd := range startupFds { + if fd == reservedFd { + isReserved = true + break + } + } + + if !isReserved { + fdsToClose = append(fdsToClose, fd) + } + } + + // exclude fds requested by the caller from the list of fds to be closed. + for _, fd := range openFds { + isReserved := false + for _, reservedFd := range attr.Files { + if fd == reservedFd { + isReserved = true + break + } + } + + if !isReserved { + 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, chroot, dir, attr, fdsToClose, p[1]) + + 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[:])) + } + + // 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 +} + +// 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, handle int, err Error) { + pid, err = forkExec(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 int(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) + } + } + + _, _, e := Syscall(SYS_EXEC, + uintptr(unsafe.Pointer(StringBytePtr(argv0))), + uintptr(unsafe.Pointer(&StringArrayPtr(argv)[0])), + 0) + + return NewError(e) +} diff --git a/src/pkg/syscall/mkall.sh b/src/pkg/syscall/mkall.sh index 7e4511f38f..f0a13d9c87 100755 --- a/src/pkg/syscall/mkall.sh +++ b/src/pkg/syscall/mkall.sh @@ -145,6 +145,12 @@ windows_386) mktypes= mkerrors="./mkerrors_windows.sh -f -m32" ;; +plan9_386) + mkerrors= + mksyscall="./mksyscall.pl -l32 -plan9" + mksysnum="./mksysnum_plan9.sh /n/sources/plan9/sys/src/libc/9syscall/sys.h" + mktypes="godefs -gsyscall -f -m32" + ;; *) echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2 exit 1 diff --git a/src/pkg/syscall/mksyscall.pl b/src/pkg/syscall/mksyscall.pl index d4f9c2ab74..068a5e697d 100755 --- a/src/pkg/syscall/mksyscall.pl +++ b/src/pkg/syscall/mksyscall.pl @@ -23,6 +23,7 @@ $cmdline = "mksyscall.pl " . join(' ', @ARGV); $errors = 0; $_32bit = ""; $nacl = 0; +$plan9 = 0; if($ARGV[0] eq "-b32") { $_32bit = "big-endian"; @@ -35,6 +36,10 @@ if($ARGV[0] eq "-nacl") { $nacl = 1; shift; } +if($ARGV[0] eq "-plan9") { + $plan9 = 1; + shift; +} if($ARGV[0] =~ /^-/) { print STDERR "usage: mksyscall.pl [-b32 | -l32] [file ...]\n"; @@ -160,9 +165,13 @@ while(<>) { my $p = $out[$i]; my ($name, $type) = parseparam($p); my $reg = ""; - if($name eq "errno") { + if($name eq "errno" && !$plan9) { $reg = "e1"; $ret[2] = $reg; + } elsif ($name eq "err" && $plan9) { + $ret[0] = "r0"; + $ret[2] = "e1"; + next; } else { $reg = sprintf("r%d", $i); $ret[$i] = $reg; @@ -191,6 +200,13 @@ while(<>) { $text .= "\t$ret[0], $ret[1], $ret[2] := $call\n"; } $text .= $body; + + if ($plan9 && $ret[2] eq "e1") { + $text .= "\terr = nil\n"; + $text .= "\tif int(r0) == -1 {\n"; + $text .= "\t\t err = NewError(e1)\n"; + $text .= "\t}\n"; + } $text .= "\treturn\n"; $text .= "}\n\n"; diff --git a/src/pkg/syscall/mksysnum_plan9.sh b/src/pkg/syscall/mksysnum_plan9.sh new file mode 100755 index 0000000000..fc619f0903 --- /dev/null +++ b/src/pkg/syscall/mksysnum_plan9.sh @@ -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 diff --git a/src/pkg/syscall/str.go b/src/pkg/syscall/str.go index 12f0c7d607..0fce842e8c 100644 --- a/src/pkg/syscall/str.go +++ b/src/pkg/syscall/str.go @@ -4,9 +4,9 @@ package syscall -func str(val int) string { // do it here rather than with fmt to avoid dependency +func itoa(val int) string { // do it here rather than with fmt to avoid dependency if val < 0 { - return "-" + str(-val) + return "-" + itoa(-val) } var buf [32]byte // big enough for int64 i := len(buf) - 1 diff --git a/src/pkg/syscall/syscall_linux.go b/src/pkg/syscall/syscall_linux.go index f27eb1de55..4667663591 100644 --- a/src/pkg/syscall/syscall_linux.go +++ b/src/pkg/syscall/syscall_linux.go @@ -60,7 +60,7 @@ func Futimesat(dirfd int, path string, tv []Timeval) (errno int) { func Futimes(fd int, tv []Timeval) (errno int) { // Believe it or not, this is the best we can do on Linux // (and is what glibc does). - return Utimes("/proc/self/fd/"+str(fd), tv) + return Utimes("/proc/self/fd/"+itoa(fd), tv) } const ImplementsGetwd = true diff --git a/src/pkg/syscall/syscall_plan9.go b/src/pkg/syscall/syscall_plan9.go new file mode 100644 index 0000000000..b889940bfc --- /dev/null +++ b/src/pkg/syscall/syscall_plan9.go @@ -0,0 +1,343 @@ +// 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 OS = "plan9" + +const ImplementsGetwd = true + +// An Error can represent any printable error condition. +type Error interface { + String() string +} + +// ErrorString implements Error's String method by returning itself. +type ErrorString string + +func (e ErrorString) String() string { return string(e) } + +// NewError converts s to an ErrorString, which satisfies the Error interface. +func NewError(s string) Error { return ErrorString(s) } + +var ( + Stdin = 0 + Stdout = 1 + Stderr = 2 + + EISDIR Error = NewError("file is a directory") +) + +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) + +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[:]) +} + +func Getpagesize() int { return 4096 } + +//sys exits(msg *byte) +func Exits(msg *string) { + if msg == nil { + exits(nil) + } + + exits(StringBytePtr(*msg)) +} + +func Exit(code int) { + if code == 0 { + Exits(nil) + } + + msg := itoa(code) + Exits(&msg) +} + +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) +} + +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 +} + + +//sys sleep(millisecs int32) (err Error) +func Sleep(nsec int64) (err Error) { + return sleep(int32((nsec + 999) / 1e6)) // round up to microsecond +} + +// 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) + + err = nil + 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 +} + +//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 = string(f[4]) + return +} + +func Unmount(name, old string) (err Error) { + oldp := uintptr(unsafe.Pointer(StringBytePtr(old))) + + var r0 uintptr + var e string + + // 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, oldp, 0) + } else { + r0, _, e = Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(StringBytePtr(name))), oldp, 0) + } + + err = nil + if int(r0) == -1 { + err = NewError(e) + } + return +} + +func Fchdir(fd int) (err Error) { + path, err := Fd2path(fd) + + if err != nil { + return + } + + return Chdir(path) +} + +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 DecodeBintime(b []byte) (nsec int64, err Error) { + if len(b) != 8 { + return -1, NewError("bad /dev/bintime format") + } + err = nil + nsec = int64(b[0])<<56 | + int64(b[1])<<48 | + int64(b[2])<<40 | + int64(b[3])<<32 | + int64(b[4])<<24 | + int64(b[5])<<16 | + int64(b[6])<<8 | + int64(b[7]) + return +} + +func Gettimeofday(tv *Timeval) (err Error) { + // TODO(paulzhol): + // avoid reopening a file descriptor for /dev/bintime on each call, + // use lower-level calls to avoid allocation. + + var b [8]byte + var nsec int64 + + fd, e := Open("/dev/bintime", O_RDONLY) + if e != nil { + return e + } + defer Close(fd) + + if _, e = Pread(fd, b[:], 0); e != nil { + return e + } + + if nsec, e = DecodeBintime(b[:]); e != nil { + return e + } + *tv = NsecToTimeval(nsec) + + return e +} + +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) diff --git a/src/pkg/syscall/syscall_plan9_386.go b/src/pkg/syscall/syscall_plan9_386.go new file mode 100644 index 0000000000..e82b540b4b --- /dev/null +++ b/src/pkg/syscall/syscall_plan9_386.go @@ -0,0 +1,5 @@ +// 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 diff --git a/src/pkg/syscall/syscall_unix.go b/src/pkg/syscall/syscall_unix.go index 74fe29d020..a77e40bc6b 100644 --- a/src/pkg/syscall/syscall_unix.go +++ b/src/pkg/syscall/syscall_unix.go @@ -17,7 +17,7 @@ func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) func Errstr(errno int) string { if errno < 0 || errno >= int(len(errors)) { - return "error " + str(errno) + return "error " + itoa(errno) } return errors[errno] } diff --git a/src/pkg/syscall/syscall_windows.go b/src/pkg/syscall/syscall_windows.go index 4f8230003c..705c742b14 100644 --- a/src/pkg/syscall/syscall_windows.go +++ b/src/pkg/syscall/syscall_windows.go @@ -175,7 +175,7 @@ func Errstr(errno int) string { b := make([]uint16, 300) n, err := FormatMessage(flags, 0, uint32(errno), 0, b, nil) if err != 0 { - return "error " + str(errno) + " (FormatMessage failed with err=" + str(err) + ")" + return "error " + itoa(errno) + " (FormatMessage failed with err=" + itoa(err) + ")" } // trim terminating \r and \n for ; n > 0 && (b[n-1] == '\n' || b[n-1] == '\r'); n-- { diff --git a/src/pkg/syscall/types_plan9.c b/src/pkg/syscall/types_plan9.c new file mode 100644 index 0000000000..6308ce08be --- /dev/null +++ b/src/pkg/syscall/types_plan9.c @@ -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. + +/* +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 + + $O_RDONLY = OREAD, + $O_WRONLY = OWRITE, + $O_RDWR = ORDWR, + + 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 + + $O_CLOEXEC = OCEXEC, + + ORCLOSE = 64, // or'ed in, remove on close + OEXCL = 0x1000, // or'ed in, exclusive use (create only) + $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; diff --git a/src/pkg/syscall/zerrors_plan9_386.go b/src/pkg/syscall/zerrors_plan9_386.go new file mode 100644 index 0000000000..78b5c72bbf --- /dev/null +++ b/src/pkg/syscall/zerrors_plan9_386.go @@ -0,0 +1,25 @@ +package syscall + +// Constants +const ( + // Invented values to support what package os expects. + O_CREAT = 0x02000 + O_NOCTTY = 0x00000 + O_TRUNC = 0x00000 + O_NONBLOCK = 0x00000 + O_APPEND = 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 +) + +// Error table diff --git a/src/pkg/syscall/zsyscall_plan9_386.go b/src/pkg/syscall/zsyscall_plan9_386.go new file mode 100644 index 0000000000..75c411ad67 --- /dev/null +++ b/src/pkg/syscall/zsyscall_plan9_386.go @@ -0,0 +1,267 @@ +// 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 exits(msg *byte) { + Syscall(SYS_EXITS, uintptr(unsafe.Pointer(msg)), 0, 0) + return +} + +// 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))) + err = nil + if int(r0) == -1 { + err = NewError(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) + err = nil + if int(r0) == -1 { + err = NewError(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sleep(millisecs int32) (err Error) { + r0, _, e1 := Syscall(SYS_SLEEP, uintptr(millisecs), 0, 0) + err = nil + if int(r0) == -1 { + err = NewError(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) + err = nil + if int(r0) == -1 { + err = NewError(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) + err = nil + if int(r0) == -1 { + err = NewError(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) { + r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0) + fd = int(r0) + err = nil + if int(r0) == -1 { + err = NewError(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) { + r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm)) + fd = int(r0) + err = nil + if int(r0) == -1 { + err = NewError(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Remove(path string) (err Error) { + r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0) + err = nil + if int(r0) == -1 { + err = NewError(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) + err = nil + if int(r0) == -1 { + err = NewError(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) + err = nil + if int(r0) == -1 { + err = NewError(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) + err = nil + if int(r0) == -1 { + err = NewError(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chdir(path string) (err Error) { + r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0) + err = nil + if int(r0) == -1 { + err = NewError(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) { + r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(StringBytePtr(name))), uintptr(unsafe.Pointer(StringBytePtr(old))), uintptr(flag)) + err = nil + if int(r0) == -1 { + err = NewError(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) { + r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(StringBytePtr(old))), uintptr(flag), uintptr(unsafe.Pointer(StringBytePtr(aname))), 0) + err = nil + if int(r0) == -1 { + err = NewError(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 unsafe.Pointer + if len(edir) > 0 { + _p0 = unsafe.Pointer(&edir[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(edir))) + n = int(r0) + err = nil + if int(r0) == -1 { + err = NewError(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) + err = nil + if int(r0) == -1 { + err = NewError(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 unsafe.Pointer + if len(edir) > 0 { + _p0 = unsafe.Pointer(&edir[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(edir))) + err = nil + if int(r0) == -1 { + err = NewError(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))) + err = nil + if int(r0) == -1 { + err = NewError(e1) + } + return +} diff --git a/src/pkg/syscall/zsysnum_plan9_386.go b/src/pkg/syscall/zsysnum_plan9_386.go new file mode 100644 index 0000000000..4135b8d819 --- /dev/null +++ b/src/pkg/syscall/zsysnum_plan9_386.go @@ -0,0 +1,47 @@ +// 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 +) diff --git a/src/pkg/syscall/ztypes_plan9_386.go b/src/pkg/syscall/ztypes_plan9_386.go new file mode 100644 index 0000000000..8f823ba659 --- /dev/null +++ b/src/pkg/syscall/ztypes_plan9_386.go @@ -0,0 +1,74 @@ +// 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_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 +} |