xref: /inferno-os/appl/cmd/mount.b (revision 5c0f8147ea7f9ebf77ceaca86b122fac886ee742)
1implement Mount;
2
3include "sys.m";
4	sys: Sys;
5include "draw.m";
6include "keyring.m";
7include "security.m";
8include "dial.m";
9	dial: Dial;
10include "factotum.m";
11include "styxconv.m";
12include "styxpersist.m";
13include "arg.m";
14include "sh.m";
15
16Mount: module
17{
18	init:	 fn(nil: ref Draw->Context, nil: list of string);
19};
20
21verbose := 0;
22doauth := 1;
23do9 := 0;
24oldstyx := 0;
25persist := 0;
26showstyx := 0;
27quiet := 0;
28
29alg := "none";
30keyfile: string;
31spec: string;
32addr: string;
33
34fail(status, msg: string)
35{
36	sys->fprint(sys->fildes(2), "mount: %s\n", msg);
37	raise "fail:"+status;
38}
39
40nomod(mod: string)
41{
42	fail("load", sys->sprint("can't load %s: %r", mod));
43}
44
45init(ctxt: ref Draw->Context, args: list of string)
46{
47	sys = load Sys Sys->PATH;
48        dial = load Dial Dial->PATH;
49        if(dial == nil)
50                 nomod(Dial->PATH);
51	arg := load Arg Arg->PATH;
52	if(arg == nil)
53		nomod(Arg->PATH);
54
55	arg->init(args);
56	arg->setusage("mount [-a|-b] [-coA9] [-C cryptoalg] [-k keyfile] [-q] net!addr|file|{command} mountpoint [spec]");
57	flags := 0;
58	while((o := arg->opt()) != 0){
59		case o {
60		'a' =>
61			flags |= Sys->MAFTER;
62		'b' =>
63			flags |= Sys->MBEFORE;
64		'c' =>
65			flags |= Sys->MCREATE;
66		'C' =>
67			alg = arg->earg();
68		'k' or
69		'f' =>
70			keyfile = arg->earg();
71		'A' =>
72			doauth = 0;
73		'9' =>
74			doauth = 0;
75			do9 = 1;
76		'o' =>
77			oldstyx = 1;
78		'v' =>
79			verbose = 1;
80		'P' =>
81			persist = 1;
82		'S' =>
83			showstyx = 1;
84		'q' =>
85			quiet = 1;
86		*   =>
87			arg->usage();
88		}
89	}
90	args = arg->argv();
91	if(len args != 2){
92		if(len args != 3)
93			arg->usage();
94		spec = hd tl tl args;
95	}
96	arg = nil;
97	addr = hd args;
98	mountpoint := hd tl args;
99
100	if(oldstyx && do9)
101		fail("usage", "cannot combine -o and -9 options");
102
103	fd := connect(ctxt, addr);
104	ok: int;
105	if(do9){
106		fd = styxlog(fd);
107		factotum := load Factotum Factotum->PATH;
108		if(factotum == nil)
109			nomod(Factotum->PATH);
110		factotum->init();
111		ok = factotum->mount(fd, mountpoint, flags, spec, keyfile).t0;
112	}else{
113		err: string;
114		if(!persist){
115			(fd, err) = authcvt(fd);
116			if(fd == nil)
117				fail("error", err);
118		}
119		fd = styxlog(fd);
120		ok = sys->mount(fd, nil, mountpoint, flags, spec);
121	}
122	if(ok < 0 && !quiet)
123		fail("mount failed", sys->sprint("mount failed: %r"));
124}
125
126connect(ctxt: ref Draw->Context, dest: string): ref Sys->FD
127{
128	if(dest != nil && dest[0] == '{' && dest[len dest - 1] == '}'){
129		if(persist)
130			fail("usage", "cannot persistently mount a command");
131		doauth = 0;
132		return popen(ctxt, dest :: nil);
133	}
134	(n, nil) := sys->tokenize(dest, "!");
135	if(n == 1){
136		fd := sys->open(dest, Sys->ORDWR);
137		if(fd != nil){
138			if(persist)
139				fail("usage", "cannot persistently mount a file");
140			return fd;
141		}
142		if(dest[0] == '/')
143			fail("open failed", sys->sprint("can't open %s: %r", dest));
144	}
145	svc := "styx";
146	if(do9)
147		svc = "9fs";
148	dest = dial->netmkaddr(dest, "net", svc);
149	if(persist){
150		styxpersist := load Styxpersist Styxpersist->PATH;
151		if(styxpersist == nil)
152			fail("load", sys->sprint("cannot load %s: %r", Styxpersist->PATH));
153		sys->pipe(p := array[2] of ref Sys->FD);
154		(c, err) := styxpersist->init(p[0], do9, nil);
155		if(c == nil)
156			fail("error", "styxpersist: "+err);
157		spawn dialler(c, dest);
158		return p[1];
159	}
160	c := dial->dial(dest, nil);
161	if(c == nil)
162			fail("dial failed",  sys->sprint("can't dial %s: %r", dest));
163	return c.dfd;
164}
165
166dialler(dialc: chan of chan of ref Sys->FD, dest: string)
167{
168	while((reply := <-dialc) != nil){
169		if(verbose)
170			sys->print("dialling %s\n", addr);
171		c := dial->dial(dest, nil);
172		if(c == nil){
173			reply <-= nil;
174			continue;
175		}
176		(fd, err) := authcvt(c.dfd);
177		if(fd == nil && verbose)
178			sys->print("%s\n", err);
179		# XXX could check that user at the other end is still the same.
180		reply <-= fd;
181	}
182}
183
184authcvt(fd: ref Sys->FD): (ref Sys->FD, string)
185{
186	err: string;
187	if(doauth){
188		(fd, err) = authenticate(keyfile, alg, fd, addr);
189		if(fd == nil)
190			return (nil, err);
191		if(verbose)
192			sys->print("remote username is %s\n", err);
193	}
194	if(oldstyx)
195		return cvstyx(fd);
196	return (fd, nil);
197}
198
199popen(ctxt: ref Draw->Context, argv: list of string): ref Sys->FD
200{
201	sh := load Sh Sh->PATH;
202	if(sh == nil)
203		nomod(Sh->PATH);
204	sync := chan of int;
205	fds := array[2] of ref Sys->FD;
206	sys->pipe(fds);
207	spawn runcmd(sh, ctxt, argv, fds[0], sync);
208	<-sync;
209	return fds[1];
210}
211
212runcmd(sh: Sh, ctxt: ref Draw->Context, argv: list of string, stdin: ref Sys->FD, sync: chan of int)
213{
214	sys->pctl(Sys->FORKFD, nil);
215	sys->dup(stdin.fd, 0);
216	stdin = nil;
217	sync <-= 0;
218	sh->run(ctxt, argv);
219}
220
221cvstyx(fd: ref Sys->FD): (ref Sys->FD, string)
222{
223	styxconv := load Styxconv Styxconv->PATHNEW2OLD;
224	if(styxconv == nil)
225		return (nil, sys->sprint("cannot load %s: %r", Styxconv->PATHNEW2OLD));
226	styxconv->init();
227	p := array[2] of ref Sys->FD;
228	if(sys->pipe(p) < 0)
229		return (nil, sys->sprint("can't create pipe: %r"));
230	spawn styxconv->styxconv(p[1], fd);
231	p[1] = nil;
232	return (p[0], nil);
233}
234
235authenticate(keyfile, alg: string, dfd: ref Sys->FD, addr: string): (ref Sys->FD, string)
236{
237	cert : string;
238
239	kr := load Keyring Keyring->PATH;
240	if(kr == nil)
241		return (nil, sys->sprint("cannot load %s: %r", Keyring->PATH));
242
243	kd := "/usr/" + user() + "/keyring/";
244	if(keyfile == nil) {
245		cert = kd + dial->netmkaddr(addr, "tcp", "");
246		(ok, nil) := sys->stat(cert);
247		if (ok < 0)
248			cert = kd + "default";
249	}
250	else if(len keyfile > 0 && keyfile[0] != '/')
251		cert = kd + keyfile;
252	else
253		cert = keyfile;
254	ai := kr->readauthinfo(cert);
255	if(ai == nil)
256		return (nil, sys->sprint("cannot read %s: %r", cert));
257
258	auth := load Auth Auth->PATH;
259	if(auth == nil)
260		nomod(Auth->PATH);
261
262	err := auth->init();
263	if(err != nil)
264		return (nil, "cannot init auth: "+err);
265
266	fd: ref Sys->FD;
267	(fd, err) = auth->client(alg, ai, dfd);
268	if(fd == nil)
269		return (nil, "authentication failed: "+err);
270	return (fd, err);
271}
272
273user(): string
274{
275	fd := sys->open("/dev/user", sys->OREAD);
276	if(fd == nil)
277		return "";
278
279	buf := array[Sys->NAMEMAX] of byte;
280	n := sys->read(fd, buf, len buf);
281	if(n < 0)
282		return "";
283
284	return string buf[0:n];
285}
286
287kill(pid: int)
288{
289	if ((fd := sys->open("#p/" + string pid + "/ctl", Sys->OWRITE)) != nil)
290		sys->fprint(fd, "kill");
291}
292
293include "styx.m";
294	styx: Styx;
295	Rmsg, Tmsg: import styx;
296
297styxlog(fd: ref Sys->FD): ref Sys->FD
298{
299	if(showstyx){
300		sys->pipe(p := array[2] of ref Sys->FD);
301		styx = load Styx Styx->PATH;
302		styx->init();
303		spawn tmsgreader(p[0], fd, p1 := chan[1] of int, p2 := chan[1] of int);
304		spawn rmsgreader(fd, p[0], p2, p1);
305		fd = p[1];
306	}
307	return fd;
308}
309
310tmsgreader(cfd, sfd: ref Sys->FD, p1, p2: chan of int)
311{
312	p1 <-= sys->pctl(0, nil);
313	m: ref Tmsg;
314	do{
315		m = Tmsg.read(cfd, 9000);
316		sys->print("%s\n", m.text());
317		d := m.pack();
318		if(sys->write(sfd, d, len d) != len d)
319			sys->print("tmsg write error: %r\n");
320	} while(m != nil && tagof(m) != tagof(Tmsg.Readerror));
321	kill(<-p2);
322}
323
324rmsgreader(sfd, cfd: ref Sys->FD, p1, p2: chan of int)
325{
326	p1 <-= sys->pctl(0, nil);
327	m: ref Rmsg;
328	do{
329		m = Rmsg.read(sfd, 9000);
330		sys->print("%s\n", m.text());
331		d := m.pack();
332		if(sys->write(cfd, d, len d) != len d)
333			sys->print("rmsg write error: %r\n");
334	} while(m != nil && tagof(m) != tagof(Tmsg.Readerror));
335	kill(<-p2);
336}
337