code: purgatorio

ref: 87d72e7e8614d96b4f61adae5fb05b0534231c4c
dir: /appl/demo/ns/ns.b/

View raw version
implement Ns;

#
# Copyright © 2003 Vita Nuova Holdings Limited.  All rights reserved.
#

include "sys.m";
	sys: Sys;
include "draw.m";
include "arg.m";
include "sh.m";
	sh: Sh;

ns : list of string;

Ns: module {
	init: fn(nil: ref Draw->Context, argv: list of string);
};

init(nil: ref Draw->Context, argv: list of string)
{
	sys = load Sys Sys->PATH;
	if (sys == nil)
		badmod(Sys->PATH);
	sh = load Sh Sh->PATH;
	if (sh == nil)
		badmod(Sh->PATH);
	# sys->pctl(sys->FORKNS, nil);
	sys->unmount(nil, "/n/remote");
	arg := load Arg Arg->PATH;
	if (arg == nil)
		badmod(Arg->PATH);

	arg->init(argv);
	arg->setusage("ns [-v] [-r relpath] paths...");
	verbose := 0;
	relpath := "";
	while ((opt := arg->opt()) != 0) {
		case opt {
		'v' =>
			verbose = 1;
		'r' =>
			relpath = arg->earg();
			if (relpath == nil)
				arg->usage();
			if (relpath[len relpath - 1] != '/')
				relpath[len relpath] = '/';
		* =>
			arg->usage();
		}
	}

	ns = arg->argv();
	arg = nil;
	if (ns == nil) {
		sys->fprint(fdout(), "error no namespace selected\n");
		exit;
	}
	spawn buildns(relpath, verbose);
}

fdout(): ref sys->FD
{
	return sys->fildes(1);
}

buildns(relpath: string, verbose: int)
{
	# sys->pctl(sys->FORKNS, nil);
	if (sh->run(nil, "memfs"::"/n/remote"::nil) != nil) {
		sys->fprint(fdout(), "error MemFS mount failed\n");
		exit;
	}
	for (tmpl := ns; tmpl != nil; tmpl = tl tmpl) {
		nspath := hd tmpl;
		if (nspath[len nspath - 1] != '/')
			nspath[len nspath] = '/';

		bindpath := nspath;
		if (bindpath[:len relpath] == relpath) {
			bindpath = "/n/remote/"+bindpath[len relpath:];
			if (createdir(bindpath) != -1) {
				if (sys->bind(nspath, bindpath, sys->MBEFORE | sys->MCREATE) == -1) {
					if (sys->bind(nspath, bindpath, sys->MBEFORE) == -1)
						sys->fprint(fdout(), "error bind failed %s: %r\n",bindpath);
					else if (verbose)
						sys->fprint(fdout(), "data nspath %s\n", nspath);
				}
				else if (verbose)
					sys->fprint(fdout(), "data nspath %s\n", nspath);
			}
			else
				sys->fprint(fdout(), "error create failed %s\n",bindpath);
		}
	}
	spawn exportns();
}

exportns()
{
	sys->export(sys->fildes(0), "/n/remote", sys->EXPWAIT);
}

createdir(path: string): int
{
	(nil, lst) := sys->tokenize(path, "/");
	npath := "";
	for (; lst != nil; lst = tl lst) {
		(n, nil) := sys->stat(npath + "/" + hd lst);
		if (n == -1) {
			fd := sys->create(npath + "/" + hd lst, sys->OREAD, 8r777 | sys->DMDIR);
			if (fd == nil)
				return -1;
		}
		npath += "/" + hd lst;
	}
	return 0;
}

badmod(path: string)
{
	sys->fprint(fdout(), "error Ns: failed to load: %s\n",path);
	exit;
}