os: Plan 9, fix OpenFile & Chmod. Update tests.

Add Process.Kill.

R=rsc
CC=golang-dev
https://golang.org/cl/4571049
This commit is contained in:
Yuval Pavel Zholkover 2011-06-14 11:20:34 -04:00 committed by Russ Cox
parent 9e2ffc315f
commit 18112437d9
10 changed files with 145 additions and 41 deletions

View File

@ -73,6 +73,7 @@ GOFILES_plan9=\
path_plan9.go\
sys_plan9.go\
exec_plan9.go\
str.go\
GOFILES+=$(GOFILES_$(GOOS))

View File

@ -38,6 +38,17 @@ func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err E
return newProcess(pid, h), nil
}
// Kill causes the Process to exit immediately.
func (p *Process) Kill() Error {
f, e := OpenFile("/proc/"+itoa(p.Pid)+"/ctl", O_WRONLY, 0)
if iserror(e) {
return NewSyscallError("kill", e)
}
defer f.Close()
_, e = f.Write([]byte("kill"))
return e
}
// Exec replaces the current process with an execution of the
// named binary, with arguments argv and environment envv.
// If successful, Exec never returns. If it fails, it returns an Error.

View File

@ -30,14 +30,43 @@ const DevNull = "/dev/null"
// methods on the returned File can be used for I/O.
// It returns the File and an Error, if any.
func OpenFile(name string, flag int, perm uint32) (file *File, err Error) {
var fd int
var e syscall.Error
var (
fd int
e syscall.Error
create bool
excl bool
trunc bool
append bool
)
if flag&O_CREATE == O_CREATE {
flag = flag & ^O_CREATE
create = true
}
if flag&O_EXCL == O_EXCL {
excl = true
}
if flag&O_TRUNC == O_TRUNC {
trunc = true
}
// O_APPEND is emulated on Plan 9
if flag&O_APPEND == O_APPEND {
flag = flag &^ O_APPEND
append = true
}
syscall.ForkLock.RLock()
if flag&O_CREATE == O_CREATE {
fd, e = syscall.Create(name, flag & ^O_CREATE, perm)
if (create && trunc) || excl {
fd, e = syscall.Create(name, flag, perm)
} else {
fd, e = syscall.Open(name, flag)
if e != nil && create {
var e1 syscall.Error
fd, e1 = syscall.Create(name, flag, perm)
if e1 == nil {
e = nil
}
}
}
syscall.ForkLock.RUnlock()
@ -45,6 +74,12 @@ func OpenFile(name string, flag int, perm uint32) (file *File, err Error) {
return nil, &PathError{"open", name, e}
}
if append {
if _, e = syscall.Seek(fd, 0, SEEK_END); e != nil {
return nil, &PathError{"seek", name, e}
}
}
return NewFile(fd, name), nil
}
@ -69,8 +104,12 @@ func (file *File) Close() Error {
// Stat returns the FileInfo structure describing file.
// It returns the FileInfo and an error, if any.
func (file *File) Stat() (fi *FileInfo, err Error) {
return dirstat(file)
func (f *File) Stat() (fi *FileInfo, err Error) {
d, err := dirstat(f)
if iserror(err) {
return nil, err
}
return fileInfoFromStat(new(FileInfo), d), err
}
// Truncate changes the size of the file.
@ -90,10 +129,15 @@ func (f *File) Truncate(size int64) Error {
// Chmod changes the mode of the file to mode.
func (f *File) Chmod(mode uint32) Error {
var d Dir
var mask = ^uint32(0777)
d.Null()
odir, e := dirstat(f)
if iserror(e) {
return &PathError{"chmod", f.name, e}
}
d.Mode = mode & 0777
d.Mode = (odir.Mode & mask) | (mode &^ mask)
if e := syscall.Fwstat(f.fd, pdir(nil, &d)); iserror(e) {
return &PathError{"chmod", f.name, e}
}
@ -188,10 +232,15 @@ func Rename(oldname, newname string) Error {
// Chmod changes the mode of the named file to mode.
func Chmod(name string, mode uint32) Error {
var d Dir
var mask = ^uint32(0777)
d.Null()
odir, e := dirstat(name)
if iserror(e) {
return &PathError{"chmod", name, e}
}
d.Mode = mode & 0777
d.Mode = (odir.Mode & mask) | (mode &^ mask)
if e := syscall.Wstat(name, pdir(nil, &d)); iserror(e) {
return &PathError{"chmod", name, e}
}

View File

@ -359,8 +359,8 @@ func TestReaddirNValues(t *testing.T) {
}
func TestHardLink(t *testing.T) {
// Hardlinks are not supported under windows.
if syscall.OS == "windows" {
// Hardlinks are not supported under windows or Plan 9.
if syscall.OS == "windows" || syscall.OS == "plan9" {
return
}
from, to := "hardlinktestfrom", "hardlinktestto"
@ -392,8 +392,8 @@ func TestHardLink(t *testing.T) {
}
func TestSymLink(t *testing.T) {
// Symlinks are not supported under windows.
if syscall.OS == "windows" {
// Symlinks are not supported under windows or Plan 9.
if syscall.OS == "windows" || syscall.OS == "plan9" {
return
}
from, to := "symlinktestfrom", "symlinktestto"
@ -454,8 +454,8 @@ func TestSymLink(t *testing.T) {
}
func TestLongSymlink(t *testing.T) {
// Symlinks are not supported under windows.
if syscall.OS == "windows" {
// Symlinks are not supported under windows or Plan 9.
if syscall.OS == "windows" || syscall.OS == "plan9" {
return
}
s := "0123456789abcdef"
@ -588,8 +588,9 @@ func checkUidGid(t *testing.T, path string, uid, gid int) {
}
func TestChown(t *testing.T) {
// Chown is not supported under windows.
if syscall.OS == "windows" {
// Chown is not supported under windows or Plan 9.
// Plan9 provides a native ChownPlan9 version instead.
if syscall.OS == "windows" || syscall.OS == "plan9" {
return
}
// Use TempDir() to make sure we're on a local file system,
@ -708,7 +709,11 @@ func TestChtimes(t *testing.T) {
t.Fatalf("second Stat %s: %s", f.Name(), err)
}
if postStat.Atime_ns >= preStat.Atime_ns {
/* Plan 9:
Mtime is the time of the last change of content. Similarly, atime is set whenever the
contents are accessed; also, it is set whenever mtime is set.
*/
if postStat.Atime_ns >= preStat.Atime_ns && syscall.OS != "plan9" {
t.Errorf("Atime_ns didn't go backwards; was=%d, after=%d",
preStat.Atime_ns,
postStat.Atime_ns)
@ -733,6 +738,10 @@ func TestChdirAndGetwd(t *testing.T) {
// These are chosen carefully not to be symlinks on a Mac
// (unlike, say, /var, /etc, and /tmp).
dirs := []string{"/", "/usr/bin"}
// /usr/bin does not usually exist on Plan 9.
if syscall.OS == "plan9" {
dirs = []string{"/", "/usr"}
}
for mode := 0; mode < 2; mode++ {
for _, d := range dirs {
if mode == 0 {
@ -858,7 +867,15 @@ func TestOpenError(t *testing.T) {
t.Errorf("Open(%q, %d) returns error of %T type; want *os.PathError", tt.path, tt.mode, err)
}
if perr.Error != tt.error {
t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, perr.Error.String(), tt.error.String())
if syscall.OS == "plan9" {
syscallErrStr := perr.Error.String()
expectedErrStr := strings.Replace(tt.error.String(), "file ", "", 1)
if !strings.HasSuffix(syscallErrStr, expectedErrStr) {
t.Errorf("Open(%q, %d) = _, %q; want suffix %q", tt.path, tt.mode, syscallErrStr, expectedErrStr)
}
} else {
t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, perr.Error.String(), tt.error.String())
}
}
}
}
@ -893,7 +910,8 @@ func run(t *testing.T, cmd []string) string {
func TestHostname(t *testing.T) {
// There is no other way to fetch hostname on windows, but via winapi.
if syscall.OS == "windows" {
// On Plan 9 it is can be taken from #c/sysname as Hostname() does.
if syscall.OS == "windows" || syscall.OS == "plan9" {
return
}
// Check internal Hostname() against the output of /bin/hostname.

View File

@ -166,8 +166,8 @@ func TestRemoveAll(t *testing.T) {
}
func TestMkdirAllWithSymlink(t *testing.T) {
if runtime.GOOS == "windows" {
t.Log("Skipping test: symlinks don't exist under Windows")
if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
t.Log("Skipping test: symlinks don't exist under Windows/Plan 9")
return
}
@ -191,7 +191,7 @@ func TestMkdirAllWithSymlink(t *testing.T) {
}
func TestMkdirAllAtSlash(t *testing.T) {
if runtime.GOOS == "windows" {
if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
return
}
RemoveAll("/_go_os_test")

View File

@ -26,7 +26,7 @@ func fileInfoFromStat(fi *FileInfo, d *Dir) *FileInfo {
}
// arg is an open *File or a path string.
func dirstat(arg interface{}) (fi *FileInfo, err Error) {
func dirstat(arg interface{}) (d *Dir, err Error) {
var name string
nd := syscall.STATFIXLEN + 16*4
@ -62,8 +62,7 @@ func dirstat(arg interface{}) (fi *FileInfo, err Error) {
if e != nil {
return nil, &PathError{"stat", name, e}
}
return fileInfoFromStat(new(FileInfo), d), nil
return d, e
}
}
@ -73,12 +72,20 @@ func dirstat(arg interface{}) (fi *FileInfo, err Error) {
// Stat returns a FileInfo structure describing the named file and an error, if any.
func Stat(name string) (fi *FileInfo, err Error) {
return dirstat(name)
d, err := dirstat(name)
if iserror(err) {
return nil, err
}
return fileInfoFromStat(new(FileInfo), d), err
}
// Lstat returns the FileInfo structure describing the named file and an
// error, if any. If the file is a symbolic link (though Plan 9 does not have symbolic links),
// the returned FileInfo describes the symbolic link. Lstat makes no attempt to follow the link.
func Lstat(name string) (fi *FileInfo, err Error) {
return dirstat(name)
d, err := dirstat(name)
if iserror(err) {
return nil, err
}
return fileInfoFromStat(new(FileInfo), d), err
}

20
src/pkg/os/str.go Normal file
View 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 os
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:])
}

View File

@ -19,20 +19,18 @@ 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,
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,
$O_TRUNC = OTRUNC,
$O_CLOEXEC = OCEXEC,
$O_EXCL = OEXCL,
$STATMAX = 65535U,
$ERRMAX = 128,

View File

@ -4,10 +4,9 @@ package syscall
const (
// Invented values to support what package os expects.
O_CREAT = 0x02000
O_APPEND = 0x00400
O_NOCTTY = 0x00000
O_TRUNC = 0x00000
O_NONBLOCK = 0x00000
O_APPEND = 0x00000
O_SYNC = 0x00000
O_ASYNC = 0x00000

View File

@ -9,6 +9,7 @@ const (
O_RDONLY = 0
O_WRONLY = 0x1
O_RDWR = 0x2
O_TRUNC = 0x10
O_CLOEXEC = 0x20
O_EXCL = 0x1000
STATMAX = 0xffff