Plan 9 from Bell Labs’s /usr/web/sources/contrib/rog/infauth/unpacked/appl/authsrc/cpu.b

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


implement Cpu;

include "sys.m";
	sys: Sys;
include "draw.m";
include "styx.m";
include "iauth.m";
	iauth: Iauth;
include "string.m";
	str: String;
include "fdrun.m";
	fdrun: FDrun;
include "wmlib.m";
include "arg.m";

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

keyspec: string;
MAXCMD: con 128*1024;

init(ctxt: ref Draw->Context, argv: list of string)
{
	sys = load Sys Sys->PATH;
	iauth = load Iauth Iauth->PATH;
	if(iauth == nil)
		badmodule(Iauth->PATH);
	iauth->init();
	str = load String String->PATH;
	if(str == nil)
		badmodule(String->PATH);
	arg := load Arg Arg->PATH;
	fdrun = load FDrun FDrun->PATH;
	if(fdrun == nil)
		badmodule(FDrun->PATH);
	fdrun->init();

	arg->init(argv);
	arg->setusage("cpu [-RA] [-h system] [-k keyspec] [cmd [arg...]]");

	system := "$cpu";
	doauth := 1;
	while((opt := arg->opt()) != 0){
		case opt {
		'R' =>
			remotesideproc(ctxt);
			exit;
		'h' =>
			system = arg->earg();
		'k' =>
			keyspec = arg->earg();
		'A' =>
			doauth = 0;
		* =>
			arg->usage();
		}
	}
	argv = arg->argv();
	if(argv == nil)
		argv = "/dis/sh" :: "-i" :: nil;
	sys->pctl(Sys->FORKNS, nil);

	na := netmkaddr(system, nil, "rstyx");
	(ok, c) := sys->dial(na, nil);
	if(ok == -1)
		fatal(sys->sprint("cannot dial %q: %r", na));

	fd: ref Sys->FD;
	if(doauth){
		(afd, err) := iauth->auth("proto=infauth role=client "+keyspec, c.dfd, 0);
		if(afd == nil)
			fatal(sys->sprint("cannot authenticate: %s", err));
		fd = afd;
	}else
		fd = c.dfd;

	c.dfd = nil;

	{
		b := str->quoted(argv);
		t := array of byte sys->sprint("%d\n%s\n", len (array of byte b)+1, b);
		if(sys->write(fd, t, len t) != len t)
			fatal("cannot send command");
	}

	if(ctxt != nil && sys->stat("/mnt/wm/clone").t0 == -1){
		sys->pipe(p := array[2] of ref Sys->FD);
		fdrun->run(ctxt, "wmexport"::nil, "0--", array[] of {p[0]}, chan[1] of string);
		p[0] = nil;
		if(sys->mount(p[1], nil, "/mnt/wm", Sys->MREPL, nil) == -1)
			sys->fprint(sys->fildes(2), "cpu: warning: cannot mount wmexport: %r\n");
	}
#	servefile("cwd", sys->fd2path(sys->open(".", Sys->OREAD)));

	sys->export(fd, "/", Sys->EXPWAIT);
}

# called with stdin connected to client side, post authentication.
remotesideproc(ctxt: ref Draw->Context)
{
	sys->pctl(Sys->NEWPGRP|Sys->FORKNS, nil);
	argv := readcmd(sys->fildes(0));
	fd := sys->open("#M0/data", Sys->ORDWR);
	# make sure buffers are big by doing fversion explicitly; pick a large number; other side will trim
	(rc, nil) := sys->fversion(fd, 64*1024, Styx->VERSION);
	if(rc == -1)
		fatal(sys->sprint("fversion failed: %r"));

	if(sys->mount(fd, nil, "/n/local", Sys->MREPL|Sys->MCREATE, nil) == -1)
		fatal(sys->sprint("mount failed: %r"));

	fd = nil;
	fds := array[2] of ref Sys->FD;
	if((fds[0] = sys->open("/n/local/dev/cons", Sys->OREAD)) == nil)
		fatal(sys->sprint("cannot open stdin: %r"));
	if((fds[1]  = sys->open("/n/local/dev/cons", Sys->OWRITE)) == nil)
		fatal(sys->sprint("cannot open stdout: %r"));
	if(sys->stat("/n/local/mnt/wm/clone").t0 != -1){
		wmlib := load Wmlib Wmlib->PATH;
		wmlib->init();

		(ectxt, err) := wmlib->importdrawcontext("/n/local/dev", "/n/local/mnt/wm");
		if(ectxt == nil)
			sys->fprint(fds[1], "cpu: warning: failed to import draw context: %s\n", err);
		else{
			sys->fprint(fds[1], "cpu: imported draw context ok\n");
			ctxt = ectxt;
			sys->pctl(Sys->FORKNS, nil);
			spawn watchdogproc(fdc := chan of ref Sys->FD);
			if(sys->mount(<-fdc, nil, "/root", Sys->MREPL, nil) == -1)
				sys->fprint(sys->fildes(2), "failed to mount watchdog: %r\n");
		}
	}else
		sys->fprint(sys->fildes(2), "no wm context\n");
	fdrun->run(ctxt, argv, "011", fds, chan[1] of string);
}

# wait until all clients of the namespace leave,
# whereupon we kill the current process group.
# this terminates wmlib->importdrawcontext, which can't know
# when no more clients might arrive.
watchdogproc(fdc: chan of ref Sys->FD)
{
	sys->pipe(p := array[2] of ref Sys->FD);
	sys->pctl(Sys->NEWNS, nil);
	fdc <-= p[1];
	p[1] = nil;
	sys->export(p[0], "#//dev", Sys->EXPWAIT);
	sys->fprint(sys->open("#p/"+string sys->pctl(0, nil)+"/ctl", Sys->OWRITE), "killgrp");
}

readcmd(fd: ref Sys->FD): list of string
{
	b := array[1] of byte;
	nb := 0;
	while((n := sys->read(fd, b, 1)) > 0 && (c := int b[0]) != '\n')
		if(c >= '0' && c <= '9')
			nb = nb * 10 + (c - '0');
	if(n <= 0)
		fatal("protocol botch; premature EOF1");
	# size sanity check:
	if(nb > MAXCMD)
		fatal("command too large");
	buf := b = array[nb] of byte;
	while(nb > 0){
		n = sys->read(fd, b, len b);
		if(n <= 0)
			fatal("protocol botch; premature EOF2");
		b = b[n:];
		nb -= n;
	}
	return str->unquoted(string buf);
}

netmkaddr(addr, net, svc: string): string
{
	if(net == nil)
		net = "net";
	(n, nil) := sys->tokenize(addr, "!");
	if(n <= 1){
		if(svc== nil)
			return sys->sprint("%s!%s", net, addr);
		return sys->sprint("%s!%s!%s", net, addr, svc);
	}
	if(svc == nil || n > 2)
		return addr;
	return sys->sprint("%s!%s", addr, svc);
}

badmodule(p: string)
{
	fatal(sys->sprint("cannot load %q: %r", p));
}

fatal(e: string)
{
	sys->fprint(sys->fildes(2), "cpu: %s\n", e);
	raise "fail:error";
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.