Commit f0a8b610 authored by Akshat Kumar's avatar Akshat Kumar Committed by Ron Minnich

net, os, syscall: Plan 9: adjust error handling

syscall: Use NewError for all system errors and introduce
        some new errors for compatibility with other packages
        and proper error handling in net. Also introduce
        Temporary and Timeout methods on ErrorString.

net: Make errors from dial, accept, listen functions follow the
        OpError standard and discern whether the underlying
        error came from syscall. Since Plan 9 uses a correspondence
        between file and network operations, all system error
        reporting happens through the underlying file operation.
        In Go code, we go through package os for file operations,
        so there is another level of indirection in error types.
        This change allows us to compare the errors with those in
        package syscall, when appropriate.

os: Just use the error string already present in package os,
        instead of calling out to package syscall.

R=rsc, ality, rminnich, bradfitz
CC=golang-dev
https://golang.org/cl/7398054
parent 1f62a784
...@@ -9,6 +9,7 @@ package net ...@@ -9,6 +9,7 @@ package net
import ( import (
"errors" "errors"
"os" "os"
"syscall"
) )
// /sys/include/ape/sys/socket.h:/SOMAXCONN // /sys/include/ape/sys/socket.h:/SOMAXCONN
...@@ -104,50 +105,58 @@ func startPlan9(net string, addr Addr) (ctl *os.File, dest, proto, name string, ...@@ -104,50 +105,58 @@ func startPlan9(net string, addr Addr) (ctl *os.File, dest, proto, name string,
return f, dest, proto, string(buf[:n]), nil return f, dest, proto, string(buf[:n]), nil
} }
func dialPlan9(net string, laddr, raddr Addr) (*netFD, error) { func netErr(e error) {
oe, ok := e.(*OpError)
if !ok {
return
}
if pe, ok := oe.Err.(*os.PathError); ok {
if _, ok = pe.Err.(syscall.ErrorString); ok {
oe.Err = pe.Err
}
}
}
func dialPlan9(net string, laddr, raddr Addr) (fd *netFD, err error) {
defer func() { netErr(err) }()
f, dest, proto, name, err := startPlan9(net, raddr) f, dest, proto, name, err := startPlan9(net, raddr)
if err != nil { if err != nil {
return nil, err return nil, &OpError{"dial", net, raddr, err}
} }
_, err = f.WriteString("connect " + dest) _, err = f.WriteString("connect " + dest)
if err != nil { if err != nil {
f.Close() f.Close()
return nil, err return nil, &OpError{"dial", f.Name(), raddr, err}
} }
data, err := os.OpenFile("/net/"+proto+"/"+name+"/data", os.O_RDWR, 0) data, err := os.OpenFile("/net/"+proto+"/"+name+"/data", os.O_RDWR, 0)
if err != nil { if err != nil {
f.Close() f.Close()
return nil, err return nil, &OpError{"dial", net, raddr, err}
} }
laddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/local") laddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/local")
if err != nil { if err != nil {
data.Close() data.Close()
f.Close() f.Close()
return nil, err return nil, &OpError{"dial", proto, raddr, err}
}
raddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/remote")
if err != nil {
data.Close()
f.Close()
return nil, err
} }
return newFD(proto, name, f, data, laddr, raddr), nil return newFD(proto, name, f, data, laddr, raddr), nil
} }
func listenPlan9(net string, laddr Addr) (*netFD, error) { func listenPlan9(net string, laddr Addr) (fd *netFD, err error) {
defer func() { netErr(err) }()
f, dest, proto, name, err := startPlan9(net, laddr) f, dest, proto, name, err := startPlan9(net, laddr)
if err != nil { if err != nil {
return nil, err return nil, &OpError{"listen", net, laddr, err}
} }
_, err = f.WriteString("announce " + dest) _, err = f.WriteString("announce " + dest)
if err != nil { if err != nil {
f.Close() f.Close()
return nil, err return nil, &OpError{"announce", proto, laddr, err}
} }
laddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/local") laddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/local")
if err != nil { if err != nil {
f.Close() f.Close()
return nil, err return nil, &OpError{Op: "listen", Net: net, Err: err}
} }
return newFD(proto, name, f, nil, laddr, nil), nil return newFD(proto, name, f, nil, laddr, nil), nil
} }
...@@ -156,28 +165,29 @@ func (l *netFD) netFD() *netFD { ...@@ -156,28 +165,29 @@ func (l *netFD) netFD() *netFD {
return newFD(l.proto, l.name, l.ctl, l.data, l.laddr, l.raddr) return newFD(l.proto, l.name, l.ctl, l.data, l.laddr, l.raddr)
} }
func (l *netFD) acceptPlan9() (*netFD, error) { func (l *netFD) acceptPlan9() (fd *netFD, err error) {
defer func() { netErr(err) }()
f, err := os.Open(l.dir + "/listen") f, err := os.Open(l.dir + "/listen")
if err != nil { if err != nil {
return nil, err return nil, &OpError{"accept", l.dir + "/listen", l.laddr, err}
} }
var buf [16]byte var buf [16]byte
n, err := f.Read(buf[:]) n, err := f.Read(buf[:])
if err != nil { if err != nil {
f.Close() f.Close()
return nil, err return nil, &OpError{"accept", l.dir + "/listen", l.laddr, err}
} }
name := string(buf[:n]) name := string(buf[:n])
data, err := os.OpenFile("/net/"+l.proto+"/"+name+"/data", os.O_RDWR, 0) data, err := os.OpenFile("/net/"+l.proto+"/"+name+"/data", os.O_RDWR, 0)
if err != nil { if err != nil {
f.Close() f.Close()
return nil, err return nil, &OpError{"accept", l.proto, l.laddr, err}
} }
raddr, err := readPlan9Addr(l.proto, "/net/"+l.proto+"/"+name+"/remote") raddr, err := readPlan9Addr(l.proto, "/net/"+l.proto+"/"+name+"/remote")
if err != nil { if err != nil {
data.Close() data.Close()
f.Close() f.Close()
return nil, err return nil, &OpError{"accept", l.proto, l.laddr, err}
} }
return newFD(l.proto, name, f, data, l.laddr, raddr), nil return newFD(l.proto, name, f, data, l.laddr, raddr), nil
} }
...@@ -89,7 +89,7 @@ func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, e ...@@ -89,7 +89,7 @@ func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, e
switch net { switch net {
case "tcp", "tcp4", "tcp6": case "tcp", "tcp4", "tcp6":
default: default:
return nil, UnknownNetworkError(net) return nil, &OpError{"dial", net, raddr, UnknownNetworkError(net)}
} }
if raddr == nil { if raddr == nil {
return nil, &OpError{"dial", net, nil, errMissingAddress} return nil, &OpError{"dial", net, nil, errMissingAddress}
...@@ -141,7 +141,7 @@ func (l *TCPListener) Close() error { ...@@ -141,7 +141,7 @@ func (l *TCPListener) Close() error {
} }
if _, err := l.fd.ctl.WriteString("hangup"); err != nil { if _, err := l.fd.ctl.WriteString("hangup"); err != nil {
l.fd.ctl.Close() l.fd.ctl.Close()
return err return &OpError{"close", l.fd.ctl.Name(), l.fd.laddr, err}
} }
return l.fd.ctl.Close() return l.fd.ctl.Close()
} }
...@@ -171,7 +171,7 @@ func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) { ...@@ -171,7 +171,7 @@ func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
switch net { switch net {
case "tcp", "tcp4", "tcp6": case "tcp", "tcp4", "tcp6":
default: default:
return nil, UnknownNetworkError(net) return nil, &OpError{"listen", net, laddr, UnknownNetworkError(net)}
} }
if laddr == nil { if laddr == nil {
laddr = &TCPAddr{} laddr = &TCPAddr{}
......
...@@ -8,7 +8,6 @@ import ( ...@@ -8,7 +8,6 @@ import (
"errors" "errors"
"os" "os"
"strings" "strings"
"syscall"
) )
// ErrNotFound is the error resulting if a path search failed to find an executable file. // ErrNotFound is the error resulting if a path search failed to find an executable file.
...@@ -22,7 +21,7 @@ func findExecutable(file string) error { ...@@ -22,7 +21,7 @@ func findExecutable(file string) error {
if m := d.Mode(); !m.IsDir() && m&0111 != 0 { if m := d.Mode(); !m.IsDir() && m&0111 != 0 {
return nil return nil
} }
return syscall.EPERM return os.ErrPermission
} }
// LookPath searches for an executable binary named file // LookPath searches for an executable binary named file
......
...@@ -23,6 +23,14 @@ func (e ErrorString) Error() string { return string(e) } ...@@ -23,6 +23,14 @@ func (e ErrorString) Error() string { return string(e) }
// NewError converts s to an ErrorString, which satisfies the Error interface. // NewError converts s to an ErrorString, which satisfies the Error interface.
func NewError(s string) error { return ErrorString(s) } 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. // A Note is a string describing a process note.
// It implements the os.Signal interface. // It implements the os.Signal interface.
type Note string type Note string
...@@ -37,9 +45,6 @@ var ( ...@@ -37,9 +45,6 @@ var (
Stdin = 0 Stdin = 0
Stdout = 1 Stdout = 1
Stderr = 2 Stderr = 2
EAFNOSUPPORT = NewError("address family not supported by protocol")
EISDIR = NewError("file is a directory")
) )
// For testing: clients can set this flag to force // For testing: clients can set this flag to force
......
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
package syscall package syscall
import "errors"
// Constants // Constants
const ( const (
// Invented values to support what package os expects. // Invented values to support what package os expects.
...@@ -28,12 +26,23 @@ const ( ...@@ -28,12 +26,23 @@ const (
// Errors // Errors
var ( var (
EINVAL = errors.New("bad arg in system call") EINVAL = NewError("bad arg in system call")
ENOTDIR = errors.New("not a directory") ENOTDIR = NewError("not a directory")
ENOENT = errors.New("file does not exist") EISDIR = NewError("file is a directory")
EEXIST = errors.New("file already exists") ENOENT = NewError("file does not exist")
EIO = errors.New("i/o error") EEXIST = NewError("file already exists")
ENAMETOOLONG = errors.New("file name too long") EMFILE = NewError("no free file descriptors")
EPERM = errors.New("permission denied") EIO = NewError("i/o error")
EPLAN9 = errors.New("not supported by plan 9") 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")
) )
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
package syscall package syscall
import "errors"
// Constants // Constants
const ( const (
// Invented values to support what package os expects. // Invented values to support what package os expects.
...@@ -28,12 +26,23 @@ const ( ...@@ -28,12 +26,23 @@ const (
// Errors // Errors
var ( var (
EINVAL = errors.New("bad arg in system call") EINVAL = NewError("bad arg in system call")
ENOTDIR = errors.New("not a directory") ENOTDIR = NewError("not a directory")
ENOENT = errors.New("file does not exist") EISDIR = NewError("file is a directory")
EEXIST = errors.New("file already exists") ENOENT = NewError("file does not exist")
EIO = errors.New("i/o error") EEXIST = NewError("file already exists")
ENAMETOOLONG = errors.New("file name too long") EMFILE = NewError("no free file descriptors")
EPERM = errors.New("permission denied") EIO = NewError("i/o error")
EPLAN9 = errors.New("not supported by plan 9") 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")
) )
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment