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