1 #include <u.h> 2 #include <libc.h> 3 #include <auth.h> 4 #include <fcall.h> 5 #include <bio.h> 6 7 uint messagesize = 65536; /* just a buffer size */ 8 9 void 10 usage(void) 11 { 12 fprint(2, "usage: aux/9pcon [-m messagesize] /srv/service | -c command | -n networkaddress\n"); 13 exits("usage"); 14 } 15 16 int 17 connectcmd(char *cmd) 18 { 19 int p[2]; 20 21 if(pipe(p) < 0) 22 return -1; 23 switch(fork()){ 24 case -1: 25 fprint(2, "fork failed: %r\n"); 26 _exits("exec"); 27 case 0: 28 dup(p[0], 0); 29 dup(p[0], 1); 30 close(p[1]); 31 execl("/bin/rc", "rc", "-c", cmd, nil); 32 fprint(2, "exec failed: %r\n"); 33 _exits("exec"); 34 default: 35 close(p[0]); 36 return p[1]; 37 } 38 } 39 40 void 41 watch(int fd) 42 { 43 int n; 44 uchar *buf; 45 Fcall f; 46 47 buf = malloc(messagesize); 48 if(buf == nil) 49 sysfatal("out of memory"); 50 51 while((n = read9pmsg(fd, buf, messagesize)) > 0){ 52 if(convM2S(buf, n, &f) == 0){ 53 print("convM2S: %r\n"); 54 continue; 55 } 56 print("\t<- %F\n", &f); 57 } 58 if(n == 0) 59 print("server eof\n"); 60 else 61 print("read9pmsg from server: %r\n"); 62 } 63 64 char* 65 tversion(Fcall *f, int, char **argv) 66 { 67 f->msize = atoi(argv[0]); 68 if(f->msize > messagesize) 69 return "message size too big; use -m option on command line"; 70 f->version = argv[1]; 71 return nil; 72 } 73 74 char* 75 tauth(Fcall *f, int, char **argv) 76 { 77 f->afid = atoi(argv[0]); 78 f->uname = argv[1]; 79 f->aname = argv[2]; 80 return nil; 81 } 82 83 char* 84 tflush(Fcall *f, int, char **argv) 85 { 86 f->oldtag = atoi(argv[0]); 87 return nil; 88 } 89 90 char* 91 tattach(Fcall *f, int, char **argv) 92 { 93 f->fid = atoi(argv[0]); 94 f->afid = atoi(argv[1]); 95 f->uname = argv[2]; 96 f->aname = argv[3]; 97 return nil; 98 } 99 100 char* 101 twalk(Fcall *f, int argc, char **argv) 102 { 103 int i; 104 105 if(argc < 2) 106 return "usage: Twalk tag fid newfid [name...]"; 107 f->fid = atoi(argv[0]); 108 f->newfid = atoi(argv[1]); 109 f->nwname = argc-2; 110 if(f->nwname > MAXWELEM) 111 return "too many names"; 112 for(i=0; i<argc-2; i++) 113 f->wname[i] = argv[2+i]; 114 return nil; 115 } 116 117 char* 118 topen(Fcall *f, int, char **argv) 119 { 120 f->fid = atoi(argv[0]); 121 f->mode = atoi(argv[1]); 122 return nil; 123 } 124 125 char* 126 tcreate(Fcall *f, int, char **argv) 127 { 128 f->fid = atoi(argv[0]); 129 f->name = argv[1]; 130 f->perm = strtoul(argv[2], 0, 8); 131 f->mode = atoi(argv[3]); 132 return nil; 133 } 134 135 char* 136 tread(Fcall *f, int, char **argv) 137 { 138 f->fid = atoi(argv[0]); 139 f->offset = strtoll(argv[1], 0, 0); 140 f->count = strtol(argv[2], 0, 0); 141 return nil; 142 } 143 144 char* 145 twrite(Fcall *f, int, char **argv) 146 { 147 f->fid = atoi(argv[0]); 148 f->offset = strtoll(argv[1], 0, 0); 149 f->data = argv[2]; 150 f->count = strlen(argv[2]); 151 return nil; 152 } 153 154 char* 155 tclunk(Fcall *f, int, char **argv) 156 { 157 f->fid = atoi(argv[0]); 158 return nil; 159 } 160 161 char* 162 tremove(Fcall *f, int, char **argv) 163 { 164 f->fid = atoi(argv[0]); 165 return nil; 166 } 167 168 char* 169 tstat(Fcall *f, int, char **argv) 170 { 171 f->fid = atoi(argv[0]); 172 return nil; 173 } 174 175 ulong 176 xstrtoul(char *s) 177 { 178 if(strcmp(s, "~0") == 0) 179 return ~0UL; 180 return strtoul(s, 0, 0); 181 } 182 183 uvlong 184 xstrtoull(char *s) 185 { 186 if(strcmp(s, "~0") == 0) 187 return ~0ULL; 188 return strtoull(s, 0, 0); 189 } 190 191 char* 192 twstat(Fcall *f, int, char **argv) 193 { 194 static uchar buf[DIRMAX]; 195 Dir d; 196 197 memset(&d, 0, sizeof d); 198 nulldir(&d); 199 d.name = argv[1]; 200 d.uid = argv[2]; 201 d.gid = argv[3]; 202 d.mode = xstrtoul(argv[4]); 203 d.mtime = xstrtoul(argv[5]); 204 d.length = xstrtoull(argv[6]); 205 206 f->fid = atoi(argv[0]); 207 f->stat = buf; 208 f->nstat = convD2M(&d, buf, sizeof buf); 209 if(f->nstat < BIT16SZ) 210 return "convD2M failed (internal error)"; 211 212 return nil; 213 } 214 215 int taggen; 216 217 char* 218 settag(Fcall*, int, char **argv) 219 { 220 static char buf[120]; 221 222 taggen = atoi(argv[0])-1; 223 snprint(buf, sizeof buf, "next tag is %d", taggen+1); 224 return buf; 225 } 226 227 typedef struct Cmd Cmd; 228 struct Cmd { 229 char *name; 230 int type; 231 int argc; 232 char *usage; 233 char *(*fn)(Fcall *f, int, char**); 234 }; 235 236 Cmd msg9p[] = { 237 "Tversion", Tversion, 2, "messagesize version", tversion, 238 "Tauth", Tauth, 3, "afid uname aname", tauth, 239 "Tflush", Tflush, 1, "oldtag", tflush, 240 "Tattach", Tattach, 4, "fid afid uname aname", tattach, 241 "Twalk", Twalk, 0, "fid newfid [name...]", twalk, 242 "Topen", Topen, 2, "fid mode", topen, 243 "Tcreate", Tcreate, 4, "fid name perm mode", tcreate, 244 "Tread", Tread, 3, "fid offset count", tread, 245 "Twrite", Twrite, 3, "fid offset data", twrite, 246 "Tclunk", Tclunk, 1, "fid", tclunk, 247 "Tremove", Tremove, 1, "fid", tremove, 248 "Tstat", Tstat, 1, "fid", tstat, 249 "Twstat", Twstat, 7, "fid name uid gid mode mtime length", twstat, 250 "nexttag", 0, 0, "", settag, 251 }; 252 253 void 254 shell9p(int fd) 255 { 256 char *e, *f[10], *p; 257 uchar *buf; 258 int i, n, nf; 259 Biobuf b; 260 Fcall t; 261 262 buf = malloc(messagesize); 263 if(buf == nil){ 264 fprint(2, "out of memory\n"); 265 return; 266 } 267 268 taggen = 0; 269 Binit(&b, 0, OREAD); 270 while(p = Brdline(&b, '\n')){ 271 p[Blinelen(&b)-1] = '\0'; 272 if(p[0] == '#') 273 continue; 274 if((nf = tokenize(p, f, nelem(f))) == 0) 275 continue; 276 for(i=0; i<nelem(msg9p); i++) 277 if(strcmp(f[0], msg9p[i].name) == 0) 278 break; 279 if(i == nelem(msg9p)){ 280 fprint(2, "?unknown message\n"); 281 continue; 282 } 283 memset(&t, 0, sizeof t); 284 t.type = msg9p[i].type; 285 if(t.type == Tversion) 286 t.tag = NOTAG; 287 else 288 t.tag = ++taggen; 289 if(nf < 1 || (msg9p[i].argc && nf != 1+msg9p[i].argc)){ 290 fprint(2, "?usage: %s %s\n", msg9p[i].name, msg9p[i].usage); 291 continue; 292 } 293 if(e = msg9p[i].fn(&t, nf-1, f+1)){ 294 fprint(2, "?%s\n", e); 295 continue; 296 } 297 n = convS2M(&t, buf, messagesize); 298 if(n <= BIT16SZ){ 299 fprint(2, "?message too large for buffer\n"); 300 continue; 301 } 302 if(write(fd, buf, n) != n){ 303 fprint(2, "?write fails: %r\n"); 304 break; 305 } 306 print("\t-> %F\n", &t); 307 } 308 } 309 310 void 311 main(int argc, char **argv) 312 { 313 int fd, pid, cmd, net; 314 315 cmd = 0; 316 net = 0; 317 ARGBEGIN{ 318 case 'c': 319 cmd = 1; 320 break; 321 case 'm': 322 messagesize = atoi(EARGF(usage())); 323 break; 324 case 'n': 325 net = 1; 326 break; 327 default: 328 usage(); 329 }ARGEND 330 331 fmtinstall('F', fcallfmt); 332 fmtinstall('D', dirfmt); 333 fmtinstall('M', dirmodefmt); 334 335 if(argc != 1) 336 usage(); 337 338 if(cmd && net) 339 usage(); 340 341 if(cmd) 342 fd = connectcmd(argv[0]); 343 else if(net){ 344 fd = dial(netmkaddr(argv[0], "net", "9fs"), 0, 0, 0); 345 if(fd < 0) 346 sysfatal("dial: %r"); 347 }else{ 348 fd = open(argv[0], ORDWR); 349 if(fd < 0) 350 sysfatal("open: %r"); 351 } 352 353 switch(pid = rfork(RFPROC|RFMEM)){ 354 case -1: 355 sysfatal("rfork: %r"); 356 break; 357 case 0: 358 watch(fd); 359 postnote(PNPROC, getppid(), "kill"); 360 break; 361 default: 362 shell9p(fd); 363 postnote(PNPROC, pid, "kill"); 364 break; 365 } 366 exits(nil); 367 } 368