1 #include "stdinc.h"
2
3 #include "9.h"
4
5 static struct {
6 VtLock* lock;
7
8 Con* con;
9 int confd[2];
10 ushort tag;
11 } cbox;
12
13 static ulong
cmd9pStrtoul(char * s)14 cmd9pStrtoul(char* s)
15 {
16 if(strcmp(s, "~0") == 0)
17 return ~0UL;
18 return strtoul(s, 0, 0);
19 }
20
21 static uvlong
cmd9pStrtoull(char * s)22 cmd9pStrtoull(char* s)
23 {
24 if(strcmp(s, "~0") == 0)
25 return ~0ULL;
26 return strtoull(s, 0, 0);
27 }
28
29 static int
cmd9pTag(Fcall *,int,char ** argv)30 cmd9pTag(Fcall*, int, char **argv)
31 {
32 cbox.tag = strtoul(argv[0], 0, 0)-1;
33
34 return 1;
35 }
36
37 static int
cmd9pTwstat(Fcall * f,int,char ** argv)38 cmd9pTwstat(Fcall* f, int, char **argv)
39 {
40 Dir d;
41 static uchar buf[DIRMAX];
42
43 memset(&d, 0, sizeof d);
44 nulldir(&d);
45 d.name = argv[1];
46 d.uid = argv[2];
47 d.gid = argv[3];
48 d.mode = cmd9pStrtoul(argv[4]);
49 d.mtime = cmd9pStrtoul(argv[5]);
50 d.length = cmd9pStrtoull(argv[6]);
51
52 f->fid = strtol(argv[0], 0, 0);
53 f->stat = buf;
54 f->nstat = convD2M(&d, buf, sizeof buf);
55 if(f->nstat < BIT16SZ){
56 vtSetError("Twstat: convD2M failed (internal error)");
57 return 0;
58 }
59
60 return 1;
61 }
62
63 static int
cmd9pTstat(Fcall * f,int,char ** argv)64 cmd9pTstat(Fcall* f, int, char** argv)
65 {
66 f->fid = strtol(argv[0], 0, 0);
67
68 return 1;
69 }
70
71 static int
cmd9pTremove(Fcall * f,int,char ** argv)72 cmd9pTremove(Fcall* f, int, char** argv)
73 {
74 f->fid = strtol(argv[0], 0, 0);
75
76 return 1;
77 }
78
79 static int
cmd9pTclunk(Fcall * f,int,char ** argv)80 cmd9pTclunk(Fcall* f, int, char** argv)
81 {
82 f->fid = strtol(argv[0], 0, 0);
83
84 return 1;
85 }
86
87 static int
cmd9pTwrite(Fcall * f,int,char ** argv)88 cmd9pTwrite(Fcall* f, int, char** argv)
89 {
90 f->fid = strtol(argv[0], 0, 0);
91 f->offset = strtoll(argv[1], 0, 0);
92 f->data = argv[2];
93 f->count = strlen(argv[2]);
94
95 return 1;
96 }
97
98 static int
cmd9pTread(Fcall * f,int,char ** argv)99 cmd9pTread(Fcall* f, int, char** argv)
100 {
101 f->fid = strtol(argv[0], 0, 0);
102 f->offset = strtoll(argv[1], 0, 0);
103 f->count = strtol(argv[2], 0, 0);
104
105 return 1;
106 }
107
108 static int
cmd9pTcreate(Fcall * f,int,char ** argv)109 cmd9pTcreate(Fcall* f, int, char** argv)
110 {
111 f->fid = strtol(argv[0], 0, 0);
112 f->name = argv[1];
113 f->perm = strtol(argv[2], 0, 8);
114 f->mode = strtol(argv[3], 0, 0);
115
116 return 1;
117 }
118
119 static int
cmd9pTopen(Fcall * f,int,char ** argv)120 cmd9pTopen(Fcall* f, int, char** argv)
121 {
122 f->fid = strtol(argv[0], 0, 0);
123 f->mode = strtol(argv[1], 0, 0);
124
125 return 1;
126 }
127
128 static int
cmd9pTwalk(Fcall * f,int argc,char ** argv)129 cmd9pTwalk(Fcall* f, int argc, char** argv)
130 {
131 int i;
132
133 if(argc < 2){
134 vtSetError("usage: Twalk tag fid newfid [name...]");
135 return 0;
136 }
137 f->fid = strtol(argv[0], 0, 0);
138 f->newfid = strtol(argv[1], 0, 0);
139 f->nwname = argc-2;
140 if(f->nwname > MAXWELEM){
141 vtSetError("Twalk: too many names");
142 return 0;
143 }
144 for(i = 0; i < argc-2; i++)
145 f->wname[i] = argv[2+i];
146
147 return 1;
148 }
149
150 static int
cmd9pTflush(Fcall * f,int,char ** argv)151 cmd9pTflush(Fcall* f, int, char** argv)
152 {
153 f->oldtag = strtol(argv[0], 0, 0);
154
155 return 1;
156 }
157
158 static int
cmd9pTattach(Fcall * f,int,char ** argv)159 cmd9pTattach(Fcall* f, int, char** argv)
160 {
161 f->fid = strtol(argv[0], 0, 0);
162 f->afid = strtol(argv[1], 0, 0);
163 f->uname = argv[2];
164 f->aname = argv[3];
165
166 return 1;
167 }
168
169 static int
cmd9pTauth(Fcall * f,int,char ** argv)170 cmd9pTauth(Fcall* f, int, char** argv)
171 {
172 f->afid = strtol(argv[0], 0, 0);
173 f->uname = argv[1];
174 f->aname = argv[2];
175
176 return 1;
177 }
178
179 static int
cmd9pTversion(Fcall * f,int,char ** argv)180 cmd9pTversion(Fcall* f, int, char** argv)
181 {
182 f->msize = strtoul(argv[0], 0, 0);
183 if(f->msize > cbox.con->msize){
184 vtSetError("msize too big");
185 return 0;
186 }
187 f->version = argv[1];
188
189 return 1;
190 }
191
192 typedef struct Cmd9p Cmd9p;
193 struct Cmd9p {
194 char* name;
195 int type;
196 int argc;
197 char* usage;
198 int (*f)(Fcall*, int, char**);
199 };
200
201 static Cmd9p cmd9pTmsg[] = {
202 "Tversion", Tversion, 2, "msize version", cmd9pTversion,
203 "Tauth", Tauth, 3, "afid uname aname", cmd9pTauth,
204 "Tflush", Tflush, 1, "oldtag", cmd9pTflush,
205 "Tattach", Tattach, 4, "fid afid uname aname", cmd9pTattach,
206 "Twalk", Twalk, 0, "fid newfid [name...]", cmd9pTwalk,
207 "Topen", Topen, 2, "fid mode", cmd9pTopen,
208 "Tcreate", Tcreate, 4, "fid name perm mode", cmd9pTcreate,
209 "Tread", Tread, 3, "fid offset count", cmd9pTread,
210 "Twrite", Twrite, 3, "fid offset data", cmd9pTwrite,
211 "Tclunk", Tclunk, 1, "fid", cmd9pTclunk,
212 "Tremove", Tremove, 1, "fid", cmd9pTremove,
213 "Tstat", Tstat, 1, "fid", cmd9pTstat,
214 "Twstat", Twstat, 7, "fid name uid gid mode mtime length", cmd9pTwstat,
215 "nexttag", 0, 0, "", cmd9pTag,
216 };
217
218 static int
cmd9p(int argc,char * argv[])219 cmd9p(int argc, char* argv[])
220 {
221 int i, n;
222 Fcall f, t;
223 uchar *buf;
224 char *usage;
225 u32int msize;
226
227 usage = "usage: 9p T-message ...";
228
229 ARGBEGIN{
230 default:
231 return cliError(usage);
232 }ARGEND
233 if(argc < 1)
234 return cliError(usage);
235
236 for(i = 0; i < nelem(cmd9pTmsg); i++){
237 if(strcmp(cmd9pTmsg[i].name, argv[0]) == 0)
238 break;
239 }
240 if(i == nelem(cmd9pTmsg))
241 return cliError(usage);
242 argc--;
243 argv++;
244 if(cmd9pTmsg[i].argc && argc != cmd9pTmsg[i].argc){
245 vtSetError("usage: %s %s",
246 cmd9pTmsg[i].name, cmd9pTmsg[i].usage);
247 return 0;
248 }
249
250 memset(&t, 0, sizeof(t));
251 t.type = cmd9pTmsg[i].type;
252 if(t.type == Tversion)
253 t.tag = NOTAG;
254 else
255 t.tag = ++cbox.tag;
256 msize = cbox.con->msize;
257 if(!cmd9pTmsg[i].f(&t, argc, argv))
258 return 0;
259 buf = vtMemAlloc(msize);
260 n = convS2M(&t, buf, msize);
261 if(n <= BIT16SZ){
262 vtSetError("%s: convS2M error", cmd9pTmsg[i].name);
263 vtMemFree(buf);
264 return 0;
265 }
266 if(write(cbox.confd[0], buf, n) != n){
267 vtSetError("%s: write error: %r", cmd9pTmsg[i].name);
268 vtMemFree(buf);
269 return 0;
270 }
271 consPrint("\t-> %F\n", &t);
272
273 if((n = read9pmsg(cbox.confd[0], buf, msize)) <= 0){
274 vtSetError("%s: read error: %r", cmd9pTmsg[i].name);
275 vtMemFree(buf);
276 return 0;
277 }
278 if(convM2S(buf, n, &f) == 0){
279 vtSetError("%s: convM2S error", cmd9pTmsg[i].name);
280 vtMemFree(buf);
281 return 0;
282 }
283 consPrint("\t<- %F\n", &f);
284
285 vtMemFree(buf);
286 return 1;
287 }
288
289 static int
cmdDot(int argc,char * argv[])290 cmdDot(int argc, char* argv[])
291 {
292 long l;
293 Dir *dir;
294 int fd, r;
295 vlong length;
296 char *f, *p, *s, *usage;
297
298 usage = "usage: . file";
299
300 ARGBEGIN{
301 default:
302 return cliError(usage);
303 }ARGEND
304 if(argc != 1)
305 return cliError(usage);
306
307 if((dir = dirstat(argv[0])) == nil)
308 return cliError(". dirstat %s: %r", argv[0]);
309 length = dir->length;
310 free(dir);
311
312 r = 1;
313 if(length != 0){
314 /*
315 * Read the whole file in.
316 */
317 if((fd = open(argv[0], OREAD)) < 0)
318 return cliError(". open %s: %r", argv[0]);
319 f = vtMemAlloc(dir->length+1);
320 if((l = read(fd, f, length)) < 0){
321 vtMemFree(f);
322 close(fd);
323 return cliError(". read %s: %r", argv[0]);
324 }
325 close(fd);
326 f[l] = '\0';
327
328 /*
329 * Call cliExec() for each line.
330 */
331 for(p = s = f; *p != '\0'; p++){
332 if(*p == '\n'){
333 *p = '\0';
334 if(cliExec(s) == 0){
335 r = 0;
336 consPrint("%s: %R\n", s);
337 }
338 s = p+1;
339 }
340 }
341 vtMemFree(f);
342 }
343
344 if(r == 0)
345 vtSetError("errors in . %#q", argv[0]);
346 return r;
347 }
348
349 static int
cmdDflag(int argc,char * argv[])350 cmdDflag(int argc, char* argv[])
351 {
352 char *usage;
353
354 usage = "usage: dflag";
355
356 ARGBEGIN{
357 default:
358 return cliError(usage);
359 }ARGEND
360 if(argc)
361 return cliError(usage);
362
363 Dflag ^= 1;
364 consPrint("dflag %d\n", Dflag);
365
366 return 1;
367 }
368
369 static int
cmdEcho(int argc,char * argv[])370 cmdEcho(int argc, char* argv[])
371 {
372 char *usage;
373 int i, nflag;
374
375 nflag = 0;
376 usage = "usage: echo [-n] ...";
377
378 ARGBEGIN{
379 default:
380 return cliError(usage);
381 case 'n':
382 nflag = 1;
383 break;
384 }ARGEND
385
386 for(i = 0; i < argc; i++){
387 if(i != 0)
388 consPrint(" %s", argv[i]);
389 else
390 consPrint(argv[i]);
391 }
392 if(!nflag)
393 consPrint("\n");
394
395 return 1;
396 }
397
398 static int
cmdBind(int argc,char * argv[])399 cmdBind(int argc, char* argv[])
400 {
401 ulong flag = 0;
402 char *usage;
403
404 usage = "usage: bind [-b|-a|-c|-bc|-ac] new old";
405
406 ARGBEGIN{
407 case 'a':
408 flag |= MAFTER;
409 break;
410 case 'b':
411 flag |= MBEFORE;
412 break;
413 case 'c':
414 flag |= MCREATE;
415 break;
416 default:
417 return cliError(usage);
418 }ARGEND
419
420 if(argc != 2 || (flag&MAFTER)&&(flag&MBEFORE))
421 return cliError(usage);
422
423 if(bind(argv[0], argv[1], flag) < 0){
424 /* try to give a less confusing error than the default */
425 if(access(argv[0], 0) < 0)
426 return cliError("bind: %s: %r", argv[0]);
427 else if(access(argv[1], 0) < 0)
428 return cliError("bind: %s: %r", argv[1]);
429 else
430 return cliError("bind %s %s: %r", argv[0], argv[1]);
431 }
432 return 1;
433 }
434
435 int
cmdInit(void)436 cmdInit(void)
437 {
438 cbox.lock = vtLockAlloc();
439 cbox.confd[0] = cbox.confd[1] = -1;
440
441 cliAddCmd(".", cmdDot);
442 cliAddCmd("9p", cmd9p);
443 cliAddCmd("dflag", cmdDflag);
444 cliAddCmd("echo", cmdEcho);
445 cliAddCmd("bind", cmdBind);
446
447 if(pipe(cbox.confd) < 0)
448 return 0;
449 if((cbox.con = conAlloc(cbox.confd[1], "console", 0)) == nil){
450 close(cbox.confd[0]);
451 close(cbox.confd[1]);
452 cbox.confd[0] = cbox.confd[1] = -1;
453 return 0;
454
455 }
456 cbox.con->isconsole = 1;
457
458 return 1;
459 }
460