Charles.Forsyth20080116-1340f4bb33e18 years agoHistory
231 lines · 4.7 KB · Brainfuck
RawDownload
implement Mount; include "sys.m";	sys: Sys;include "draw.m";include "keyring.m";include "security.m";include "arg.m";include "sh.m";include "styxconv.m";	styxconv: Styxconv; Mount: module{	init:	 fn(nil: ref Draw->Context, nil: list of string);}; vflag := 0;doauth := 1; usage(){	sys->fprint(sys->fildes(2), "Usage: mount [-a|-b] [-cA] [-C cryptoalg] [-f keyfile] net!addr|file|{command} mountpoint [spec]\n");	raise "fail:usage";} fail(status, msg: string){	sys->fprint(sys->fildes(2), "mount: %s\n", msg);	raise "fail:"+status;} nomod(mod: string){	fail("load", sys->sprint("can't load %s: %r", mod));} init(ctxt: ref Draw->Context, args: list of string){	sys = load Sys Sys->PATH; 	vflag = 0;	unauth := 0;	alg := "none";	keyfile: string;	spec: string; 	arg := load Arg Arg->PATH;	if(arg == nil)		nomod(Arg->PATH);	styxconv = load Styxconv Styxconv->PATH;	if(styxconv == nil)		nomod(Styxconv->PATH); 	arg->init(args);	styxconv->init(); 	flags := 0;	while((o := arg->opt()) != 0)		case o {		'a' =>			flags |= Sys->MAFTER;		'b' =>			flags |= Sys->MBEFORE;		'c' =>			flags |= Sys->MCREATE;		'C' =>			alg = arg->arg();			if(alg == nil)				usage();		'f' =>			keyfile = arg->arg();			if(keyfile == nil)				usage();		'A' =>			doauth = 0;		'v' =>			vflag = 1;		'u' =>			unauth = 1;	# temporary, undocumented option for testing		*   =>			usage();		}	args = arg->argv();	arg = nil;	if(len args != 2){		if(len args != 3)			usage();		spec = hd tl tl args;	}	addr := hd args;	mountpoint := hd tl args; 	# open stream	fd := do_connect(ctxt, addr); 	# authenticate if necessary	if (doauth)		fd = do_auth(keyfile, alg, fd, addr, unauth); 	p := array[2] of ref Sys->FD;	if(sys->pipe(p) < 0)		fail("can't create pipe", sys->sprint("can't create pipe: %r"));	pidch := chan of int;	spawn styxconv->styxconv(p[1], fd, pidch);	p[1] = nil;	<- pidch;	ok := sys->mount(p[0], nil, mountpoint, flags, spec);	p[0] = nil;	if(ok < 0)		fail("mount failed", sys->sprint("mount failed: %r"));	} # either make network connection or open filedo_connect(ctxt: ref Draw->Context, dest: string): ref Sys->FD{	if(dest != nil && dest[0] == '{' && dest[len dest - 1] == '}'){		doauth = 0;		return popen(ctxt, dest :: nil);	}	(n, nil) := sys->tokenize(dest, "!");	if(n == 1){		fd := sys->open(dest, Sys->ORDWR);		if(fd != nil)			return fd;		if(dest[0] == '/')			fail("open failed", sys->sprint("can't open %s: %r", dest));	}	(ok, c) := sys->dial(netmkaddr(dest, "net", "styx"), nil);	if(ok < 0)			fail("dial failed",  sys->sprint("can't dial %s: %r", dest));	return c.dfd;} popen(ctxt: ref Draw->Context, argv: list of string): ref Sys->FD{	sh := load Sh Sh->PATH;	if(sh == nil)		nomod(Sh->PATH);	sync := chan of int;	fds := array[2] of ref Sys->FD;	sys->pipe(fds);	spawn runcmd(sh, ctxt, argv, fds[0], sync);	<-sync;	return fds[1];} runcmd(sh: Sh, ctxt: ref Draw->Context, argv: list of string, stdin: ref Sys->FD,		sync: chan of int){	sys->pctl(Sys->FORKFD, nil);	sys->dup(stdin.fd, 0);	stdin = nil;	sync <-= 0;	sh->run(ctxt, argv);} # authenticate if necessarydo_auth(keyfile, alg: string, dfd: ref Sys->FD, addr: string, unauth: int): ref Sys->FD{	cert : string; 	kr := load Keyring Keyring->PATH;	if(kr == nil)		nomod(Keyring->PATH); 	kd := "/usr/" + user() + "/keyring/";	if (keyfile == nil) {		cert = kd + netmkaddr(addr, "tcp", "");		(ok, nil) := sys->stat(cert);		if (ok < 0)			cert = kd + "default";	}	else if (len keyfile > 0 && keyfile[0] != '/')		cert = kd + keyfile;	else		cert = keyfile;	ai := kr->readauthinfo(cert);	if (ai == nil){		if(!unauth)			fail("readauthinfo failed", sys->sprint("cannot read %s: %r", cert));		sys->fprint(sys->fildes(2), "mount: can't read %s (%r): trying mount as `nobody'\n", cert);	} 	au := load Auth Auth->PATH;	if(au == nil)		nomod(Auth->PATH); 	err := au->init();	if(err != nil)		fail("auth init failed", sys->sprint("cannot init Auth: %s", err)); 	fd: ref Sys->FD;	(fd, err) = au->client(alg, ai, dfd);	if(fd == nil)		fail("auth failed", sys->sprint("authentication failed: %s", err));	if(vflag)		sys->print("remote username is %s\n", err); 	return fd;} user(): string{	fd := sys->open("/dev/user", sys->OREAD);	if(fd == nil)		return ""; 	buf := array[Sys->NAMEMAX] of byte;	n := sys->read(fd, buf, len buf);	if(n < 0)		return ""; 	return string buf[0:n]; } 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);}