ref: 57c522a6b71132167243a28c58184f70219d069a
dir: /appl/cmd/ns.b/
# ns - display the construction of the current namespace (loosely based on plan 9's ns)
implement Ns;
include "sys.m";
sys: Sys;
include "draw.m";
include "arg.m";
Ns: module
{
init: fn(nil: ref Draw->Context, argv: list of string);
};
SHELLMETA: con "' \t\\$#";
usage()
{
sys->fprint(sys->fildes(2), "usage: ns [-r] [pid]\n");
raise "fail:usage";
}
init(nil: ref Draw->Context, args: list of string)
{
sys = load Sys Sys->PATH;
arg := load Arg Arg->PATH;
if(arg == nil){
sys->fprint(sys->fildes(2), "ns: can't load %s: %r\n", Arg->PATH);
raise "fail:load";
}
arg->init(args);
pid := sys->pctl(0, nil);
raw := 0;
while((o := arg->opt()) != 0)
case o {
'r' =>
raw = 1;
* =>
usage();
}
args = arg->argv();
arg = nil;
if(len args > 1)
usage();
if(len args > 0)
pid = int hd args;
nsname := sys->sprint("/prog/%d/ns", pid);
nsfd := sys->open(nsname, Sys->OREAD);
if(nsfd == nil) {
sys->fprint(sys->fildes(2), "ns: can't open %s: %r\n", nsname);
raise "fail:open";
}
buf := array[2048] of byte;
while((l := sys->read(nsfd, buf, len buf)) > 0){
(nstr, lstr) := sys->tokenize(string buf[0:l], " \n");
if(nstr < 2)
continue;
cmd := hd lstr;
lstr = tl lstr;
if(cmd == "cd" && lstr != nil){
sys->print("%s %s\n", cmd, quoted(hd lstr));
continue;
}
sflag := "";
if((hd lstr)[0] == '-') {
sflag = hd lstr + " ";
lstr = tl lstr;
}
if(len lstr < 2)
continue;
src := hd lstr;
lstr = tl lstr;
if(len src >= 3 && (src[0:2] == "#/" || src[0:2] == "#U")) # remove unnecesary #/'s and #U's
src = src[2:];
# remove "#." from beginning of destination path
dest := hd lstr;
if(dest == "#M") {
dest = dest[2:];
if(dest == "")
dest = "/";
}
if(cmd == "mount" && !raw)
src = netaddr(src); # optionally rewrite network files to network address
# quote arguments if "#" found
sys->print("%s %s%s %s\n", cmd, sflag, quoted(src), quoted(dest));
}
if(l < 0)
sys->fprint(sys->fildes(2), "ns: error reading %s: %r\n", nsname);
}
netaddr(f: string): string
{
if(len f < 1 || f[0] != '/')
return f;
(nf, flds) := sys->tokenize(f, "/"); # expect /net[.alt]/proto/2/data
if(nf < 4)
return f;
netdir := hd flds;
if(netdir != "net" && netdir != "net.alt")
return f;
proto := hd tl flds;
d := hd tl tl flds;
if(hd tl tl tl flds != "data")
return f;
fd := sys->open(sys->sprint("/%s/%s/%s/remote", hd flds, proto, d), Sys->OREAD);
if(fd == nil)
return f;
buf := array[256] of byte;
n := sys->read(fd, buf, len buf);
if(n <= 0)
return f;
if(buf[n-1] == byte '\n')
n--;
if(netdir != "net")
proto = "/"+netdir+"/"+proto;
return sys->sprint("%s!%s", proto, string buf[0:n]);
}
any(c: int, t: string): int
{
for(j := 0; j < len t; j++)
if(c == t[j])
return 1;
return 0;
}
contains(s: string, t: string): int
{
for(i := 0; i<len s; i++)
if(any(s[i], t))
return 1;
return 0;
}
quoted(s: string): string
{
if(!contains(s, SHELLMETA))
return s;
r := "'";
for(i := 0; i < len s; i++){
if(s[i] == '\'')
r[len r] = '\'';
r[len r] = s[i];
}
r[len r] = '\'';
return r;
}