xref: /inferno-os/appl/lib/newns.b (revision b2e326f2d4281f7380036516b62928f8c02850d4)
137da2899SCharles.Forsythimplement Newns;
237da2899SCharles.Forsyth#
337da2899SCharles.Forsyth# Build a new namespace from a file
437da2899SCharles.Forsyth#
537da2899SCharles.Forsyth#	new	create a new namespace from current directory (use cd)
637da2899SCharles.Forsyth#	fork	split the namespace before modification
737da2899SCharles.Forsyth#	nodev	disallow device attaches
837da2899SCharles.Forsyth#	bind	[-abrci] from to
937da2899SCharles.Forsyth#	mount	[-abrci9] [net!]machine[!svc] to [spec]
1037da2899SCharles.Forsyth#	import [-abrci9] [net!]machine[!svc] [remotedir] dir
1137da2899SCharles.Forsyth#	unmount	[-i] [from] to
1237da2899SCharles.Forsyth#   	cd	directory
1337da2899SCharles.Forsyth#
1437da2899SCharles.Forsyth#	-i to bind/mount/unmount means continue in the face of errors
1537da2899SCharles.Forsyth#
1637da2899SCharles.Forsythinclude "sys.m";
1737da2899SCharles.Forsyth	sys: Sys;
1862d7827bScharles forsyth	FD, FileIO: import Sys;
1937da2899SCharles.Forsyth	stderr: ref FD;
2037da2899SCharles.Forsyth
2137da2899SCharles.Forsythinclude "draw.m";
2237da2899SCharles.Forsyth
2337da2899SCharles.Forsythinclude "bufio.m";
2437da2899SCharles.Forsyth	bio: Bufio;
2537da2899SCharles.Forsyth	Iobuf: import bio;
2637da2899SCharles.Forsyth
27fbc1184cSCharles Forsythinclude "dial.m";
28fbc1184cSCharles Forsyth	dial: Dial;
2962d7827bScharles forsyth	Connection: import dial;
30fbc1184cSCharles Forsyth
3137da2899SCharles.Forsythinclude "newns.m";
3237da2899SCharles.Forsyth
3337da2899SCharles.Forsyth#include "sh.m";
3437da2899SCharles.Forsyth
3537da2899SCharles.Forsythinclude "keyring.m";
3637da2899SCharles.Forsyth	kr: Keyring;
3737da2899SCharles.Forsyth
3837da2899SCharles.Forsythinclude "security.m";
3937da2899SCharles.Forsyth	au: Auth;
4037da2899SCharles.Forsyth
4137da2899SCharles.Forsythinclude "factotum.m";
4237da2899SCharles.Forsyth
4337da2899SCharles.Forsythinclude "arg.m";
4437da2899SCharles.Forsyth	arg: Arg;
4537da2899SCharles.Forsyth
466e425a9dSCharles.Forsythinclude "string.m";
476e425a9dSCharles.Forsyth	str: String;
486e425a9dSCharles.Forsyth
4937da2899SCharles.Forsythnewns(user: string, file: string): string
5037da2899SCharles.Forsyth{
5137da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
5237da2899SCharles.Forsyth	kr = load Keyring Keyring->PATH;
5337da2899SCharles.Forsyth	stderr = sys->fildes(2);
5437da2899SCharles.Forsyth
5537da2899SCharles.Forsyth	# Could do some authentication here, and bail if no good FIXME
5637da2899SCharles.Forsyth	if(user == nil)
5737da2899SCharles.Forsyth		;
5837da2899SCharles.Forsyth	bio = load Bufio Bufio->PATH;
5937da2899SCharles.Forsyth	if(bio == nil)
6037da2899SCharles.Forsyth		return sys->sprint("cannot load %s: %r", Bufio->PATH);
6137da2899SCharles.Forsyth
6237da2899SCharles.Forsyth	arg = load Arg Arg->PATH;
6337da2899SCharles.Forsyth	if (arg == nil)
6437da2899SCharles.Forsyth		return sys->sprint("cannot load %s: %r", Arg->PATH);
6537da2899SCharles.Forsyth
6637da2899SCharles.Forsyth	au = load Auth Auth->PATH;
6737da2899SCharles.Forsyth	if(au == nil)
6837da2899SCharles.Forsyth		return sys->sprint("cannot load %s: %r", Auth->PATH);
6937da2899SCharles.Forsyth	err := au->init();
7037da2899SCharles.Forsyth	if(err != nil)
7137da2899SCharles.Forsyth		return "Auth->init: "+err;
7237da2899SCharles.Forsyth
736e425a9dSCharles.Forsyth	str = load String String->PATH;		# no check, because we'll live without it
746e425a9dSCharles.Forsyth
7537da2899SCharles.Forsyth	if(file == nil){
7637da2899SCharles.Forsyth		file = "namespace";
7737da2899SCharles.Forsyth		if(sys->stat(file).t0 < 0)
7837da2899SCharles.Forsyth			file = "/lib/namespace";
7937da2899SCharles.Forsyth	}
8037da2899SCharles.Forsyth
8137da2899SCharles.Forsyth	mfp := bio->open(file, bio->OREAD);
8237da2899SCharles.Forsyth	if(mfp==nil)
8337da2899SCharles.Forsyth      		return sys->sprint("cannot open %q: %r", file);
8437da2899SCharles.Forsyth
8537da2899SCharles.Forsyth	if(0 && user != nil){
8637da2899SCharles.Forsyth		sys->pctl(Sys->FORKENV, nil);
8737da2899SCharles.Forsyth		setenv("user", user);
8837da2899SCharles.Forsyth		setenv("home", "/usr/"+user);
8937da2899SCharles.Forsyth	}
9037da2899SCharles.Forsyth
9137da2899SCharles.Forsyth	facfd := sys->open("/mnt/factotum/rpc", Sys->ORDWR);
9237da2899SCharles.Forsyth	return nsfile(mfp, facfd);
9337da2899SCharles.Forsyth}
9437da2899SCharles.Forsyth
9537da2899SCharles.Forsythnsfile(b: ref Iobuf, facfd: ref Sys->FD): string
9637da2899SCharles.Forsyth{
9737da2899SCharles.Forsyth	e := "";
9837da2899SCharles.Forsyth	while((l := b.gets('\n')) != nil){
996e425a9dSCharles.Forsyth		if(str != nil)
1006e425a9dSCharles.Forsyth			slist := str->unquoted(l);
1016e425a9dSCharles.Forsyth		else
1026e425a9dSCharles.Forsyth			(nil, slist) = sys->tokenize(l, " \t\n\r");	# old way, in absence of String
1036e425a9dSCharles.Forsyth		if(slist == nil)
10437da2899SCharles.Forsyth			continue;
10537da2899SCharles.Forsyth		e = nsop(expand(slist), facfd);
10637da2899SCharles.Forsyth		if(e != "")
10737da2899SCharles.Forsyth			break;
10837da2899SCharles.Forsyth   	}
10937da2899SCharles.Forsyth	return e;
11037da2899SCharles.Forsyth}
11137da2899SCharles.Forsyth
11237da2899SCharles.Forsythexpand(l: list of string): list of string
11337da2899SCharles.Forsyth{
11437da2899SCharles.Forsyth	nl: list of string;
11537da2899SCharles.Forsyth	for(; l != nil; l = tl l){
11637da2899SCharles.Forsyth		s := hd l;
11737da2899SCharles.Forsyth		for(i := 0; i < len s; i++)
11837da2899SCharles.Forsyth			if(s[i] == '$'){
11937da2899SCharles.Forsyth				for(j := i+1; j < len s; j++)
12037da2899SCharles.Forsyth					if((c := s[j]) == '.' || c == '/' || c == '$')
12137da2899SCharles.Forsyth						break;
12237da2899SCharles.Forsyth				if(j > i+1){
12337da2899SCharles.Forsyth					(ok, v) := getenv(s[i+1:j]);
12437da2899SCharles.Forsyth					if(!ok)
12537da2899SCharles.Forsyth						return nil;
12637da2899SCharles.Forsyth					s = s[0:i] + v + s[j:];
12737da2899SCharles.Forsyth					i = i + len v;
12837da2899SCharles.Forsyth				}
12937da2899SCharles.Forsyth			}
13037da2899SCharles.Forsyth		nl = s :: nl;
13137da2899SCharles.Forsyth	}
13237da2899SCharles.Forsyth	l = nil;
13337da2899SCharles.Forsyth	for(; nl != nil; nl = tl nl)
13437da2899SCharles.Forsyth		l = hd nl :: l;
13537da2899SCharles.Forsyth	return l;
13637da2899SCharles.Forsyth}
13737da2899SCharles.Forsyth
13837da2899SCharles.Forsythnsop(argv: list of string, facfd: ref Sys->FD): string
13937da2899SCharles.Forsyth{
14037da2899SCharles.Forsyth	# ignore comments
14137da2899SCharles.Forsyth	if(argv == nil || (hd argv)[0] == '#')
14237da2899SCharles.Forsyth		return nil;
14337da2899SCharles.Forsyth
14437da2899SCharles.Forsyth	e := "";
14537da2899SCharles.Forsyth	c := 0;
14637da2899SCharles.Forsyth	cmdstr := hd argv;
14737da2899SCharles.Forsyth	case cmdstr {
14837da2899SCharles.Forsyth	"." =>
14937da2899SCharles.Forsyth		if(tl argv == nil)
15037da2899SCharles.Forsyth			return ".: needs a filename";
15137da2899SCharles.Forsyth		nsf := hd tl argv;
15237da2899SCharles.Forsyth		mfp := bio->open(nsf, bio->OREAD);
15337da2899SCharles.Forsyth		if(mfp==nil)
15437da2899SCharles.Forsyth      			return sys->sprint("can't open %q for read %r", nsf);
15537da2899SCharles.Forsyth		e = nsfile(mfp, facfd);
15637da2899SCharles.Forsyth	"new" =>
15737da2899SCharles.Forsyth		c = Sys->NEWNS | Sys->FORKENV;
15837da2899SCharles.Forsyth	"clear" =>
15937da2899SCharles.Forsyth		if(sys->pctl(Sys->FORKNS, nil) < 0 ||
16037da2899SCharles.Forsyth		   sys->bind("#/", "/", Sys->MREPL) < 0 ||
16137da2899SCharles.Forsyth		   sys->chdir("/") < 0 ||
16237da2899SCharles.Forsyth		   sys->pctl(Sys->NEWNS, nil) < 0)
16337da2899SCharles.Forsyth			return sys->sprint("%r");
16437da2899SCharles.Forsyth		return nil;
16537da2899SCharles.Forsyth	"fork"  =>
16637da2899SCharles.Forsyth		c = Sys->FORKNS;
16737da2899SCharles.Forsyth	"nodev" =>
16837da2899SCharles.Forsyth		c = Sys->NODEVS;
16937da2899SCharles.Forsyth	"bind" =>
17037da2899SCharles.Forsyth		e = bind(argv);
17137da2899SCharles.Forsyth	"mount" =>
17237da2899SCharles.Forsyth		e = mount(argv, facfd);
17337da2899SCharles.Forsyth	"unmount" =>
17437da2899SCharles.Forsyth		e = unmount(argv);
17537da2899SCharles.Forsyth	"import" =>
17637da2899SCharles.Forsyth		e = import9(argv, facfd);
17737da2899SCharles.Forsyth   	"cd" =>
17837da2899SCharles.Forsyth   		if(len argv != 2)
17937da2899SCharles.Forsyth			return "cd: must have one argument";
18037da2899SCharles.Forsyth		if(sys->chdir(hd tl argv) < 0)
18137da2899SCharles.Forsyth			return sys->sprint("%r");
18237da2899SCharles.Forsyth	* =>
18337da2899SCharles.Forsyth      		e = "invalid namespace command";
18437da2899SCharles.Forsyth	}
18537da2899SCharles.Forsyth	if(c != 0) {
18637da2899SCharles.Forsyth		if(sys->pctl(c, nil) < 0)
18737da2899SCharles.Forsyth			return sys->sprint("%r");
18837da2899SCharles.Forsyth	}
18937da2899SCharles.Forsyth	return e;
19037da2899SCharles.Forsyth}
19137da2899SCharles.Forsyth
19237da2899SCharles.ForsythMoptres: adt {
19337da2899SCharles.Forsyth	argv: list of string;
19437da2899SCharles.Forsyth	flags: int;
19537da2899SCharles.Forsyth	alg: string;
19637da2899SCharles.Forsyth	keyfile: string;
19737da2899SCharles.Forsyth	ignore: int;
19837da2899SCharles.Forsyth	use9: int;
199*e5242bb5SRyabin Sergey	doauth: int;
20037da2899SCharles.Forsyth};
20137da2899SCharles.Forsyth
20237da2899SCharles.Forsythmopt(argv: list of string): (ref Moptres, string)
20337da2899SCharles.Forsyth{
204*e5242bb5SRyabin Sergey	r := ref Moptres(nil, 0, "none", nil, 0, 0, 1);
20537da2899SCharles.Forsyth
20637da2899SCharles.Forsyth	arg->init(argv);
20737da2899SCharles.Forsyth	while ((opt := arg->opt()) != 0) {
20837da2899SCharles.Forsyth		case opt {
20937da2899SCharles.Forsyth		'i' => r.ignore = 1;
21037da2899SCharles.Forsyth		'a' => r.flags |= sys->MAFTER;
21137da2899SCharles.Forsyth		'b' => r.flags |= sys->MBEFORE;
21237da2899SCharles.Forsyth		'c' => r.flags |= sys->MCREATE;
21337da2899SCharles.Forsyth		'r' => r.flags |= sys->MREPL;
21437da2899SCharles.Forsyth		'k' =>
21537da2899SCharles.Forsyth			if((r.keyfile = arg->arg()) == nil)
21637da2899SCharles.Forsyth				return (nil, "mount: missing arg to -k option");
21737da2899SCharles.Forsyth		'C' =>
21837da2899SCharles.Forsyth			if((r.alg = arg->arg()) == nil)
21937da2899SCharles.Forsyth				return (nil, "mount: missing arg to -C option");
22037da2899SCharles.Forsyth		'9' =>
22137da2899SCharles.Forsyth			r.use9 = 1;
222*e5242bb5SRyabin Sergey		'A' =>
223*e5242bb5SRyabin Sergey			r.doauth = 0;
22437da2899SCharles.Forsyth		 *  =>
22537da2899SCharles.Forsyth			return (nil, sys->sprint("mount: bad option -%c", opt));
22637da2899SCharles.Forsyth		}
22737da2899SCharles.Forsyth	}
22837da2899SCharles.Forsyth	if((r.flags & (Sys->MAFTER|Sys->MBEFORE)) == 0)
22937da2899SCharles.Forsyth		r.flags |= Sys->MREPL;
23037da2899SCharles.Forsyth
23137da2899SCharles.Forsyth	r.argv = arg->argv();
23237da2899SCharles.Forsyth	return (r, nil);
23337da2899SCharles.Forsyth}
23437da2899SCharles.Forsyth
23537da2899SCharles.Forsythbind(argv: list of string): string
23637da2899SCharles.Forsyth{
23737da2899SCharles.Forsyth	(r, err) := mopt(argv);
23837da2899SCharles.Forsyth	if(err != nil)
23937da2899SCharles.Forsyth		return err;
24037da2899SCharles.Forsyth
24137da2899SCharles.Forsyth	if(len r.argv < 2)
24237da2899SCharles.Forsyth		return "bind: too few args";
24337da2899SCharles.Forsyth
24437da2899SCharles.Forsyth	from := hd r.argv;
24537da2899SCharles.Forsyth	r.argv = tl r.argv;
24637da2899SCharles.Forsyth	todir := hd r.argv;
24737da2899SCharles.Forsyth	if(sys->bind(from, todir, r.flags) < 0)
24837da2899SCharles.Forsyth		return ig(r, sys->sprint("bind %s %s: %r", from, todir));
24937da2899SCharles.Forsyth
25037da2899SCharles.Forsyth	return nil;
25137da2899SCharles.Forsyth}
25237da2899SCharles.Forsyth
25337da2899SCharles.Forsythmount(argv: list of string, facfd: ref Sys->FD): string
25437da2899SCharles.Forsyth{
25537da2899SCharles.Forsyth	fd: ref Sys->FD;
25637da2899SCharles.Forsyth
25737da2899SCharles.Forsyth	(r, err) := mopt(argv);
25837da2899SCharles.Forsyth	if(err != nil)
25937da2899SCharles.Forsyth		return err;
26037da2899SCharles.Forsyth
26137da2899SCharles.Forsyth	if(len r.argv < 2)
26237da2899SCharles.Forsyth		return ig(r, "mount: too few args");
26337da2899SCharles.Forsyth
264fbc1184cSCharles Forsyth	if(dial == nil){
265fbc1184cSCharles Forsyth		dial = load Dial Dial->PATH;
266fbc1184cSCharles Forsyth		if(dial == nil)
267fbc1184cSCharles Forsyth			return ig(r, "mount: can't load Dial");
268fbc1184cSCharles Forsyth	}
269fbc1184cSCharles Forsyth
27037da2899SCharles.Forsyth	addr := hd r.argv;
27137da2899SCharles.Forsyth	r.argv = tl r.argv;
272fbc1184cSCharles Forsyth	dest := dial->netmkaddr(addr, "net", "styx");
27337da2899SCharles.Forsyth	dir := hd r.argv;
27437da2899SCharles.Forsyth	r.argv = tl r.argv;
27537da2899SCharles.Forsyth	if(r.argv != nil)
27637da2899SCharles.Forsyth		spec := hd r.argv;
27737da2899SCharles.Forsyth
278fbc1184cSCharles Forsyth	c := dial->dial(dest, nil);
279fbc1184cSCharles Forsyth	if(c == nil)
28037da2899SCharles.Forsyth		return ig(r, sys->sprint("dial: %s: %r", dest));
28137da2899SCharles.Forsyth
282*e5242bb5SRyabin Sergey	if(r.doauth != 1){
283*e5242bb5SRyabin Sergey		if(sys->mount(c.dfd, nil, dir, r.flags, spec) < 0)
284*e5242bb5SRyabin Sergey			return ig(r, sys->sprint("mount %q %q: %r", addr, dir));
285*e5242bb5SRyabin Sergey		return nil;
286*e5242bb5SRyabin Sergey	}
287*e5242bb5SRyabin Sergey
28837da2899SCharles.Forsyth	if(r.use9){
28937da2899SCharles.Forsyth		factotum := load Factotum Factotum->PATH;
29037da2899SCharles.Forsyth		if(factotum == nil)
29137da2899SCharles.Forsyth			return ig(r, sys->sprint("cannot load %s: %r", Factotum->PATH));
29237da2899SCharles.Forsyth		factotum->init();
29337da2899SCharles.Forsyth		afd := sys->fauth(fd, spec);
294e84ac692SCharles.Forsyth		if(afd != nil)
295e84ac692SCharles.Forsyth			factotum->proxy(afd, facfd, "proto=p9any role=client");	# ignore result; if it fails, mount will fail
29637da2899SCharles.Forsyth		if(sys->mount(fd, afd, dir, r.flags, spec) < 0)
29737da2899SCharles.Forsyth			return ig(r, sys->sprint("mount %q %q: %r", addr, dir));
29837da2899SCharles.Forsyth		return nil;
29937da2899SCharles.Forsyth	}
30037da2899SCharles.Forsyth
30137da2899SCharles.Forsyth	user := user();
30237da2899SCharles.Forsyth	kd := "/usr/" + user + "/keyring/";
30337da2899SCharles.Forsyth	cert: string;
30437da2899SCharles.Forsyth	if (r.keyfile != nil) {
30537da2899SCharles.Forsyth		cert = r.keyfile;
30637da2899SCharles.Forsyth		if (cert[0] != '/')
30737da2899SCharles.Forsyth			cert = kd + cert;
308fbc1184cSCharles Forsyth		if(sys->stat(cert).t0 < 0)
30937da2899SCharles.Forsyth			return ig(r, sys->sprint("cannot find certificate %q: %r", cert));
31037da2899SCharles.Forsyth	} else {
31137da2899SCharles.Forsyth		cert = kd + addr;
312fbc1184cSCharles Forsyth		if(sys->stat(cert).t0 < 0)
31337da2899SCharles.Forsyth			cert = kd + "default";
31437da2899SCharles.Forsyth	}
31537da2899SCharles.Forsyth	ai := kr->readauthinfo(cert);
31637da2899SCharles.Forsyth	if(ai == nil)
31737da2899SCharles.Forsyth		return ig(r, sys->sprint("cannot read certificate from %q: %r", cert));
31837da2899SCharles.Forsyth
31937da2899SCharles.Forsyth	err = au->init();
32037da2899SCharles.Forsyth	if (err != nil)
32137da2899SCharles.Forsyth		return ig(r, sys->sprint("auth->init: %r"));
32237da2899SCharles.Forsyth	(fd, err) = au->client(r.alg, ai, c.dfd);
32337da2899SCharles.Forsyth	if(fd == nil)
32437da2899SCharles.Forsyth		return ig(r, sys->sprint("auth: %r"));
32537da2899SCharles.Forsyth
32637da2899SCharles.Forsyth	if(sys->mount(fd, nil, dir, r.flags, spec) < 0)
32737da2899SCharles.Forsyth		return ig(r, sys->sprint("mount %q %q: %r", addr, dir));
32837da2899SCharles.Forsyth
32937da2899SCharles.Forsyth	return nil;
33037da2899SCharles.Forsyth}
33137da2899SCharles.Forsyth
33237da2899SCharles.Forsythimport9(argv: list of string, facfd: ref Sys->FD): string
33337da2899SCharles.Forsyth{
33437da2899SCharles.Forsyth	(r, err) := mopt(argv);
33537da2899SCharles.Forsyth	if(err != nil)
33637da2899SCharles.Forsyth		return err;
33737da2899SCharles.Forsyth
33837da2899SCharles.Forsyth	if(len r.argv < 2)
33937da2899SCharles.Forsyth		return "import: too few args";
34037da2899SCharles.Forsyth	if(facfd == nil)
34137da2899SCharles.Forsyth		return ig(r, "import: no factotum");
34237da2899SCharles.Forsyth	factotum := load Factotum Factotum->PATH;
34337da2899SCharles.Forsyth	if(factotum == nil)
34437da2899SCharles.Forsyth		return ig(r, sys->sprint("cannot load %s: %r", Factotum->PATH));
34537da2899SCharles.Forsyth	factotum->init();
34637da2899SCharles.Forsyth	addr := hd r.argv;
34737da2899SCharles.Forsyth	r.argv = tl r.argv;
34837da2899SCharles.Forsyth	rdir := hd r.argv;
34937da2899SCharles.Forsyth	r.argv = tl r.argv;
35037da2899SCharles.Forsyth	dir := rdir;
35137da2899SCharles.Forsyth	if(r.argv != nil)
35237da2899SCharles.Forsyth		dir = hd r.argv;
353fbc1184cSCharles Forsyth
354fbc1184cSCharles Forsyth	if(dial == nil){
355fbc1184cSCharles Forsyth		dial = load Dial Dial->PATH;
356fbc1184cSCharles Forsyth		if(dial == nil)
357fbc1184cSCharles Forsyth			return ig(r, "import: can't load Dial");
358fbc1184cSCharles Forsyth	}
359fbc1184cSCharles Forsyth
360fbc1184cSCharles Forsyth	dest := dial->netmkaddr(addr, "net", "17007");	# exportfs; might not be in inferno's ndb yet
361fbc1184cSCharles Forsyth	c := dial->dial(dest, nil);
362fbc1184cSCharles Forsyth	if(c == nil)
36337da2899SCharles.Forsyth		return ig(r, sys->sprint("import: %s: %r", dest));
36437da2899SCharles.Forsyth	fd := c.dfd;
36537da2899SCharles.Forsyth	if(factotum->proxy(fd, facfd, "proto=p9any role=client") == nil)
36637da2899SCharles.Forsyth		return ig(r, sys->sprint("import: %s: %r", dest));
36737da2899SCharles.Forsyth	if(sys->fprint(fd, "%s", rdir) < 0)
36837da2899SCharles.Forsyth		return ig(r, sys->sprint("import: %s: %r", dest));
36937da2899SCharles.Forsyth	buf := array[256] of byte;
37037da2899SCharles.Forsyth	if((n := sys->read(fd, buf, len buf)) != 2 || buf[0] != byte 'O' || buf[1] != byte 'K'){
37137da2899SCharles.Forsyth		if(n >= 4)
37237da2899SCharles.Forsyth			sys->werrstr(string buf[0:n]);
37337da2899SCharles.Forsyth		return ig(r, sys->sprint("import: %s: %r", dest));
37437da2899SCharles.Forsyth	}
37537da2899SCharles.Forsyth	# TO DO: new style: impo aan|nofilter clear|ssl|tls\n
37637da2899SCharles.Forsyth	afd := sys->fauth(fd, "");
377e84ac692SCharles.Forsyth	if(afd != nil)
378e84ac692SCharles.Forsyth		factotum->proxy(afd, facfd, "proto=p9any role=client");
37937da2899SCharles.Forsyth	if(sys->mount(fd, afd, dir, r.flags, "") < 0)
38037da2899SCharles.Forsyth		return ig(r, sys->sprint("import %q %q: %r", addr, dir));
38137da2899SCharles.Forsyth	return nil;
38237da2899SCharles.Forsyth}
38337da2899SCharles.Forsyth
38437da2899SCharles.Forsythunmount(argv: list of string): string
38537da2899SCharles.Forsyth{
38637da2899SCharles.Forsyth	(r, err) := mopt(argv);
38737da2899SCharles.Forsyth	if(err != nil)
38837da2899SCharles.Forsyth		return err;
38937da2899SCharles.Forsyth
39037da2899SCharles.Forsyth	from, tu: string;
39137da2899SCharles.Forsyth	case len r.argv {
39237da2899SCharles.Forsyth	* =>
39337da2899SCharles.Forsyth		return "unmount: takes 1 or 2 args";
39437da2899SCharles.Forsyth	1 =>
39537da2899SCharles.Forsyth		from = nil;
39637da2899SCharles.Forsyth		tu = hd r.argv;
39737da2899SCharles.Forsyth	2 =>
39837da2899SCharles.Forsyth		from = hd r.argv;
39937da2899SCharles.Forsyth		tu = hd tl r.argv;
40037da2899SCharles.Forsyth	}
40137da2899SCharles.Forsyth
40237da2899SCharles.Forsyth	if(sys->unmount(from, tu) < 0)
40337da2899SCharles.Forsyth		return ig(r, sys->sprint("unmount: %r"));
40437da2899SCharles.Forsyth
40537da2899SCharles.Forsyth	return nil;
40637da2899SCharles.Forsyth}
40737da2899SCharles.Forsyth
40837da2899SCharles.Forsythig(r: ref Moptres, e: string): string
40937da2899SCharles.Forsyth{
41037da2899SCharles.Forsyth	if(r.ignore)
41137da2899SCharles.Forsyth		return nil;
41237da2899SCharles.Forsyth	return e;
41337da2899SCharles.Forsyth}
41437da2899SCharles.Forsyth
41537da2899SCharles.Forsythuser(): string
41637da2899SCharles.Forsyth{
41737da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
41837da2899SCharles.Forsyth
41937da2899SCharles.Forsyth	fd := sys->open("/dev/user", sys->OREAD);
42037da2899SCharles.Forsyth	if(fd == nil)
42137da2899SCharles.Forsyth		return "";
42237da2899SCharles.Forsyth
42337da2899SCharles.Forsyth	buf := array[Sys->NAMEMAX] of byte;
42437da2899SCharles.Forsyth	n := sys->read(fd, buf, len buf);
42537da2899SCharles.Forsyth	if(n < 0)
42637da2899SCharles.Forsyth		return "";
42737da2899SCharles.Forsyth
42837da2899SCharles.Forsyth	return string buf[0:n];
42937da2899SCharles.Forsyth}
43037da2899SCharles.Forsyth
43137da2899SCharles.Forsythgetenv(name: string): (int, string)
43237da2899SCharles.Forsyth{
43337da2899SCharles.Forsyth	fd := sys->open("#e/"+name, Sys->OREAD);
43437da2899SCharles.Forsyth	if(fd == nil)
43537da2899SCharles.Forsyth		return (0, nil);
43637da2899SCharles.Forsyth	b := array[256] of byte;
43737da2899SCharles.Forsyth	n := sys->read(fd, b, len b);
43837da2899SCharles.Forsyth	if(n <= 0)
43937da2899SCharles.Forsyth		return (1, "");
44037da2899SCharles.Forsyth	for(i := 0; i < n; i++)
44137da2899SCharles.Forsyth		if(b[i] == byte 0 || b[i] == byte '\n')
44237da2899SCharles.Forsyth			break;
44337da2899SCharles.Forsyth	return (1, string b[0:i]);
44437da2899SCharles.Forsyth}
44537da2899SCharles.Forsyth
44637da2899SCharles.Forsythsetenv(name: string, val: string)
44737da2899SCharles.Forsyth{
44837da2899SCharles.Forsyth	fd := sys->create("#e/"+name, Sys->OWRITE, 8r664);
44937da2899SCharles.Forsyth	if(fd != nil)
45037da2899SCharles.Forsyth		sys->fprint(fd, "%s", val);
45137da2899SCharles.Forsyth}
45237da2899SCharles.Forsyth
453e84ac692SCharles.Forsythnewuser(user: string, cap: string, nsfile: string): string
454e84ac692SCharles.Forsyth{
455e84ac692SCharles.Forsyth	if(cap == nil)
456e84ac692SCharles.Forsyth		return "no capability";
457e84ac692SCharles.Forsyth
458e84ac692SCharles.Forsyth	sys = load Sys Sys->PATH;
459e84ac692SCharles.Forsyth	fd := sys->open("#¤/capuse", Sys->OWRITE);
460e84ac692SCharles.Forsyth	if(fd == nil)
461e84ac692SCharles.Forsyth		return sys->sprint("opening #¤/capuse: %r");
462e84ac692SCharles.Forsyth
463e84ac692SCharles.Forsyth	b := array of byte cap;
464e84ac692SCharles.Forsyth	if(sys->write(fd, b, len b) < 0)
465e84ac692SCharles.Forsyth		return sys->sprint("writing %s to #¤/capuse: %r", cap);
466e84ac692SCharles.Forsyth
467e84ac692SCharles.Forsyth	# mount factotum as new user (probably unhelpful if not factotum owner)
468e84ac692SCharles.Forsyth	sys->unmount(nil, "/mnt/factotum");
469e84ac692SCharles.Forsyth	sys->bind("#sfactotum", "/mnt/factotum", Sys->MREPL);
470e84ac692SCharles.Forsyth
471e84ac692SCharles.Forsyth	return newns(user, nsfile);
472e84ac692SCharles.Forsyth}
473