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");
}
|