xref: /plan9/sys/src/cmd/disk/kfs/con.c (revision 59cc4ca53493a3c6d2349fe2b7f7c40f7dce7294)
1 #include	"all.h"
2 
3 static	char	elem[NAMELEN];
4 static	Filsys*	cur_fs;
5 static	char	conline[100];
6 
7 void
8 consserve(void)
9 {
10 	strncpy(cons.chan->whoname, "console", sizeof(cons.chan->whoname));
11 	con_session();
12 	cmd_exec("cfs");
13 	cmd_exec("user");
14 }
15 
16 int
17 cmd_exec(char *arg)
18 {
19 	char *s, *c;
20 	int i;
21 
22 	for(i=0; s = command[i].string; i++) {
23 		for(c=arg; *s; c++)
24 			if(*c != *s++)
25 				goto brk;
26 		if(*c == '\0' || *c == ' ' || *c == '\t'){
27 			cons.arg = c;
28 			(*command[i].func)();
29 			return 1;
30 		}
31 	brk:;
32 	}
33 	return 0;
34 }
35 
36 void
37 cmd_check(void)
38 {
39 	char *s;
40 	int flags;
41 
42 	flags = 0;
43 	for(s = cons.arg; *s; s++){
44 		while(*s == ' ' || *s == '\t')
45 			s++;
46 		if(*s == '\0')
47 			break;
48 		switch(*s){
49 		/* rebuild the free list */
50 		case 'f':	flags |= Cfree;			break;
51 		/* fix bad tags */
52 		case 't':	flags |= Ctag;			break;
53 		/* fix bad tags and clear the contents of the block */
54 		case 'c':	flags |= Cream;			break;
55 		/* delete all redundant references to a block */
56 		case 'd':	flags |= Cbad;			break;
57 		/* read and check tags on all blocks */
58 		case 'r':	flags |= Crdall;		break;
59 		/* write all of the blocks you touch */
60 		case 'w':	flags |= Ctouch;		break;
61 		/* print all directories as they are read */
62 		case 'p':	flags |= Cpdir;			break;
63 		/* print all files as they are read */
64 		case 'P':	flags |= Cpfile;		break;
65 		/* quiet, just report really nasty stuff */
66 		case 'q':	flags |= Cquiet;		break;
67 		}
68 	}
69 	check(cur_fs, flags);
70 }
71 
72 enum
73 {
74 	Sset	= (1<<0),
75 	Setc	= (1<<1),
76 };
77 void
78 cmd_stats(void)
79 {
80 	cprint("work stats\n");
81 	cprint("	work = %F rps\n", (Filta){&cons.work, 1});
82 	cprint("	rate = %F tBps\n", (Filta){&cons.rate, 1000});
83 	cprint("	hits = %F iops\n", (Filta){&cons.bhit, 1});
84 	cprint("	read = %F iops\n", (Filta){&cons.bread, 1});
85 	cprint("	init = %F iops\n", (Filta){&cons.binit, 1});
86 /*	for(i = 0; i < MAXTAG; i++)
87 		cprint("	tag %G = %F iops\n", i, (Filta){&cons.tags[i], 1});
88 */
89 }
90 
91 void
92 cmd_sync(void)
93 {
94 	rlock(&mainlock);
95 	syncall();
96 	runlock(&mainlock);
97 }
98 
99 void
100 cmd_halt(void)
101 {
102 	wlock(&mainlock);
103 	syncall();
104 	superok(cur_fs->dev, superaddr(cur_fs->dev), 1);
105 	print("kfs: file system halted\n");
106 }
107 
108 void
109 cmd_help(void)
110 {
111 	int i;
112 
113 	for(i=0; command[i].string; i++)
114 		cprint("	%s %s\n", command[i].string, command[i].args);
115 	cprint("check options:\n"
116 		" r	read all blocks\n"
117 		" f	rebuild the free list\n"
118 		" t	fix all bad tags\n"
119 		" c	fix bad tags and zero the blocks\n"
120 		" d	delete all redundant references to blocks\n"
121 		" p	print directories as they are checked\n"
122 		" P	print all files as they are checked\n"
123 		" w	write all blocks that are read\n");
124 }
125 
126 void
127 cmd_create(void)
128 {
129 	int uid, gid, err;
130 	long perm;
131 	char oelem[NAMELEN];
132 	char name[NAMELEN];
133 
134 	if(con_clone(FID1, FID2))
135 		return;
136 	if(skipbl(1))
137 		return;
138 	oelem[0] = 0;
139 	while(nextelem()) {
140 		if(oelem[0])
141 			if(con_walk(FID2, oelem))
142 				return;
143 		memmove(oelem, elem, NAMELEN);
144 	}
145 	if(skipbl(1))
146 		return;
147 	uid = strtouid(cname(name));
148 	if(uid == 0){
149 		cprint("unknown user %s\n", name);
150 		return;
151 	}
152 	gid = strtouid(cname(name));
153 	if(gid == 0){
154 		cprint("unknown group %s\n", name);
155 		return;
156 	}
157 	perm = number(0777, 8);
158 	skipbl(0);
159 	for(; *cons.arg; cons.arg++){
160 		if(*cons.arg == 'l')
161 			perm |= PLOCK;
162 		else
163 		if(*cons.arg == 'a')
164 			perm |= PAPND;
165 		else
166 		if(*cons.arg == 'd')
167 			perm |= PDIR;
168 		else
169 			break;
170 	}
171 	err = con_create(FID2, elem, uid, gid, perm, 0);
172 	if(err)
173 		cprint("can't create %s: %s\n", elem, errstring[err]);
174 }
175 
176 void
177 cmd_clri(void)
178 {
179 	if(con_clone(FID1, FID2))
180 		return;
181 	if(skipbl(1))
182 		return;
183 	while(nextelem())
184 		if(con_walk(FID2, elem)){
185 			cprint("can't walk %s\n", elem);
186 			return;
187 		}
188 	con_clri(FID2);
189 }
190 
191 void
192 cmd_rename(void)
193 {
194 	Dentry d;
195 	char stat[DIRREC];
196 	char oelem[NAMELEN], nxelem[NAMELEN];
197 	int err;
198 
199 	if(con_clone(FID1, FID2))
200 		return;
201 	if(skipbl(1))
202 		return;
203 	oelem[0] = 0;
204 	while(nextelem()) {
205 		if(oelem[0])
206 			if(con_walk(FID2, oelem)){
207 				cprint("file does not exits");
208 				return;
209 			}
210 		memmove(oelem, elem, NAMELEN);
211 	}
212 	cname(nxelem);
213 	if(!con_walk(FID2, nxelem))
214 		cprint("file %s already exists\n", nxelem);
215 	else if(con_walk(FID2, oelem))
216 		cprint("file does not already exist\n");
217 	else if(err = con_stat(FID2, stat))
218 		cprint("can't stat file: %s\n", errstring[err]);
219 	else{
220 		convM2D(stat, &d);
221 		strncpy(d.name, nxelem, NAMELEN);
222 		convD2M(&d, stat);
223 		if(err = con_wstat(FID2, stat))
224 			cprint("can't move file: %s\n", errstring[err]);
225 	}
226 }
227 
228 void
229 cmd_remove(void)
230 {
231 	if(con_clone(FID1, FID2))
232 		return;
233 	if(skipbl(1))
234 		return;
235 	while(nextelem())
236 		if(con_walk(FID2, elem)){
237 			cprint("can't walk %s\n", elem);
238 			return;
239 		}
240 	con_remove(FID2);
241 }
242 
243 void
244 cmd_cfs(void)
245 {
246 	Filsys *fs;
247 
248 	if(*cons.arg != ' ') {
249 		fs = &filesys[0];		/* default */
250 	} else {
251 		if(skipbl(1))
252 			return;
253 		if(!nextelem())
254 			fs = &filesys[0];	/* default */
255 		else
256 			fs = fsstr(elem);
257 	}
258 	if(fs == 0) {
259 		cprint("unknown file system %s\n", elem);
260 		return;
261 	}
262 	if(con_attach(FID1, "adm", fs->name))
263 		panic("FID1 attach to root");
264 	cur_fs = fs;
265 }
266 
267 int
268 adduser(char *user)
269 {
270 	char stat[DIRREC];
271 	char msg[100];
272 	Uid *u;
273 	int i, c, nu;
274 
275 	/*
276 	 * check uniq of name
277 	 * and get next uid
278 	 */
279 	cmd_exec("cfs");
280 	cmd_exec("user");
281 	nu = 0;
282 	for(i=0, u=uid; i<conf.nuid; i++,u++) {
283 		c = u->uid;
284 		if(c == 0)
285 			break;
286 		if(strcmp(uidspace+u->offset, user) == 0)
287 			return 1;
288 		if(c >= 9000)
289 			continue;
290 		if(c > nu)
291 			nu = c;
292 	}
293 	nu++;
294 	if(nu >= 9000) {
295 		cprint("out of user ids\n");
296 		return 0;
297 	}
298 
299 	/*
300 	 * write onto adm/users
301 	 */
302 	if(con_clone(FID1, FID2)
303 	|| con_path(FID2, "/adm/users")
304 	|| con_open(FID2, 1)) {
305 		cprint("can't open /adm/users\n");
306 		return 0;
307 	}
308 
309 	sprint(msg, "%d:%s:%s:\n", nu, user, user);
310 	cprint("add user '%s'", msg);
311 	c = strlen(msg);
312 	i = con_stat(FID2, stat);
313 	if(i){
314 		cprint("can't stat /adm/users: %s\n", errstring[i]);
315 		return 0;
316 	}
317 	i = con_write(FID2, msg, statlen(stat), c);
318 	if(i != c){
319 		cprint("short write on /adm/users: %d %d\n", c, i);
320 		return 0;
321 	}
322 	return 1;
323 }
324 
325 void
326 cmd_newuser(void)
327 {
328 	char user[NAMELEN], msg[100];
329 	int i, c;
330 
331 	/*
332 	 * get uid
333 	 */
334 	cname(user);
335 	for(i=0; i<NAMELEN; i++) {
336 		c = user[i];
337 		if(c == 0)
338 			break;
339 		if(c >= '0' && c <= '9'
340 		|| c >= 'a' && c <= 'z'
341 		|| c >= 'A' && c <= 'Z')
342 			continue;
343 		cprint("bad character in name: 0x%x\n", c);
344 		return;
345 	}
346 	if(i < 2) {
347 		cprint("name too short: %s\n", user);
348 		return;
349 	}
350 	if(i >= NAMELEN) {
351 		cprint("name too long: %s\n", user);
352 		return;
353 	}
354 
355 	/*
356 	 * install and create directory
357 	 */
358 	if(!adduser(user))
359 		return;
360 
361 	cmd_exec("user");
362 	sprint(msg, "create /usr/%s %s %s 775 d", user, user, user);
363 	cmd_exec(msg);
364 	sprint(msg, "create /usr/%s/tmp %s %s 775 d", user, user, user);
365 	cmd_exec(msg);
366 	sprint(msg, "create /usr/%s/lib %s %s 775 d", user, user, user);
367 	cmd_exec(msg);
368 	sprint(msg, "create /usr/%s/bin %s %s 775 d", user, user, user);
369 	cmd_exec(msg);
370 	sprint(msg, "create /usr/%s/bin/rc %s %s 775 d", user, user, user);
371 	cmd_exec(msg);
372 	sprint(msg, "create /usr/%s/bin/mips %s %s 775 d", user, user, user);
373 	cmd_exec(msg);
374 	sprint(msg, "create /usr/%s/bin/386 %s %s 775 d", user, user, user);
375 	cmd_exec(msg);
376 	sprint(msg, "create /usr/%s/bin/power %s %s 775 d", user, user, user);
377 	cmd_exec(msg);
378 	sprint(msg, "create /usr/%s/bin/alpha %s %s 775 d", user, user, user);
379 	cmd_exec(msg);
380 }
381 
382 void
383 cmd_checkuser(void)
384 {
385 	uchar buf[DIRREC], *p;
386 	static char utime[4];
387 
388 	if(con_clone(FID1, FID2)
389 	|| con_path(FID2, "/adm/users")
390 	|| con_open(FID2, 0)
391 	|| con_stat(FID2, (char*)buf))
392 		return;
393 	p = buf + 3*NAMELEN + 4*4;
394 	if(memcmp(utime, p, 4) == 0)
395 		return;
396 	memmove(utime, p, 4);
397 	cmd_user();
398 }
399 
400 void
401 cmd_allow(void)
402 {
403 	wstatallow = 1;
404 }
405 
406 void
407 cmd_disallow(void)
408 {
409 	wstatallow = 0;
410 }
411 
412 void
413 cmd_chat(void)
414 {
415 	chat = 1 - chat;
416 }
417 
418 void
419 cmd_noneattach(void)
420 {
421 	allownone = !allownone;
422 	if(allownone)
423 		cprint("none can attach to new connections\n");
424 	else
425 		cprint("none can only attach on authenticated connections\n");
426 }
427 
428 void
429 cmd_noauth(void)
430 {
431 	if (noauth) {
432 		if (nvr.authid[0] == '\0' || nvr.authkey[0] == '\0')
433 			cprint("auth configuration error\n");
434 		else
435 			noauth = 0;
436 	} else
437 		noauth = 1;
438 	cprint("authentication %sabled\n", noauth? "dis" : "en");
439 }
440 
441 void
442 cmd_listen(void)
443 {
444 	char addr[NAMELEN];
445 
446 	if(skipbl(0))
447 		strcpy(addr, "il!*!17008");
448 	else
449 		cname(addr);
450 
451 	if(netserve(addr))
452 		cprint("announce %s failed\n", addr);
453 	else
454 		cprint("announce %s\n", addr);
455 }
456 
457 Command	command[] =
458 {
459 	"allow",	cmd_allow,	"",
460 	"allowoff",	cmd_disallow,	"",
461 	"cfs",		cmd_cfs,	"[filesys]",
462 	"chat",		cmd_chat,	"",
463 	"check",	cmd_check,	"[rftRdPpw]",
464 	"clri",		cmd_clri,	"filename",
465 	"create",	cmd_create,	"filename user group perm [ald]",
466 	"disallow",	cmd_disallow,	"",
467 	"halt",		cmd_halt,	"",
468 	"help",		cmd_help,	"",
469 	"listen",		cmd_listen,	"[address]",
470 	"newuser",	cmd_newuser,	"username",
471 	"noauth",		cmd_noauth,	"",
472 	"noneattach",	cmd_noneattach, "",
473 	"remove",	cmd_remove,	"filename",
474 	"rename",	cmd_rename,	"file newname",
475 	"stats",	cmd_stats,	"[fw]",
476 	"sync",		cmd_sync,	"",
477 	"user",		cmd_user,	"",
478 	0
479 };
480 
481 int
482 skipbl(int err)
483 {
484 	if(*cons.arg != ' ') {
485 		if(err)
486 			cprint("syntax error\n");
487 		return 1;
488 	}
489 	while(*cons.arg == ' ')
490 		cons.arg++;
491 	return 0;
492 }
493 
494 char*
495 cname(char *name)
496 {
497 	int i, c;
498 
499 	skipbl(0);
500 	memset(name, 0, NAMELEN);
501 	for(i=0;; i++) {
502 		c = *cons.arg;
503 		switch(c) {
504 		case ' ':
505 		case '\t':
506 		case '\n':
507 		case '\0':
508 			return name;
509 		}
510 		if(i < NAMELEN-1)
511 			name[i] = c;
512 		cons.arg++;
513 	}
514 	return 0;
515 }
516 
517 int
518 nextelem(void)
519 {
520 	char *e;
521 	int i, c;
522 
523 	e = elem;
524 	while(*cons.arg == '/')
525 		cons.arg++;
526 	c = *cons.arg;
527 	if(c == 0 || c == ' ')
528 		return 0;
529 	for(i = 0; c = *cons.arg; i++) {
530 		if(c == ' ' || c == '/')
531 			break;
532 		if(i == NAMELEN) {
533 			cprint("path name component too long\n");
534 			return 0;
535 		}
536 		*e++ = c;
537 		cons.arg++;
538 	}
539 	*e = 0;
540 	return 1;
541 }
542 
543 long
544 number(int d, int base)
545 {
546 	int c, sign, any;
547 	long n;
548 
549 	sign = 0;
550 	any = 0;
551 	n = 0;
552 
553 	c = *cons.arg;
554 	while(c == ' ') {
555 		cons.arg++;
556 		c = *cons.arg;
557 	}
558 	if(c == '-') {
559 		sign = 1;
560 		cons.arg++;
561 		c = *cons.arg;
562 	}
563 	while((c >= '0' && c <= '9') ||
564 	      (base == 16 && c >= 'a' && c <= 'f') ||
565 	      (base == 16 && c >= 'A' && c <= 'F')) {
566 		n *= base;
567 		if(c >= 'a' && c <= 'f')
568 			n += c - 'a' + 10;
569 		else
570 		if(c >= 'A' && c <= 'F')
571 			n += c - 'A' + 10;
572 		else
573 			n += c - '0';
574 		cons.arg++;
575 		c = *cons.arg;
576 		any = 1;
577 	}
578 	if(!any)
579 		return d;
580 	if(sign)
581 		n = -n;
582 	return n;
583 }
584