diff --git a/cmd/ufs/ufs.go b/cmd/ufs/ufs.go index d1e023e..d86b0db 100644 --- a/cmd/ufs/ufs.go +++ b/cmd/ufs/ufs.go @@ -9,6 +9,7 @@ import ( "log" "net" + "github.com/Harvey-OS/ninep/debug" "github.com/Harvey-OS/ninep/filesystem" "github.com/Harvey-OS/ninep/protocol" ) @@ -16,22 +17,38 @@ import ( var ( ntype = flag.String("ntype", "tcp4", "Default network type") naddr = flag.String("addr", ":5640", "Network address") + root = flag.String("root", "/", "filesystem root") + trace = flag.Bool("trace", false, "enable debug messages") ) +func checkErr(format string, err error) { + if err != nil { + log.Fatalf(format, err) + } +} + func main() { flag.Parse() - ln, err := net.Listen(*ntype, *naddr) - if err != nil { - log.Fatalf("Listen failed: %v", err) + tracer := func(format string, args ...interface{}) {} + if *trace { + tracer = log.Printf } - s, err := ufs.NewUFS(func(s *protocol.Server) error { - s.Trace = nil // log.Printf - return nil - }) + ln, err := net.Listen(*ntype, *naddr) + checkErr("Listen failed: %v", err) + + fs, err := ufs.NewServer(ufs.Root(*root), ufs.Trace(tracer)) + checkErr("ufs.NewServer failed: %v", err) - if err := s.Serve(ln); err != nil { - log.Fatal(err) + var ninefs protocol.NineServer = fs + if *trace { + ninefs, err = debug.NewServer(ninefs, debug.Trace(tracer)) + checkErr("debug.NewServer failed: %v", err) } + + s, err := protocol.NewServer(ninefs, protocol.Trace(tracer)) + checkErr("protocol.NewServer failed: %v", err) + + checkErr("Serve failed: %v", s.Serve(ln)) } diff --git a/debug/debug.go b/debug/debug.go new file mode 100644 index 0000000..f8b82ed --- /dev/null +++ b/debug/debug.go @@ -0,0 +1,184 @@ +// Copyright 2009 The Ninep 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 debug + +import ( + "bytes" + "errors" + + "github.com/Harvey-OS/ninep/protocol" +) + +type Server struct { + protocol.NineServer + + trace protocol.Tracer +} + +type ServerOpt func(*Server) error + +func NewServer(s protocol.NineServer, opts ...ServerOpt) (*Server, error) { + s2 := &Server{ + NineServer: s, + trace: nologf, + } + + for _, opt := range opts { + if err := opt(s2); err != nil { + return nil, err + } + } + + return s2, nil +} + +func Trace(tracer protocol.Tracer) ServerOpt { + return func(s *Server) error { + if tracer == nil { + return errors.New("tracer cannot be nil") + } + s.trace = tracer + return nil + } +} + +// nologf does nothing and is the default trace function +func nologf(format string, args ...interface{}) {} + +func (s *Server) Rversion(msize protocol.MaxSize, version string) (protocol.MaxSize, string, error) { + s.trace(">>> Tversion %v %v\n", msize, version) + msize, version, err := s.NineServer.Rversion(msize, version) + if err == nil { + s.trace("<<< Rversion %v %v\n", msize, version) + } else { + s.trace("<<< Error %v\n", err) + } + return msize, version, err +} + +func (s *Server) Rattach(fid protocol.FID, afid protocol.FID, uname string, aname string) (protocol.QID, error) { + s.trace(">>> Tattach fid %v, afid %v, uname %v, aname %v\n", fid, afid, + uname, aname) + qid, err := s.NineServer.Rattach(fid, afid, uname, aname) + if err == nil { + s.trace("<<< Rattach %v\n", qid) + } else { + s.trace("<<< Error %v\n", err) + } + return qid, err +} + +func (s *Server) Rflush(o protocol.Tag) error { + s.trace(">>> Tflush tag %v\n", o) + err := s.NineServer.Rflush(o) + if err == nil { + s.trace("<<< Rflush\n") + } else { + s.trace("<<< Error %v\n", err) + } + return err +} + +func (s *Server) Rwalk(fid protocol.FID, newfid protocol.FID, paths []string) ([]protocol.QID, error) { + s.trace(">>> Twalk fid %v, newfid %v, paths %v\n", fid, newfid, paths) + qid, err := s.NineServer.Rwalk(fid, newfid, paths) + if err == nil { + s.trace("<<< Rwalk %v\n", qid) + } else { + s.trace("<<< Error %v\n", err) + } + return qid, err +} + +func (s *Server) Ropen(fid protocol.FID, mode protocol.Mode) (protocol.QID, protocol.MaxSize, error) { + s.trace(">>> Topen fid %v, mode %v\n", fid, mode) + qid, iounit, err := s.NineServer.Ropen(fid, mode) + if err == nil { + s.trace("<<< Ropen %v %v\n", qid, iounit) + } else { + s.trace("<<< Error %v\n", err) + } + return qid, iounit, err +} + +func (s *Server) Rcreate(fid protocol.FID, name string, perm protocol.Perm, mode protocol.Mode) (protocol.QID, protocol.MaxSize, error) { + s.trace(">>> Tcreate fid %v, name %v, perm %v, mode %v\n", fid, name, + perm, mode) + qid, iounit, err := s.NineServer.Rcreate(fid, name, perm, mode) + if err == nil { + s.trace("<<< Rcreate %v %v\n", qid, iounit) + } else { + s.trace("<<< Error %v\n", err) + } + return qid, iounit, err +} + +func (s *Server) Rclunk(fid protocol.FID) error { + s.trace(">>> Tclunk fid %v\n", fid) + err := s.NineServer.Rclunk(fid) + if err == nil { + s.trace("<<< Rclunk\n") + } else { + s.trace("<<< Error %v\n", err) + } + return err +} + +func (s *Server) Rstat(fid protocol.FID) ([]byte, error) { + s.trace(">>> Tstat fid %v\n", fid) + b, err := s.NineServer.Rstat(fid) + if err == nil { + dir, _ := protocol.Unmarshaldir(bytes.NewBuffer(b)) + s.trace("<<< Rstat %v\n", dir) + } else { + s.trace("<<< Error %v\n", err) + } + return b, err +} + +func (s *Server) Rwstat(fid protocol.FID, b []byte) error { + dir, _ := protocol.Unmarshaldir(bytes.NewBuffer(b)) + s.trace(">>> Twstat fid %v, %v\n", fid, dir) + err := s.NineServer.Rwstat(fid, b) + if err == nil { + s.trace("<<< Rwstat\n") + } else { + s.trace("<<< Error %v\n", err) + } + return err +} + +func (s *Server) Rremove(fid protocol.FID) error { + s.trace(">>> Tremove fid %v\n", fid) + err := s.NineServer.Rremove(fid) + if err == nil { + s.trace("<<< Rremove\n") + } else { + s.trace("<<< Error %v\n", err) + } + return err +} + +func (s *Server) Rread(fid protocol.FID, o protocol.Offset, c protocol.Count) ([]byte, error) { + s.trace(">>> Tread fid %v, off %v, count %v\n", fid, o, c) + b, err := s.NineServer.Rread(fid, o, c) + if err == nil { + s.trace("<<< Rread %v\n", len(b)) + } else { + s.trace("<<< Error %v\n", err) + } + return b, err +} + +func (s *Server) Rwrite(fid protocol.FID, o protocol.Offset, b []byte) (protocol.Count, error) { + s.trace(">>> Twrite fid %v, off %v, count %v\n", fid, o, len(b)) + c, err := s.NineServer.Rwrite(fid, o, b) + if err == nil { + s.trace("<<< Rwrite %v\n", c) + } else { + s.trace("<<< Error %v\n", err) + } + return c, err +} diff --git a/filesystem/debug.go b/filesystem/debug.go deleted file mode 100644 index 11f1ee4..0000000 --- a/filesystem/debug.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2009 The Ninep 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 ufs - -import ( - "bytes" - "log" - - "github.com/Harvey-OS/ninep/protocol" -) - -type debugFileServer struct { - *FileServer -} - -func (e *debugFileServer) Rversion(msize protocol.MaxSize, version string) (protocol.MaxSize, string, error) { - log.Printf(">>> Tversion %v %v\n", msize, version) - msize, version, err := e.FileServer.Rversion(msize, version) - if err == nil { - log.Printf("<<< Rversion %v %v\n", msize, version) - } else { - log.Printf("<<< Error %v\n", err) - } - return msize, version, err -} - -func (e *debugFileServer) Rattach(fid protocol.FID, afid protocol.FID, uname string, aname string) (protocol.QID, error) { - log.Printf(">>> Tattach fid %v, afid %v, uname %v, aname %v\n", fid, afid, - uname, aname) - qid, err := e.FileServer.Rattach(fid, afid, uname, aname) - if err == nil { - log.Printf("<<< Rattach %v\n", qid) - } else { - log.Printf("<<< Error %v\n", err) - } - return qid, err -} - -func (e *debugFileServer) Rflush(o protocol.Tag) error { - log.Printf(">>> Tflush tag %v\n", o) - err := e.FileServer.Rflush(o) - if err == nil { - log.Printf("<<< Rflush\n") - } else { - log.Printf("<<< Error %v\n", err) - } - return err -} - -func (e *debugFileServer) Rwalk(fid protocol.FID, newfid protocol.FID, paths []string) ([]protocol.QID, error) { - log.Printf(">>> Twalk fid %v, newfid %v, paths %v\n", fid, newfid, paths) - qid, err := e.FileServer.Rwalk(fid, newfid, paths) - if err == nil { - log.Printf("<<< Rwalk %v\n", qid) - } else { - log.Printf("<<< Error %v\n", err) - } - return qid, err -} - -func (e *debugFileServer) Ropen(fid protocol.FID, mode protocol.Mode) (protocol.QID, protocol.MaxSize, error) { - log.Printf(">>> Topen fid %v, mode %v\n", fid, mode) - qid, iounit, err := e.FileServer.Ropen(fid, mode) - if err == nil { - log.Printf("<<< Ropen %v %v\n", qid, iounit) - } else { - log.Printf("<<< Error %v\n", err) - } - return qid, iounit, err -} - -func (e *debugFileServer) Rcreate(fid protocol.FID, name string, perm protocol.Perm, mode protocol.Mode) (protocol.QID, protocol.MaxSize, error) { - log.Printf(">>> Tcreate fid %v, name %v, perm %v, mode %v\n", fid, name, - perm, mode) - qid, iounit, err := e.FileServer.Rcreate(fid, name, perm, mode) - if err == nil { - log.Printf("<<< Rcreate %v %v\n", qid, iounit) - } else { - log.Printf("<<< Error %v\n", err) - } - return qid, iounit, err -} - -func (e *debugFileServer) Rclunk(fid protocol.FID) error { - log.Printf(">>> Tclunk fid %v\n", fid) - err := e.FileServer.Rclunk(fid) - if err == nil { - log.Printf("<<< Rclunk\n") - } else { - log.Printf("<<< Error %v\n", err) - } - return err -} - -func (e *debugFileServer) Rstat(fid protocol.FID) ([]byte, error) { - log.Printf(">>> Tstat fid %v\n", fid) - b, err := e.FileServer.Rstat(fid) - if err == nil { - dir, _ := protocol.Unmarshaldir(bytes.NewBuffer(b)) - log.Printf("<<< Rstat %v\n", dir) - } else { - log.Printf("<<< Error %v\n", err) - } - return b, err -} - -func (e *debugFileServer) Rwstat(fid protocol.FID, b []byte) error { - dir, _ := protocol.Unmarshaldir(bytes.NewBuffer(b)) - log.Printf(">>> Twstat fid %v, %v\n", fid, dir) - err := e.FileServer.Rwstat(fid, b) - if err == nil { - log.Printf("<<< Rwstat\n") - } else { - log.Printf("<<< Error %v\n", err) - } - return err -} - -func (e *debugFileServer) Rremove(fid protocol.FID) error { - log.Printf(">>> Tremove fid %v\n", fid) - err := e.FileServer.Rremove(fid) - if err == nil { - log.Printf("<<< Rremove\n") - } else { - log.Printf("<<< Error %v\n", err) - } - return err -} - -func (e *debugFileServer) Rread(fid protocol.FID, o protocol.Offset, c protocol.Count) ([]byte, error) { - log.Printf(">>> Tread fid %v, off %v, count %v\n", fid, o, c) - b, err := e.FileServer.Rread(fid, o, c) - if err == nil { - log.Printf("<<< Rread %v\n", len(b)) - } else { - log.Printf("<<< Error %v\n", err) - } - return b, err -} - -func (e *debugFileServer) Rwrite(fid protocol.FID, o protocol.Offset, b []byte) (protocol.Count, error) { - log.Printf(">>> Twrite fid %v, off %v, count %v\n", fid, o, len(b)) - c, err := e.FileServer.Rwrite(fid, o, b) - if err == nil { - log.Printf("<<< Rwrite %v\n", c) - } else { - log.Printf("<<< Error %v\n", err) - } - return c, err -} diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go index bb11357..49031ee 100644 --- a/filesystem/filesystem.go +++ b/filesystem/filesystem.go @@ -6,7 +6,7 @@ package ufs import ( "bytes" - "flag" + "errors" "fmt" "io" "log" @@ -38,12 +38,11 @@ type FileServer struct { // mu guards below mu sync.Mutex files map[protocol.FID]*file + + trace protocol.Tracer } -var ( - debug = flag.Int("debug", 0, "print debug messages") - root = flag.String("root", "/", "Set the root for all attaches") -) +type ServerOpt func(*FileServer) error func stat(s string) (*protocol.Dir, protocol.QID, error) { var q protocol.QID @@ -59,6 +58,48 @@ func stat(s string) (*protocol.Dir, protocol.QID, error) { return d, q, nil } +func NewServer(opts ...ServerOpt) (*FileServer, error) { + s := &FileServer{ + files: make(map[protocol.FID]*file), + trace: nologf, + } + + for _, opt := range opts { + if err := opt(s); err != nil { + return nil, err + } + } + + return s, nil +} + +func Root(root string) ServerOpt { + return func(s *FileServer) error { + s.rootPath = root + return nil + } +} + +func IOunit(size protocol.MaxSize) ServerOpt { + return func(s *FileServer) error { + s.IOunit = size + return nil + } +} + +func Trace(tracer protocol.Tracer) ServerOpt { + return func(s *FileServer) error { + if tracer == nil { + return errors.New("tracer cannot be nil") + } + s.trace = tracer + return nil + } +} + +// nologf does nothing and is the default trace function +func nologf(format string, args ...interface{}) {} + func (e *FileServer) Rversion(msize protocol.MaxSize, version string) (protocol.MaxSize, string, error) { if version != "9P2000" { return 0, "", fmt.Errorf("%v not supported; only 9P2000", version) @@ -441,22 +482,3 @@ func (e *FileServer) Rwrite(fid protocol.FID, o protocol.Offset, b []byte) (prot n, err := f.file.WriteAt(b, int64(o)) return protocol.Count(n), err } - -type ServerOpt func(*protocol.Server) error - -func NewUFS(opts ...protocol.ServerOpt) (*protocol.Server, error) { - f := &FileServer{} - f.files = make(map[protocol.FID]*file) - f.rootPath = *root // for now. - // any opts for the ufs layer can be added here too ... - var d protocol.NineServer = f - if *debug != 0 { - d = &debugFileServer{f} - } - s, err := protocol.NewServer(d, opts...) - if err != nil { - return nil, err - } - f.IOunit = 8192 - return s, nil -} diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go index f1771cb..b7b46f2 100644 --- a/filesystem/filesystem_test.go +++ b/filesystem/filesystem_test.go @@ -18,7 +18,7 @@ func print(f string, args ...interface{}) { } func TestNew(t *testing.T) { - n, err := NewUFS() + n, err := NewServer() if err != nil { t.Fatal(err) } @@ -79,10 +79,11 @@ func TestMount(t *testing.T) { } t.Logf("Client is %v", c.String()) - n, err := NewUFS(func(s *protocol.Server) error { - s.Trace = print //t.Logf - return nil - }) + fs, err := NewServer() + if err != nil { + t.Fatal(err) + } + n, err := protocol.NewServer(fs, protocol.Trace(print)) if err != nil { t.Fatal(err) } diff --git a/filesystem/filesystem_windows.go b/filesystem/filesystem_windows.go index 7a5ef70..70cc388 100644 --- a/filesystem/filesystem_windows.go +++ b/filesystem/filesystem_windows.go @@ -13,13 +13,13 @@ import "os" // resetDir closes the underlying file and reopens it so it can be read again. // This is because Windows doesn't seem to support calling Seek on a directory // handle. -func resetDir(f *File) error { +func resetDir(f *file) error { f2, err := os.OpenFile(f.fullName, os.O_RDONLY, 0) if err != nil { return err } - f.File.Close() - f.File = f2 + f.file.Close() + f.file = f2 return nil } diff --git a/protocol/protocol_test.go b/protocol/protocol_test.go index a16b810..2ada3de 100644 --- a/protocol/protocol_test.go +++ b/protocol/protocol_test.go @@ -330,10 +330,7 @@ func TestTManyRPCs(t *testing.T) { t.Logf("Client is %v", c.String()) e := newEcho() - s, err := NewServer(e, func(s *Server) error { - s.Trace = print - return nil - }) + s, err := NewServer(e, Trace(print)) if err != nil { t.Fatalf("NewServer: want nil, got %v", err) } @@ -368,12 +365,7 @@ func TestTMessages(t *testing.T) { t.Logf("Client is %v", c.String()) e := newEcho() - s, err := NewServer(e, func(s *Server) error { - s.Trace = print // t.Logf - s.NS = e - return nil - }) - + s, err := NewServer(e, Trace(print)) if err != nil { t.Fatalf("NewServer: want nil, got %v", err) } diff --git a/protocol/server.go b/protocol/server.go index 04037e7..3a3ae7d 100644 --- a/protocol/server.go +++ b/protocol/server.go @@ -8,6 +8,7 @@ package protocol import ( "bytes" + "errors" "fmt" "io" "net" @@ -27,8 +28,8 @@ type Server struct { // TCP address to listen on, default is DefaultAddr Addr string - // Trace function for logging - Trace Tracer + // trace function for logging + trace Tracer // mu guards below mu sync.Mutex @@ -54,9 +55,12 @@ type conn struct { } func NewServer(ns NineServer, opts ...ServerOpt) (*Server, error) { - s := &Server{} - s.NS = ns - s.D = Dispatch + s := &Server{ + NS: ns, + D: Dispatch, + trace: nologf, + } + for _, o := range opts { if err := o(s); err != nil { return nil, err @@ -65,6 +69,19 @@ func NewServer(ns NineServer, opts ...ServerOpt) (*Server, error) { return s, nil } +func Trace(tracer Tracer) ServerOpt { + return func(s *Server) error { + if tracer == nil { + return errors.New("tracer cannot be nil") + } + s.trace = tracer + return nil + } +} + +// nologf does nothing and is the default trace function +func nologf(format string, args ...interface{}) {} + func (s *Server) newConn(rwc net.Conn) *conn { c := &conn{ server: s, @@ -141,7 +158,7 @@ func (s *Server) Serve(ln net.Listener) error { if max := 1 * time.Second; tempDelay > max { tempDelay = max } - s.logf("ufs: Accept error: %v; retrying in %v", err, tempDelay) + s.trace("ufs: Accept error: %v; retrying in %v", err, tempDelay) time.Sleep(tempDelay) continue } @@ -178,19 +195,13 @@ func (s *Server) String() string { return "" } -func (s *Server) logf(format string, args ...interface{}) { - if s.Trace != nil { - s.Trace(format, args...) - } -} - func (c *conn) String() string { return fmt.Sprintf("Dead %v %d replies pending", c.dead, len(c.replies)) } func (c *conn) logf(format string, args ...interface{}) { // prepend some info about the conn - c.server.logf("[%v] "+format, append([]interface{}{c.remoteAddr}, args...)...) + c.server.trace("[%v] "+format, append([]interface{}{c.remoteAddr}, args...)...) } func (c *conn) serve() {