shithub: purgatorio

ref: a411870ee4640241e3c494367d922847da84f972
dir: purgatorio/appl/cmd/ns.b

View raw version
# 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;
}