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