1
0
mirror of https://github.com/golang/go synced 2024-11-22 01:44:40 -07:00

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\ path_plan9.go\
sys_plan9.go\ sys_plan9.go\
exec_plan9.go\ exec_plan9.go\
str.go\
GOFILES+=$(GOFILES_$(GOOS)) 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 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 // Exec replaces the current process with an execution of the
// named binary, with arguments argv and environment envv. // named binary, with arguments argv and environment envv.
// If successful, Exec never returns. If it fails, it returns an Error. // 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. // methods on the returned File can be used for I/O.
// It returns the File and an Error, if any. // It returns the File and an Error, if any.
func OpenFile(name string, flag int, perm uint32) (file *File, err Error) { func OpenFile(name string, flag int, perm uint32) (file *File, err Error) {
var fd int var (
var e syscall.Error 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() syscall.ForkLock.RLock()
if flag&O_CREATE == O_CREATE { if (create && trunc) || excl {
fd, e = syscall.Create(name, flag & ^O_CREATE, perm) fd, e = syscall.Create(name, flag, perm)
} else { } else {
fd, e = syscall.Open(name, flag) 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() 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} 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 return NewFile(fd, name), nil
} }
@ -69,8 +104,12 @@ func (file *File) Close() Error {
// Stat returns the FileInfo structure describing file. // Stat returns the FileInfo structure describing file.
// It returns the FileInfo and an error, if any. // It returns the FileInfo and an error, if any.
func (file *File) Stat() (fi *FileInfo, err Error) { func (f *File) Stat() (fi *FileInfo, err Error) {
return dirstat(file) d, err := dirstat(f)
if iserror(err) {
return nil, err
}
return fileInfoFromStat(new(FileInfo), d), err
} }
// Truncate changes the size of the file. // 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. // Chmod changes the mode of the file to mode.
func (f *File) Chmod(mode uint32) Error { func (f *File) Chmod(mode uint32) Error {
var d Dir var d Dir
var mask = ^uint32(0777)
d.Null() 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) { if e := syscall.Fwstat(f.fd, pdir(nil, &d)); iserror(e) {
return &PathError{"chmod", f.name, 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. // Chmod changes the mode of the named file to mode.
func Chmod(name string, mode uint32) Error { func Chmod(name string, mode uint32) Error {
var d Dir var d Dir
var mask = ^uint32(0777)
d.Null() 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) { if e := syscall.Wstat(name, pdir(nil, &d)); iserror(e) {
return &PathError{"chmod", name, e} return &PathError{"chmod", name, e}
} }

View File

@ -359,8 +359,8 @@ func TestReaddirNValues(t *testing.T) {
} }
func TestHardLink(t *testing.T) { func TestHardLink(t *testing.T) {
// Hardlinks are not supported under windows. // Hardlinks are not supported under windows or Plan 9.
if syscall.OS == "windows" { if syscall.OS == "windows" || syscall.OS == "plan9" {
return return
} }
from, to := "hardlinktestfrom", "hardlinktestto" from, to := "hardlinktestfrom", "hardlinktestto"
@ -392,8 +392,8 @@ func TestHardLink(t *testing.T) {
} }
func TestSymLink(t *testing.T) { func TestSymLink(t *testing.T) {
// Symlinks are not supported under windows. // Symlinks are not supported under windows or Plan 9.
if syscall.OS == "windows" { if syscall.OS == "windows" || syscall.OS == "plan9" {
return return
} }
from, to := "symlinktestfrom", "symlinktestto" from, to := "symlinktestfrom", "symlinktestto"
@ -454,8 +454,8 @@ func TestSymLink(t *testing.T) {
} }
func TestLongSymlink(t *testing.T) { func TestLongSymlink(t *testing.T) {
// Symlinks are not supported under windows. // Symlinks are not supported under windows or Plan 9.
if syscall.OS == "windows" { if syscall.OS == "windows" || syscall.OS == "plan9" {
return return
} }
s := "0123456789abcdef" s := "0123456789abcdef"
@ -588,8 +588,9 @@ func checkUidGid(t *testing.T, path string, uid, gid int) {
} }
func TestChown(t *testing.T) { func TestChown(t *testing.T) {
// Chown is not supported under windows. // Chown is not supported under windows or Plan 9.
if syscall.OS == "windows" { // Plan9 provides a native ChownPlan9 version instead.
if syscall.OS == "windows" || syscall.OS == "plan9" {
return return
} }
// Use TempDir() to make sure we're on a local file system, // 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) 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", t.Errorf("Atime_ns didn't go backwards; was=%d, after=%d",
preStat.Atime_ns, preStat.Atime_ns,
postStat.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 // These are chosen carefully not to be symlinks on a Mac
// (unlike, say, /var, /etc, and /tmp). // (unlike, say, /var, /etc, and /tmp).
dirs := []string{"/", "/usr/bin"} 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 mode := 0; mode < 2; mode++ {
for _, d := range dirs { for _, d := range dirs {
if mode == 0 { if mode == 0 {
@ -858,10 +867,18 @@ func TestOpenError(t *testing.T) {
t.Errorf("Open(%q, %d) returns error of %T type; want *os.PathError", tt.path, tt.mode, err) t.Errorf("Open(%q, %d) returns error of %T type; want *os.PathError", tt.path, tt.mode, err)
} }
if perr.Error != tt.error { if perr.Error != tt.error {
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()) t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, perr.Error.String(), tt.error.String())
} }
} }
} }
}
func run(t *testing.T, cmd []string) string { func run(t *testing.T, cmd []string) string {
// Run /bin/hostname and collect output. // Run /bin/hostname and collect output.
@ -893,7 +910,8 @@ func run(t *testing.T, cmd []string) string {
func TestHostname(t *testing.T) { func TestHostname(t *testing.T) {
// There is no other way to fetch hostname on windows, but via winapi. // 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 return
} }
// Check internal Hostname() against the output of /bin/hostname. // 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) { func TestMkdirAllWithSymlink(t *testing.T) {
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
t.Log("Skipping test: symlinks don't exist under Windows") t.Log("Skipping test: symlinks don't exist under Windows/Plan 9")
return return
} }
@ -191,7 +191,7 @@ func TestMkdirAllWithSymlink(t *testing.T) {
} }
func TestMkdirAllAtSlash(t *testing.T) { func TestMkdirAllAtSlash(t *testing.T) {
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
return return
} }
RemoveAll("/_go_os_test") 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. // 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 var name string
nd := syscall.STATFIXLEN + 16*4 nd := syscall.STATFIXLEN + 16*4
@ -62,8 +62,7 @@ func dirstat(arg interface{}) (fi *FileInfo, err Error) {
if e != nil { if e != nil {
return nil, &PathError{"stat", name, e} return nil, &PathError{"stat", name, e}
} }
return d, e
return fileInfoFromStat(new(FileInfo), d), nil
} }
} }
@ -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. // Stat returns a FileInfo structure describing the named file and an error, if any.
func Stat(name string) (fi *FileInfo, err Error) { 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 // 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), // 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. // the returned FileInfo describes the symbolic link. Lstat makes no attempt to follow the link.
func Lstat(name string) (fi *FileInfo, err Error) { 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,19 +19,17 @@ enum {
OREAD = 0, // open for read OREAD = 0, // open for read
OWRITE = 1, // write OWRITE = 1, // write
ORDWR = 2, // read and 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_RDONLY = OREAD,
$O_WRONLY = OWRITE, $O_WRONLY = OWRITE,
$O_RDWR = ORDWR, $O_RDWR = ORDWR,
$O_TRUNC = OTRUNC,
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, $O_CLOEXEC = OCEXEC,
ORCLOSE = 64, // or'ed in, remove on close
OEXCL = 0x1000, // or'ed in, exclusive use (create only)
$O_EXCL = OEXCL, $O_EXCL = OEXCL,
$STATMAX = 65535U, $STATMAX = 65535U,

View File

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

View File

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