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