xref: /plan9/sys/src/cmd/fossil/Ccmd.c (revision 2cca75a1b2b8c6083390679d69d5c50cf66d9a01)
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