diff --git a/internal/p9/server.go b/internal/p9/server.go index 0f8f133..eb95685 100644 --- a/internal/p9/server.go +++ b/internal/p9/server.go @@ -111,6 +111,7 @@ type Server struct { planStore Store memStore Store toolStore Store + utilStore Store skillStore Store sessionStore Store batchStore *BatchStore @@ -136,6 +137,7 @@ func New() *Server { planStore: NewFlatDirStore(defaultPlanDir(), 0644), memStore: NewFlatDirStore(memDir, 0644), toolStore: NewToolStore(), + utilStore: NewUtilStore(), skillStore: NewSkillStore(), transcriptStore: NewFlatDirStore(transcriptDir, 0444), tmpStore: NewFlatDirStore(tmpDir, 0600), @@ -321,6 +323,12 @@ func (s *Server) pathType(path string) string { return "dir" case len(parts) == 1 && parts[0] == "t": return "dir" + case len(parts) == 1 && parts[0] == "u": + return "dir" + case len(parts) == 2 && parts[0] == "u": + if _, err := s.utilStore.Stat(parts[1]); err == nil { + return "file" + } case len(parts) == 1 && parts[0] == "tr": return "dir" case len(parts) == 2 && parts[0] == "tr": @@ -331,7 +339,7 @@ func (s *Server) pathType(path string) string { return "dir" case len(parts) == 2 && parts[0] == "b": switch parts[1] { - case "new", "idx": + case "new", "idx", "q", "sched": return "file" default: if _, err := s.batchStore.Stat(parts[1]); err == nil { @@ -567,6 +575,14 @@ func (s *Server) read(cs *connState, fc *plan9.Fcall) *plan9.Fcall { } return s.readSlice(fc, content) } + if path == "/b/q" || path == "/b/sched" { + plog.Debug("Tread path=%q offset=%d count=%d", path, fc.Offset, fc.Count) + content, err := os.ReadFile(paths.CfgDir() + "/scripts/b/" + pathBase(path)) + if err != nil { + return errFcall(fc, err.Error()) + } + return s.readSlice(fc, content) + } if strings.HasPrefix(path, "/b/") { parts := strings.SplitN(strings.TrimPrefix(path, "/"), "/", 3) if len(parts) == 3 && parts[0] == "b" { @@ -672,6 +688,16 @@ func (s *Server) read(cs *connState, fc *plan9.Fcall) *plan9.Fcall { return s.readSlice(fc, content) } + // Util files are served from the util store. + if strings.HasPrefix(path, "/u/") { + plog.Debug("Tread path=%q offset=%d count=%d", path, fc.Offset, fc.Count) + content, err := s.utilStore.Get(pathBase(path)) + if err != nil { + return errFcall(fc, err.Error()) + } + return s.readSlice(fc, content) + } + // Tmp files are served from the tmp store. if strings.HasPrefix(path, "/tmp/") { plog.Debug("Tread path=%q offset=%d count=%d", path, fc.Offset, fc.Count) @@ -1276,6 +1302,7 @@ func (s *Server) readDir(path string, offset uint64, count uint32) []byte { dirs = append(dirs, makeDir("sk", "/sk", true, plan9.DMDIR|0555)) dirs = append(dirs, makeDir("t", "/t", true, plan9.DMDIR|0777)) dirs = append(dirs, makeDir("tmp", "/tmp", true, plan9.DMDIR|0755)) + dirs = append(dirs, makeDir("u", "/u", true, plan9.DMDIR|0755)) dirs = append(dirs, makeDir("tr", "/tr", true, plan9.DMDIR|0555)) } else if path == "/a" { entries, _ := s.agentStore.List() @@ -1357,7 +1384,14 @@ func (s *Server) readDir(path string, offset uint64, count uint32) []byte { dirs = append(dirs, d) } } + } else if path == "/u" { + entries, _ := s.utilStore.List() + for _, e := range entries { + dirs = append(dirs, makeDir(e.Name(), "/u/"+e.Name(), false, 0555)) + } } else if path == "/b" { + dirs = append(dirs, makeDir("q", "/b/q", false, 0555)) + dirs = append(dirs, makeDir("sched", "/b/sched", false, 0555)) entries, _ := s.batchStore.List() for _, e := range entries { isDir := e.IsDir() @@ -1448,7 +1482,7 @@ func (s *Server) makeStat(path string) plan9.Dir { qid.Type = QTDir if path == "/t" { mode = plan9.DMDIR | 0777 - } else if path == "/a" || path == "/m" || path == "/pl" || path == "/tmp" { + } else if path == "/a" || path == "/m" || path == "/pl" || path == "/tmp" || path == "/u" { mode = plan9.DMDIR | 0755 } else { mode = plan9.DMDIR | 0555 @@ -1482,6 +1516,10 @@ func (s *Server) makeStat(path string) plan9.Dir { mode = 0444 } else if strings.HasPrefix(path, "/t/") { mode = 0777 + } else if strings.HasPrefix(path, "/u/") { + mode = 0555 + } else if path == "/b/q" || path == "/b/sched" { + mode = 0555 } else { mode = 0444 } @@ -1563,6 +1601,14 @@ func (s *Server) makeStat(path string) plan9.Dir { if content, err := s.toolStore.Get(base); err == nil { dir.Length = uint64(len(content)) } + case strings.HasPrefix(path, "/u/"): + if content, err := s.utilStore.Get(base); err == nil { + dir.Length = uint64(len(content)) + } + case path == "/b/q" || path == "/b/sched": + if content, err := os.ReadFile(paths.CfgDir() + "/scripts/b/" + base); err == nil { + dir.Length = uint64(len(content)) + } case strings.HasPrefix(path, "/tmp/"): if info, err := s.tmpStore.Stat(base); err == nil { dir.Length = uint64(info.Size()) diff --git a/internal/p9/sessionstore.go b/internal/p9/sessionstore.go index 31dcc81..c8b43ac 100644 --- a/internal/p9/sessionstore.go +++ b/internal/p9/sessionstore.go @@ -12,19 +12,16 @@ import ( // Add an entry here to expose a new file; the server uses this map for // routing, mode, and stat length. var sessionStoreFiles = map[string]os.FileMode{ - "new": 0666, - "idx": 0444, - "ls": 0555, - "kill": 0555, - "sh": 0555, - "job": 0555, - "q": 0555, - "sched": 0555, - "optimize": 0555, + "new": 0666, + "idx": 0444, + "ls": 0555, + "kill": 0555, + "sh": 0555, + "job": 0555, } // sessionStoreOrder defines the listing order for fixed s/ entries. -var sessionStoreOrder = []string{"new", "idx", "ls", "kill", "sh", "job", "q", "sched", "optimize"} +var sessionStoreOrder = []string{"new", "idx", "ls", "kill", "sh", "job"} // SessionStore implements Store for the /s/ directory. // Entries are session IDs (directories) plus the synthetic files "new" and "idx". @@ -67,7 +64,7 @@ func (s *SessionStore) Get(name string) ([]byte, error) { return s.index(), nil default: if _, ok := sessionStoreFiles[name]; ok { - return os.ReadFile(paths.CfgDir() + "/scripts/" + name) + return os.ReadFile(paths.CfgDir() + "/scripts/s/" + name) } } return nil, fmt.Errorf("%s: not a readable file", name) diff --git a/internal/p9/utilstore.go b/internal/p9/utilstore.go new file mode 100644 index 0000000..59d40a5 --- /dev/null +++ b/internal/p9/utilstore.go @@ -0,0 +1,28 @@ +package p9 + +import ( + "os" + + "ollie/pkg/paths" +) + +// UtilStore is a FlatDirStore backed by the scripts/u/ directory. +type UtilStore struct { + *FlatDirStore +} + +func NewUtilStore() *UtilStore { + return &UtilStore{FlatDirStore: NewFlatDirStore(paths.CfgDir()+"/scripts/u", 0555)} +} + +func (s *UtilStore) Stat(name string) (os.FileInfo, error) { + return s.FlatDirStore.Stat(name) +} + +func (s *UtilStore) List() ([]os.DirEntry, error) { + return s.FlatDirStore.List() +} + +func (s *UtilStore) Get(name string) ([]byte, error) { + return s.FlatDirStore.Get(name) +}