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