implement Keepalive; include "sys.m"; sys: Sys; include "draw.m"; include "arg.m"; include "styx.m"; styx: Styx; Rmsg, Tmsg: import styx; Keepalive: module { init: fn(nil: ref Draw->Context, nil: list of string); }; interval := 100; buf := array[256] of byte; PLACE: con "/n/placeholder"; init(nil: ref Draw->Context, argv: list of string) { sys = load Sys Sys->PATH; styx = load Styx Styx->PATH; styx->init(); arg := load Arg Arg->PATH; arg->init(argv); arg->setusage("keepalive [-t seconds] dir..."); while((opt := arg->opt()) != 0){ case opt { 't' => interval = int arg->earg(); if(interval <= 0) sys->fprint(sys->fildes(2), "keepalive: interval too short\n"); raise "fail:error"; * => arg->usage(); } } argv = arg->argv(); fds: list of ref Sys->FD; for(; argv != nil; argv = tl argv){ fd := sys->open(hd argv, Sys->OREAD); if(fd == nil) sys->fprint(sys->fildes(2), "keepalive: cannot open %q: %r\n", hd argv); else fds = fd :: fds; } if(fds == nil) raise "fail:error"; sys->pctl(Sys->NEWPGRP, nil); spawn keepalives(fds, sync := chan of int); <-sync; sys->pipe(p := array[2] of ref Sys->FD); spawn dummyserve(p[0], sync); p[0] = nil; <-sync; if(sys->mount(p[1], nil, PLACE, Sys->MAFTER, nil) == -1){ sys->fprint(sys->fildes(2), "keepalive: cannot mount keepalive onto %s: %r\n", PLACE); die(); raise "fail:error"; } } dummyserve(fd: ref Sys->FD, sync: chan of int) { sys->pctl(Sys->NEWNS|Sys->NEWFD, fd.fd::nil); fd = sys->fildes(fd.fd); sync <-= 1; while((gm := Tmsg.read(fd, 0)) != nil && tagof gm != tagof Tmsg.Readerror){ pick m := gm { Version => reply(fd, ref Rmsg.Version(m.tag, Sys->ATOMICIO, m.version)); Attach => reply(fd, ref Rmsg.Attach(m.tag, Sys->Qid(big 0, 0, Sys->QTDIR))); * => reply(fd, ref Rmsg.Error(m.tag, "i'm just here to be here")); } } die(); } keepalives(fds: list of ref Sys->FD, sync: chan of int) { sys->pctl(Sys->NEWNS, nil); sys->chdir("/"); sync1 := chan of int; for(; fds != nil; fds = tl fds){ spawn keepalive(hd fds, sync1); <-sync1; } sync <-= 0; } keepalive(fd: ref Sys->FD, sync: chan of int) { n: int; sys->pctl(Sys->NEWFD, fd.fd :: nil); sync <-= 0; fd = sys->fildes(fd.fd); (ok, info) := sys->fstat(fd); isdir := ok && (info.mode & Sys->DMDIR); for(;;){ sys->sleep(interval * 1000); sys->seek(fd, big 0, 0); # read all elements of directory in case it's a union. do { n = sys->read(fd, buf, len buf); } while (isdir && n > 0); if(n == -1) exit; } } reply(fd: ref Sys->FD, m: ref Rmsg) { p := m.pack(); sys->write(fd, p, len p); } die() { sys->fprint(sys->open("#p/"+string sys->pctl(0, nil)+"/ctl", Sys->OWRITE), "killgrp"); }