xref: /plan9/sys/src/cmd/disk/kfs/con.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
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, errstr[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], nelem[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(nelem);
214 	if(!con_walk(FID2, nelem))
215 		cprint("file %s already exists\n", nelem);
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", errstr[err]);
220 	else{
221 		convM2D(stat, &d);
222 		strncpy(d.name, nelem, NAMELEN);
223 		convD2M(&d, stat);
224 		if(err = con_wstat(FID2, stat))
225 			cprint("can't move file: %s\n", errstr[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 = &filsys[0];		/* default */
251 	} else {
252 		if(skipbl(1))
253 			return;
254 		if(!nextelem())
255 			fs = &filsys[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 >= 10000)
290 			continue;
291 		if(c > nu)
292 			nu = c;
293 	}
294 	nu++;
295 
296 	/*
297 	 * write onto adm/users
298 	 */
299 	if(con_clone(FID1, FID2)
300 	|| con_path(FID2, "/adm/users")
301 	|| con_open(FID2, 1)) {
302 		cprint("can't open /adm/users\n");
303 		return 0;
304 	}
305 
306 	sprint(msg, "%d:%s:%s:\n", nu, user, user);
307 	cprint("add user '%s'", msg);
308 	c = strlen(msg);
309 	i = con_stat(FID2, stat);
310 	if(i){
311 		cprint("can't stat /adm/users: %s\n", errstr[i]);
312 		return 0;
313 	}
314 	i = con_write(FID2, msg, statlen(stat), c);
315 	if(i != c){
316 		cprint("short write on /adm/users: %d %d\n", c, i);
317 		return 0;
318 	}
319 	return 1;
320 }
321 
322 void
323 cmd_newuser(void)
324 {
325 	char user[NAMELEN], msg[100];
326 	int i, c;
327 
328 	/*
329 	 * get uid
330 	 */
331 	cname(user);
332 	for(i=0; i<NAMELEN; i++) {
333 		c = user[i];
334 		if(c == 0)
335 			break;
336 		if(c >= '0' && c <= '9'
337 		|| c >= 'a' && c <= 'z'
338 		|| c >= 'A' && c <= 'Z')
339 			continue;
340 		cprint("bad character in name: 0x%x\n", c);
341 		return;
342 	}
343 	if(i < 2) {
344 		cprint("name too short: %s\n", user);
345 		return;
346 	}
347 	if(i >= NAMELEN) {
348 		cprint("name too long: %s\n", user);
349 		return;
350 	}
351 
352 	/*
353 	 * install and create directory
354 	 */
355 	if(!adduser(user))
356 		return;
357 
358 	cmd_exec("user");
359 	sprint(msg, "create /usr/%s %s %s 775 d", user, user, user);
360 	cmd_exec(msg);
361 	sprint(msg, "create /usr/%s/tmp %s %s 775 d", user, user, user);
362 	cmd_exec(msg);
363 	sprint(msg, "create /usr/%s/lib %s %s 775 d", user, user, user);
364 	cmd_exec(msg);
365 	sprint(msg, "create /usr/%s/bin %s %s 775 d", user, user, user);
366 	cmd_exec(msg);
367 	sprint(msg, "create /usr/%s/bin/rc %s %s 775 d", user, user, user);
368 	cmd_exec(msg);
369 	sprint(msg, "create /usr/%s/bin/mips %s %s 775 d", user, user, user);
370 	cmd_exec(msg);
371 	sprint(msg, "create /usr/%s/bin/386 %s %s 775 d", user, user, user);
372 	cmd_exec(msg);
373 	sprint(msg, "create /usr/%s/bin/68020 %s %s 775 d", user, user, user);
374 	cmd_exec(msg);
375 	sprint(msg, "create /usr/%s/bin/sparc %s %s 775 d", user, user, user);
376 	cmd_exec(msg);
377 }
378 
379 void
380 cmd_checkuser(void)
381 {
382 	uchar buf[DIRREC], *p;
383 	static char utime[4];
384 
385 	if(con_clone(FID1, FID2)
386 	|| con_path(FID2, "/adm/users")
387 	|| con_open(FID2, 0)
388 	|| con_stat(FID2, (char*)buf))
389 		return;
390 	p = buf + 3*NAMELEN + 4*4;
391 	if(memcmp(utime, p, 4) == 0)
392 		return;
393 	memmove(utime, p, 4);
394 	cmd_user();
395 }
396 
397 void
398 cmd_allow(void)
399 {
400 	wstatallow = 1;
401 }
402 
403 void
404 cmd_disallow(void)
405 {
406 	wstatallow = 0;
407 }
408 
409 Command	command[] =
410 {
411 	"allow",	cmd_allow,	"",
412 	"allowoff",	cmd_disallow,	"",
413 	"cfs",		cmd_cfs,	"[filsys]",
414 	"check",	cmd_check,	"[rftRdPpw]",
415 	"clri",		cmd_clri,	"filename",
416 	"create",	cmd_create,	"filename user group perm [ald]",
417 	"disallow",	cmd_disallow,	"",
418 	"halt",		cmd_halt,	"",
419 	"help",		cmd_help,	"",
420 	"newuser",	cmd_newuser,	"username",
421 	"remove",	cmd_remove,	"filename",
422 	"rename",	cmd_rename,	"file newname",
423 	"stats",	cmd_stats,	"[fw]",
424 	"sync",		cmd_sync,	"",
425 	"user",		cmd_user,	"",
426 	0
427 };
428 
429 int
430 skipbl(int err)
431 {
432 	if(*cons.arg != ' ') {
433 		if(err)
434 			cprint("syntax error\n");
435 		return 1;
436 	}
437 	while(*cons.arg == ' ')
438 		cons.arg++;
439 	return 0;
440 }
441 
442 char*
443 cname(char *name)
444 {
445 	int i, c;
446 
447 	skipbl(0);
448 	memset(name, 0, NAMELEN);
449 	for(i=0;; i++) {
450 		c = *cons.arg;
451 		switch(c) {
452 		case ' ':
453 		case '\t':
454 		case '\n':
455 		case '\0':
456 			return name;
457 		}
458 		if(i < NAMELEN-1)
459 			name[i] = c;
460 		cons.arg++;
461 	}
462 	return 0;
463 }
464 
465 int
466 nextelem(void)
467 {
468 	char *e;
469 	int i, c;
470 
471 	e = elem;
472 	while(*cons.arg == '/')
473 		cons.arg++;
474 	c = *cons.arg;
475 	if(c == 0 || c == ' ')
476 		return 0;
477 	for(i = 0; c = *cons.arg; i++) {
478 		if(c == ' ' || c == '/')
479 			break;
480 		if(i == NAMELEN) {
481 			cprint("path name component too long\n");
482 			return 0;
483 		}
484 		*e++ = c;
485 		cons.arg++;
486 	}
487 	*e = 0;
488 	return 1;
489 }
490 
491 long
492 number(int d, int base)
493 {
494 	int c, sign, any;
495 	long n;
496 
497 	sign = 0;
498 	any = 0;
499 	n = 0;
500 
501 	c = *cons.arg;
502 	while(c == ' ') {
503 		cons.arg++;
504 		c = *cons.arg;
505 	}
506 	if(c == '-') {
507 		sign = 1;
508 		cons.arg++;
509 		c = *cons.arg;
510 	}
511 	while((c >= '0' && c <= '9') ||
512 	      (base == 16 && c >= 'a' && c <= 'f') ||
513 	      (base == 16 && c >= 'A' && c <= 'F')) {
514 		n *= base;
515 		if(c >= 'a' && c <= 'f')
516 			n += c - 'a' + 10;
517 		else
518 		if(c >= 'A' && c <= 'F')
519 			n += c - 'A' + 10;
520 		else
521 			n += c - '0';
522 		cons.arg++;
523 		c = *cons.arg;
524 		any = 1;
525 	}
526 	if(!any)
527 		return d;
528 	if(sign)
529 		n = -n;
530 	return n;
531 }
532