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