func NewDup(from, to string) Redirs { switch from { case "1", "2": default: dbg.Warn("%s: unknown dup %s", addr, from) nerrors++ return nil } switch to { case "1", "2": default: dbg.Warn("%s: unknown dup %s", addr, to) nerrors++ return nil } if from == to { dbg.Warn("%s: stupid dup %s %s", addr, from, to) nerrors++ return nil } return []*Redir{ { From: int(from[0] - '0'), To: int(to[0] - '0'), Name: "|=", }, } }
// If ln is "path addr" and addr is of the form // net ! addr ! proto ! tree ! path // or // /one/path // the dial the tree and walk to the path. func specialForm(ln string) (string, zx.Dir) { if len(ln)==0 || ln[0]!='/' { return "", nil } toks := strings.Fields(ln) if len(toks)!=2 || len(toks[0])==0 || len(toks[1])==0 { return "", nil } p, addr := toks[0], toks[1] if addr[0] == '/' { addr = "*!*!lfs!main!" + addr } atoks := strings.SplitN(addr, "!", -1) if len(atoks) < 2 { return "", nil } t, err := rfs.Import(addr) if err != nil { dbg.Warn("ns: %s: import: %s", ln, err) return "", nil } path := "/" if len(atoks)>=5 && atoks[2]!="lfs" { path = atoks[4] } d, err := zx.Stat(t, path) if err != nil { dbg.Warn("ns: %s: stat: %s", ln, err) return "", nil } return p, d }
/* Authenticate the wax server. To be called early within the handler function for wax pages. It returns false if auth failed and the handler should return without handling anything. When TLS is disabled, or there's no key file, auth is considered ok. */ func Auth(w http.ResponseWriter, r *http.Request) bool { if auth.TLSserver == nil || !auth.Enabled { return true } clive, err := r.Cookie("clive") if err != nil { dbg.Warn("wax/auth: no cookie: %s", err) failed(w) return false } toks := strings.SplitN(string(clive.Value), ":", 2) if len(toks) < 2 { dbg.Warn("wax/auth: wrong cookie") failed(w) return false } ch, resp := toks[0], toks[1] u, ok := auth.ChallengeResponseOk("wax", ch, resp) if !ok { dbg.Warn("wax/auth: failed for %s", u) failed(w) return false } return ok }
// Make a new repl for the given name and local and remote tree addresses. // Pred defaults to exclude all dot files and dirs: 'name~^\.&prune|true' func New(name, pred, laddr, raddr string) (*Repl, error) { r := &Repl{ Name: name, Laddr: laddr, Raddr: raddr, pred: pred, } r.vprintf = dbg.FlagPrintf(os.Stdout, &r.Verb) if err := r.dial(); err != nil { return nil, err } var err, rerr error r.Ldb, err = sync.NewDB(name + "[" + laddr + "]", pred, r.lfs) if err != nil { dbg.Warn("%s: %s", laddr, err) } r.Rdb, rerr = sync.NewDB(name + "[" + raddr + "]", pred, r.rfs) if rerr != nil { err = rerr dbg.Warn("%s: %s", raddr, rerr) } r.Ldb.Pred = r.pred r.Rdb.Pred = r.pred return r, err }
func main() { defer dbg.Exits("") os.Args[0] = "zxdump" dfltdump := zx.Path(dbg.Home, "dump") opts.NewFlag("s", "don't dump right now, wait until next at 5am", &Skip) opts.NewFlag("1", "dump once and exit", &Once) opts.NewFlag("v", "verbose", &Verbose) opts.NewFlag("D", "debug", &Debug) opts.NewFlag("x", "expr: files excluded (.*, tmp.* if none given); tmp always excluded.", &Xcludes) Dump = dfltdump opts.NewFlag("d", "dir: where to keep the dump, or empty if none", &Dump) args, err := opts.Parse(os.Args) if err != nil { dbg.Warn("%s", err) opts.Usage() dbg.Exits(err) } if len(Xcludes) == 0 { Xcludes = []string{".*", "tmp.*", "*.tmp"} } Xcludes = append(Xcludes, "tmp") if len(args) == 0 { dbg.Warn("arguments missing") opts.Usage() dbg.Exits("usage") } if Skip && Once { dbg.Fatal("can't skip the current dump and dump once now") } nt := 0 ec := make(chan bool) for i := 0; i < len(args); i++ { al := strings.SplitN(args[i], "!", 2) if len(al) == 1 { al = append(al, al[0]) al[0] = path.Base(al[0]) } t, err := lfs.New(al[0], al[1], lfs.RO) if err != nil { dbg.Warn("%s: %s", al[0], err) continue } t.ReadAttrs(true) nt++ go dump(Dump, t, ec) } if nt == 0 { dbg.Fatal("no trees to dump") } for nt > 0 { <-ec nt-- } }
/* Start the wax web server. */ func Serve(port string) error { startedlk.Lock() defer startedlk.Unlock() if started { return fmt.Errorf("already started") } started = true http.HandleFunc("/js/", jsHandler) if auth.TLSserver != nil { dbg.Warn("wax: listening at https://%s:%s\n", dbg.Sys, port) return http.ListenAndServeTLS(port, auth.ServerPem, auth.ServerKey, nil) } dbg.Warn("wax: listening at http://%s:%s\n", dbg.Sys, port) return http.ListenAndServe(port, nil) }
/* Check out to see if resp is the expected response for the ch challenge on the named auth domain. Returns the user who authenticates and the status for authentication. Always returns true when Auth is not enabled. */ func ChallengeResponseOk(name, ch, resp string) (user string, ok bool) { u := dbg.Usr if !Enabled { return u, true } if keys==nil || iv==nil { return u, false } u = keys[0].Uid key := keys[0].Key if name!="" && name!="default" { var err error ks, err := LoadKey(KeyDir(), name) if err != nil { dbg.Warn("auth: loadkey %s: %s", name, err) return u, false } u, key = ks[0].Uid, ks[0].Key } chresp, ok := encrypt(key, iv, []byte(ch)) if !ok || len(chresp)==0 { return u, false } return u, fmt.Sprintf("%x", chresp) == resp }
func NewRedir(from, name string, app bool) Redirs { if len(from) == 0 { return nil } if len(from) > 1 { rdr := NewRedir(from[:1], name, app) for i := 1; i < len(from); i++ { rdr = append(rdr, NewDup(from[i:i+1], from[:1])...) } return rdr } switch from { case "0", "1", "2": default: dbg.Warn("%s: unknown redirect %c", addr, from) nerrors++ return nil } return []*Redir{ { From: int(from[0] - '0'), Name: name, App: app, }, } }
// called from yacc, to execute a top-level node. func (nd *Nd) Exec() error { if nd==nil || nd.Kind==Nnone || nd.Kind==Nnop { return nil } var err error switch nd.Kind { case Npipe: nd.mkExec(os.Stdin, os.Stdout, os.Stderr, Argv...) err = nd.xPipe() if err == nil { if nd.async() { bg.Add(nd) go func() { err := nd.wait() bg.Del(nd, err) }() } else { err = nd.wait() } } case Nset: nd.mkExec(os.Stdin, os.Stdout, os.Stderr, Argv...) nd.xSet() err = nd.wait() default: dbg.Warn("%s not yet implemented", nd.Kind) err = dbg.ErrBug } setsts(err) return err }
func TestWait(t *testing.T) { os.Args[0] = "app.test" t.Skip("this is not a test") Debug = testing.Verbose() defer Exiting() c := New() c.Args = []string{"proc1"} wc := make(chan *Ctx) Printf("getting ctx\n") go func() { c := New() c.Args = []string{"proc2"} defer Exiting() defer dbg.Warn("D2") wc <- c Printf("print2\n") Fatal("ouch") dprintf("end2\n") }() cc := <-wc Printf("got ctx\n") <-cc.Wait Warn("cc sts %v\n", cerror(cc.Wait)) Fatal("fatal") dprintf("end\n") }
func lfscache(t zx.Tree, fn func()) (zx.Tree, func(), error) { m, err := lfs.New("clfs", lfsdir, lfs.RW) if err != nil { return nil, nil, fmt.Errorf("lfs", err) } m.SaveAttrs(true) m.IOstats = &zx.IOstats{} m.Dbg = zdebug ncfs.Debug = zdebug xfs, err := ncfs.New("cfs", m, t, rflag) if err != nil { return nil, nil, fmt.Errorf("cfs: %s", err) } st := &zx.IOstats{} xfs.IOstats = st if xaddr != "" { serve(xfs, xaddr) } if sflag { xfn := func() { st.Averages() dbg.Warn("%s iostats:\n%s\n", xfs.Name(), st) if fn != nil { fn() } } return xfs, xfn, nil } return xfs, fn, nil }
// no locks, used only at init time func (t *Fs) reloadChild(f *mFile) { ds, err := zx.GetDir(t.lfs, f.d["path"]) if err != nil { dbg.Warn("%s: reload: %s", t.name, err) return } for _, d := range ds { if d["path"] == "/Ctl" || d["path" ] == "/Chg" { continue } cf := &mFile{ name: d["name"], d: zx.Dir{ "name": d["name"], "path": d["path"], "spath": d["path"], "tpath": t.path, "type": d["type"], "Wuid": d["Wuid"], "Sum": d["Sum"], }, } for k, v := range d.UsrAttrs() { cf.d[k] = v } f.child = append(f.child, cf) if cf.d["type"] == "d" { t.reloadChild(cf) } } }
func usage(err error) { dbg.Warn("%s", err) opts.Usage() fmt.Fprintf(os.Stderr, "\tspec is name | name!file | name!file!flags \n") fmt.Fprintf(os.Stderr, "\tspec flags are ro | rw | ncro | ncrw \n") dbg.Exits(err) }
func ExampleNew() { // create a tree fs, err := New("example mfs") if err != nil { dbg.Fatal("lfs: %s", err) } dbg.Warn("fs %s ready", fs) // Now use it... }
func (c *FileInfo) checkClean() { if c.state != CClean && c.state != CUnread && !c.busy { dbg.Warn("%s: not clean and not busy: %s", c.path, c.state) panic("bugs") } for _, cc := range c.child { cc.checkClean() } }
func ExampleNew() { // create a tree rooted at /bin in RO mode fs, err := New("example lfs", "/bin", RO) if err != nil { dbg.Fatal("lfs: %s", err) } dbg.Warn("fs %s ready", fs) // Now use it... }
func (l *lex) source(what string) { dat, err := ioutil.ReadFile(what) if err != nil { dbg.Warn("open: %s: %s", what, err) return } l.in = append([]inText{bytes.NewBuffer(dat)}, l.in...) l.saddr = append([]Addr{l.Addr}, l.saddr...) l.Addr = Addr{what, 1} }
func errc(tag string, ec chan error, nc chan int) { n := 0 for e := range ec { if e != nil && e.Error() != "pruned" { n++ dbg.Warn("%s: %s", tag, e) } } nc <- n }
// Facade that serves t at the given address by using the ds // to serve and calling Serve for each client. func Server(t zx.Tree, addr string) { dbg.Warn("serve %s at %s...", t.Name(), addr) cc, ec, err := ds.Serve(os.Args[0], addr) if err != nil { dbg.Warn("serve: %s", err) return } go func() { for c := range cc { if c != nil { go serveFor(t, *c) } } if err := cerror(cc); err != nil { dbg.Warn("serve: %s", err) } close(ec, "done") }() }
func ExampleLfs_Stat() { var fs *Lfs // = New("tag", path, RO|RW) dirc := fs.Stat("/ls") dir := <-dirc if dir == nil { dbg.Fatal("stat: %s", cerror(dirc)) } dbg.Warn("stat was %s", dir) }
func waitDumpTime(name string) { t := time.Now() dt := time.Date(t.Year(), t.Month(), t.Day(), 5, 0, 0, 0, time.Local) if dt.Before(time.Now()) { dt = dt.Add(24 * time.Hour) } dbg.Warn("next %s dump at %v", name, dt) delta := dt.Sub(t) time.Sleep(delta) }
func main() { defer dbg.Exits("") os.Args[0] = "zxfs" quiet := false opts.NewFlag("q", "don't print errors to stderr", &quiet) opts.NewFlag("D", "debug and zxfs calls", &zxfs.Debug) opts.NewFlag("r", "read only", &rflag) opts.NewFlag("s", "statistics", &sflag) opts.NewFlag("n", "don't use caching (otherwise write-through cache)", &nocaching) opts.NewFlag("d", "use delayed writes cache", &delayed) opts.NewFlag("Z", "debug zx requests", &zdebug) opts.NewFlag("V", "verbose debug and fuse requests", &fs.Debug) opts.NewFlag("x", "addr: re-export locally the cached tree to this address, if any", &xaddr) opts.NewFlag("m", "use mfs caching", &mfscfs) opts.NewFlag("l", "dir: use lfs caching at dir", &lfsdir) args, err := opts.Parse(os.Args) if err != nil { opts.Usage(os.Stderr) dbg.Fatal(err) } zxfs.Debug = zxfs.Debug || fs.Debug zxfs.Verb = !quiet || zxfs.Debug if fs.Debug { fuse.Debug = func(m interface{}) { fmt.Fprintf(os.Stderr, "fuse: %v\n", m) } } switch len(args) { case 2: addr = args[0] mntdir = args[1] case 1: addr = args[0] default: opts.Usage(os.Stderr) dbg.Fatal("usage") } dprintf("debug on\n") xfs, fn, err := mkfs(addr) if err != nil { dbg.Fatal("%s", err) } defer fn() if nocaching || !delayed { err = ncmount(xfs) } else { dbg.Fatal("delayed write mount is gone") } if err != nil { dbg.Fatal("%s", err) } dbg.Warn("unmounted: exiting") }
func (rs Redirs) NoDups() { m := map[int]bool{} for _, r := range rs { if r.From>=0 && m[r.From] { dbg.Warn("%s: dup redir %d", addr, r.From) nerrors++ r.From = -1 } m[r.From] = true } }
func serveFor(t zx.Tree, c nchan.Conn) { ai, err := auth.AtServer(c, "", "zx", "finder") if err != nil && err != auth.ErrDisabled { dbg.Warn("auth %s: %s\n", c.Tag, err) close(c.In, err) close(c.Out, err) return } srv := Serve("rfs:"+c.Tag, c, ai, RW, t) srv.Debug = false }
func ArgVal(toks []string, idx string) []string { if idx == "" { return toks } n, err := strconv.ParseInt(idx, 10, 32) i := int(n) if err != nil || i < 0 || i >= len(toks) { dbg.Warn("%s: bad index in $%s", addr, "argv") return nil } return toks[i : i+1] }
func main() { defer dbg.Exits("") os.Args[0] = "tcmd" n := 10 if len(os.Args) > 1 { n, _ = strconv.Atoi(os.Args[1]) } for i := 0; i < n; i++ { dbg.Warn("T %d", i) time.Sleep(time.Second) } }
func zxwax() { ctrl := ctl.NewControl() ctrl.BoolFlag("Debug", &Debug) ctrl.CmdFlag("Exit", func() { dbg.Fatal("exiting at user request") }) wax.ServeLogin("/", "/index") pg := `$tb$<p>$zx$<p>` part, err := wax.New(pg) if err != nil { dbg.Warn("wax new: %s", err) return } part.SetEnv(map[string]interface{}{ "tb": ctrl.Bar("tb"), "zx": zxw, }) part.Serve("/index") if err = wax.Serve(":" + wport); err != nil { dbg.Warn("wax serve: %s", err) } }
func ExampleNew() { // create a tree using the local directory /tmp/cache for the cache dfs, err := lfs.New("cache", "/tmp/cache", lfs.RW) if err != nil { dbg.Fatal("lfs: %s", err) } fs, err := New("example mdfs", dfs) if err != nil { dbg.Fatal("mfds: %s", err) } dbg.Warn("fs %s ready", fs) // Now use it... }
// no locks, used only at init time func (t *Fs) reload() { d, err := zx.Stat(t.lfs, "/") if err != nil { dbg.Warn("%s: reload: %s", t.name, err) return } ud := d.UsrAttrs() ud["Sum"] = d["Sum"] for k, v := range ud { t.root.d[k] = v } t.reloadChild(t.root) }
func dial(d zx.Dir) (zx.Tree, error) { addr := d["addr"] if addr == "" { return nil, errors.New("no address") } spath := d["spath"] if spath == "" { spath = d["path"] } if spath == "" { return nil, errors.New("no server path") } remslk.RLock() r := rems[addr] remslk.RUnlock() if r != nil { return r, nil } remslk.Lock() defer remslk.Unlock() toks := strings.Split(addr, "!") tree := "main" if len(toks) >= 4 { tree = toks[3] } c, err := ds.Dial(addr) if err != nil { return nil, err } if _, err := auth.AtClient(c, "", "zx"); err!=nil && err!=auth.ErrDisabled { close(c.In, err) close(c.Out, err) return nil, err } m := nchan.NewMux(c, true) r, err = New(m, tree) if err != nil { return nil, err } r.addr = addr hc := m.Hup() go func() { <-hc dbg.Warn("rfs hangup on %s", addr) r.gone() }() rems[addr] = r return r, nil }