con.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. #include "all.h"
  2. #include "9p1.h"
  3. static char elem[NAMELEN];
  4. static Filsys* cur_fs;
  5. static char conline[100];
  6. void
  7. consserve(void)
  8. {
  9. con_session();
  10. cmd_exec("cfs");
  11. cmd_exec("user");
  12. }
  13. int
  14. cmd_exec(char *arg)
  15. {
  16. char *s, *c;
  17. int i;
  18. for(i=0; s = command[i].string; i++) {
  19. for(c=arg; *s; c++)
  20. if(*c != *s++)
  21. goto brk;
  22. if(*c == '\0' || *c == ' ' || *c == '\t'){
  23. cons.arg = c;
  24. (*command[i].func)();
  25. return 1;
  26. }
  27. brk:;
  28. }
  29. return 0;
  30. }
  31. void
  32. cmd_check(void)
  33. {
  34. char *s;
  35. int flags;
  36. flags = 0;
  37. for(s = cons.arg; *s; s++){
  38. while(*s == ' ' || *s == '\t')
  39. s++;
  40. if(*s == '\0')
  41. break;
  42. switch(*s){
  43. /* rebuild the free list */
  44. case 'f': flags |= Cfree; break;
  45. /* fix bad tags */
  46. case 't': flags |= Ctag; break;
  47. /* fix bad tags and clear the contents of the block */
  48. case 'c': flags |= Cream; break;
  49. /* delete all redundant references to a block */
  50. case 'd': flags |= Cbad; break;
  51. /* read and check tags on all blocks */
  52. case 'r': flags |= Crdall; break;
  53. /* write all of the blocks you touch */
  54. case 'w': flags |= Ctouch; break;
  55. /* print all directories as they are read */
  56. case 'p': flags |= Cpdir; break;
  57. /* print all files as they are read */
  58. case 'P': flags |= Cpfile; break;
  59. /* quiet, just report really nasty stuff */
  60. case 'q': flags |= Cquiet; break;
  61. }
  62. }
  63. check(cur_fs, flags);
  64. }
  65. enum
  66. {
  67. Sset = (1<<0),
  68. Setc = (1<<1),
  69. };
  70. void
  71. cmd_stats(void)
  72. {
  73. cprint("work stats\n");
  74. cprint(" work = %A rps\n", (Filta){&cons.work, 1});
  75. cprint(" rate = %A tBps\n", (Filta){&cons.rate, 1000});
  76. cprint(" hits = %A iops\n", (Filta){&cons.bhit, 1});
  77. cprint(" read = %A iops\n", (Filta){&cons.bread, 1});
  78. cprint(" init = %A iops\n", (Filta){&cons.binit, 1});
  79. /* for(i = 0; i < MAXTAG; i++)
  80. cprint(" tag %G = %A iops\n", i, (Filta){&cons.tags[i], 1});
  81. */
  82. }
  83. void
  84. cmd_sync(void)
  85. {
  86. rlock(&mainlock);
  87. syncall();
  88. runlock(&mainlock);
  89. }
  90. void
  91. cmd_halt(void)
  92. {
  93. wlock(&mainlock);
  94. syncall();
  95. superok(cur_fs->dev, superaddr(cur_fs->dev), 1);
  96. print("kfs: file system halted\n");
  97. }
  98. void
  99. cmd_start(void)
  100. {
  101. superok(cur_fs->dev, superaddr(cur_fs->dev), 0);
  102. wunlock(&mainlock);
  103. print("kfs: file system started\n");
  104. }
  105. void
  106. cmd_help(void)
  107. {
  108. int i;
  109. for(i=0; command[i].string; i++)
  110. cprint(" %s %s\n", command[i].string, command[i].args);
  111. cprint("check options:\n"
  112. " r read all blocks\n"
  113. " f rebuild the free list\n"
  114. " t fix all bad tags\n"
  115. " c fix bad tags and zero the blocks\n"
  116. " d delete all redundant references to blocks\n"
  117. " p print directories as they are checked\n"
  118. " P print all files as they are checked\n"
  119. " w write all blocks that are read\n");
  120. }
  121. void
  122. cmd_create(void)
  123. {
  124. int uid, gid, err;
  125. long perm;
  126. char oelem[NAMELEN];
  127. char name[NAMELEN];
  128. if(err = con_clone(FID1, FID2)){
  129. cprint("clone failed: %s\n", errstring[err]);
  130. return;
  131. }
  132. if(skipbl(1)){
  133. cprint("skipbl\n");
  134. return;
  135. }
  136. oelem[0] = 0;
  137. while(nextelem()) {
  138. if(oelem[0])
  139. if(err = con_walk(FID2, oelem)){
  140. cprint("walk failed: %s\n", errstring[err]);
  141. return;
  142. }
  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. void
  176. cmd_clri(void)
  177. {
  178. if(con_clone(FID1, FID2))
  179. return;
  180. if(skipbl(1))
  181. return;
  182. while(nextelem())
  183. if(con_walk(FID2, elem)){
  184. cprint("can't walk %s\n", elem);
  185. return;
  186. }
  187. con_clri(FID2);
  188. }
  189. void
  190. cmd_rename(void)
  191. {
  192. ulong perm;
  193. Dentry d;
  194. char stat[DIRREC];
  195. char oelem[NAMELEN], noelem[NAMELEN], nxelem[NAMELEN];
  196. int err;
  197. if(con_clone(FID1, FID2))
  198. return;
  199. if(skipbl(1))
  200. return;
  201. oelem[0] = 0;
  202. while(nextelem()) {
  203. if(oelem[0])
  204. if(con_walk(FID2, oelem)){
  205. cprint("file does not exits");
  206. return;
  207. }
  208. memmove(oelem, elem, NAMELEN);
  209. }
  210. if(skipbl(1))
  211. return;
  212. if(cons.arg[0]=='/'){
  213. if(con_clone(FID1, FID3))
  214. return;
  215. noelem[0] = 0;
  216. while(nextelem()){
  217. if(noelem[0])
  218. if(con_walk(FID3, noelem)){
  219. cprint("target path %s does not exist", noelem);
  220. return;
  221. }
  222. memmove(noelem, elem, NAMELEN);
  223. }
  224. if(!con_walk(FID3, elem)){
  225. cprint("target %s already exists\n", elem);
  226. return;
  227. }
  228. if(con_walk(FID2, oelem)){
  229. cprint("src %s does not exist\n", oelem);
  230. return;
  231. }
  232. /*
  233. * we know the target does not exist,
  234. * the source does exist.
  235. * to do the rename, create the target and then
  236. * copy the directory entry directly. then remove the source.
  237. */
  238. if(err = con_stat(FID2, stat)){
  239. cprint("can't stat file: %s\n", errstring[err]);
  240. return;
  241. }
  242. convM2D9p1(stat, &d);
  243. perm = (d.mode&0777)|((d.mode&0x7000)<<17);
  244. if(err = con_create(FID3, elem, d.uid, d.gid, perm, (d.mode&DDIR)?OREAD:ORDWR)){
  245. cprint("can't create %s: %s\n", elem, errstring[err]);
  246. return;
  247. }
  248. if(err = con_swap(FID2, FID3)){
  249. cprint("can't swap data: %s\n", errstring[err]);
  250. return;
  251. }
  252. if(err = con_remove(FID2)){
  253. cprint("can't remove file: %s\n", errstring[err]);
  254. return;
  255. }
  256. }else{
  257. cname(nxelem);
  258. if(strchr(nxelem, '/')){
  259. cprint("bad rename target: not full path, but contains slashes\n");
  260. return;
  261. }
  262. if(!con_walk(FID2, nxelem))
  263. cprint("file %s already exists\n", nxelem);
  264. else if(con_walk(FID2, oelem))
  265. cprint("file does not already exist\n");
  266. else if(err = con_stat(FID2, stat))
  267. cprint("can't stat file: %s\n", errstring[err]);
  268. else{
  269. convM2D9p1(stat, &d);
  270. strncpy(d.name, nxelem, NAMELEN);
  271. convD2M9p1(&d, stat);
  272. if(err = con_wstat(FID2, stat))
  273. cprint("can't move file: %s\n", errstring[err]);
  274. }
  275. }
  276. }
  277. void
  278. cmd_remove(void)
  279. {
  280. if(con_clone(FID1, FID2))
  281. return;
  282. if(skipbl(1))
  283. return;
  284. while(nextelem())
  285. if(con_walk(FID2, elem)){
  286. cprint("can't walk %s\n", elem);
  287. return;
  288. }
  289. con_remove(FID2);
  290. }
  291. void
  292. cmd_cfs(void)
  293. {
  294. Filsys *fs;
  295. if(*cons.arg != ' ') {
  296. fs = &filesys[0]; /* default */
  297. } else {
  298. if(skipbl(1)){
  299. cprint("skipbl\n");
  300. return;
  301. }
  302. if(!nextelem())
  303. fs = &filesys[0]; /* default */
  304. else
  305. fs = fsstr(elem);
  306. }
  307. if(fs == 0) {
  308. cprint("unknown file system %s\n", elem);
  309. return;
  310. }
  311. if(con_attach(FID1, "adm", fs->name))
  312. panic("FID1 attach to root");
  313. cur_fs = fs;
  314. }
  315. /*
  316. * find out the length of a file
  317. * given the mesg version of a stat buffer
  318. * we call this because convM2D is different
  319. * for the file system than in the os
  320. */
  321. static uvlong
  322. statlen(char *ap)
  323. {
  324. uchar *p;
  325. ulong ll, hl;
  326. p = (uchar*)ap;
  327. p += 3*28+5*4;
  328. ll = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
  329. hl = p[4] | (p[5]<<8) | (p[6]<<16) | (p[7]<<24);
  330. return ll | ((uvlong) hl << 32);
  331. }
  332. int
  333. adduser(char *user, int isgroup)
  334. {
  335. char stat[DIRREC];
  336. char msg[100];
  337. Uid *u;
  338. int i, c, nu;
  339. /*
  340. * check uniq of name
  341. * and get next uid
  342. */
  343. cmd_exec("cfs");
  344. cmd_exec("user");
  345. if(isgroup)
  346. nu = 9000;
  347. else
  348. nu = 0;
  349. for(i=0, u=uid; i<conf.nuid; i++,u++) {
  350. c = u->uid;
  351. if(c == 0)
  352. break;
  353. if(strcmp(uidspace+u->offset, user) == 0)
  354. return 1;
  355. if(c >= 9000 && !isgroup)
  356. continue;
  357. if(c > nu)
  358. nu = c;
  359. }
  360. nu++;
  361. if(isgroup){
  362. if(nu >= 0x10000) {
  363. cprint("out of group ids\n");
  364. return 0;
  365. }
  366. } else {
  367. if(nu >= 9000) {
  368. cprint("out of user ids\n");
  369. return 0;
  370. }
  371. }
  372. /*
  373. * write onto adm/users
  374. */
  375. if(con_clone(FID1, FID2)
  376. || con_path(FID2, "/adm/users")
  377. || con_open(FID2, 1)) {
  378. cprint("can't open /adm/users\n");
  379. return 0;
  380. }
  381. sprint(msg, "%d:%s:%s:\n", nu, user, user);
  382. cprint("add user %s", msg);
  383. c = strlen(msg);
  384. i = con_stat(FID2, stat);
  385. if(i){
  386. cprint("can't stat /adm/users: %s\n", errstring[i]);
  387. return 0;
  388. }
  389. i = con_write(FID2, msg, statlen(stat), c);
  390. if(i != c){
  391. cprint("short write on /adm/users: %d %d\n", c, i);
  392. return 0;
  393. }
  394. return 1;
  395. }
  396. void
  397. cmd_newuser(void)
  398. {
  399. char user[NAMELEN], param[NAMELEN], msg[100];
  400. int i, c;
  401. /*
  402. * get uid
  403. */
  404. cname(user);
  405. cname(param);
  406. for(i=0; i<NAMELEN; i++) {
  407. c = user[i];
  408. if(c == 0)
  409. break;
  410. if(c >= '0' && c <= '9'
  411. || c >= 'a' && c <= 'z'
  412. || c >= 'A' && c <= 'Z')
  413. continue;
  414. cprint("bad character in name: 0x%x\n", c);
  415. return;
  416. }
  417. if(i < 2) {
  418. cprint("name too short: %s\n", user);
  419. return;
  420. }
  421. if(i >= NAMELEN) {
  422. cprint("name too long: %s\n", user);
  423. return;
  424. }
  425. switch(param[0]){
  426. case 0:
  427. if(!adduser(user, 0))
  428. return;
  429. cmd_exec("user");
  430. break;
  431. case ':':
  432. adduser(user, 1);
  433. cmd_exec("user");
  434. return;
  435. case '#':
  436. adduser(user, 0);
  437. cmd_exec("user");
  438. return;
  439. }
  440. /*
  441. * create directories
  442. */
  443. cmd_exec("user");
  444. sprint(msg, "create /usr/%s %s %s 775 d", user, user, user);
  445. cmd_exec(msg);
  446. sprint(msg, "create /usr/%s/tmp %s %s 775 d", user, user, user);
  447. cmd_exec(msg);
  448. sprint(msg, "create /usr/%s/lib %s %s 775 d", user, user, user);
  449. cmd_exec(msg);
  450. sprint(msg, "create /usr/%s/bin %s %s 775 d", user, user, user);
  451. cmd_exec(msg);
  452. sprint(msg, "create /usr/%s/bin/rc %s %s 775 d", user, user, user);
  453. cmd_exec(msg);
  454. sprint(msg, "create /usr/%s/bin/mips %s %s 775 d", user, user, user);
  455. cmd_exec(msg);
  456. sprint(msg, "create /usr/%s/bin/386 %s %s 775 d", user, user, user);
  457. cmd_exec(msg);
  458. sprint(msg, "create /usr/%s/bin/power %s %s 775 d", user, user, user);
  459. cmd_exec(msg);
  460. sprint(msg, "create /usr/%s/bin/alpha %s %s 775 d", user, user, user);
  461. cmd_exec(msg);
  462. }
  463. void
  464. cmd_checkuser(void)
  465. {
  466. uchar buf[DIRREC], *p;
  467. static char utime[4];
  468. if(con_clone(FID1, FID2)
  469. || con_path(FID2, "/adm/users")
  470. || con_open(FID2, 0)
  471. || con_stat(FID2, (char*)buf))
  472. return;
  473. p = buf + 3*NAMELEN + 4*4;
  474. if(memcmp(utime, p, 4) == 0)
  475. return;
  476. memmove(utime, p, 4);
  477. cmd_user();
  478. }
  479. void
  480. cmd_allow(void)
  481. {
  482. wstatallow = 1;
  483. }
  484. void
  485. cmd_disallow(void)
  486. {
  487. wstatallow = 0;
  488. }
  489. void
  490. cmd_chat(void)
  491. {
  492. chat = 1 - chat;
  493. }
  494. void
  495. cmd_atime(void)
  496. {
  497. noatime = !noatime;
  498. if(noatime)
  499. cprint("atimes will not be updated\n");
  500. else
  501. cprint("atimes will be updated\n");
  502. }
  503. void
  504. cmd_noneattach(void)
  505. {
  506. allownone = !allownone;
  507. if(allownone)
  508. cprint("none can attach to new connections\n");
  509. else
  510. cprint("none can only attach on authenticated connections\n");
  511. }
  512. void
  513. cmd_listen(void)
  514. {
  515. char addr[NAMELEN];
  516. if(skipbl(0))
  517. strcpy(addr, "il!*!17008");
  518. else
  519. cname(addr);
  520. if(netserve(addr))
  521. cprint("announce %s failed\n", addr);
  522. else
  523. cprint("announce %s\n", addr);
  524. }
  525. void
  526. cmd_nowritegroup(void)
  527. {
  528. writegroup = 0;
  529. }
  530. Command command[] =
  531. {
  532. "allow", cmd_allow, "",
  533. "allowoff", cmd_disallow, "",
  534. "atime", cmd_atime, "",
  535. "cfs", cmd_cfs, "[filesys]",
  536. "chat", cmd_chat, "",
  537. "check", cmd_check, "[cdfpPqrtw]",
  538. "clri", cmd_clri, "filename",
  539. "create", cmd_create, "filename user group perm [ald]",
  540. "disallow", cmd_disallow, "",
  541. "halt", cmd_halt, "",
  542. "help", cmd_help, "",
  543. "listen", cmd_listen, "[address]",
  544. "newuser", cmd_newuser, "username",
  545. "noneattach", cmd_noneattach, "",
  546. "nowritegroup", cmd_nowritegroup, "",
  547. "remove", cmd_remove, "filename",
  548. "rename", cmd_rename, "file newname",
  549. "start", cmd_start, "",
  550. "stats", cmd_stats, "[fw]",
  551. "sync", cmd_sync, "",
  552. "user", cmd_user, "",
  553. 0
  554. };
  555. int
  556. skipbl(int err)
  557. {
  558. if(*cons.arg != ' ') {
  559. if(err)
  560. cprint("syntax error\n");
  561. return 1;
  562. }
  563. while(*cons.arg == ' ')
  564. cons.arg++;
  565. return 0;
  566. }
  567. char*
  568. _cname(char *name)
  569. {
  570. int i, c;
  571. memset(name, 0, NAMELEN);
  572. for(i=0;; i++) {
  573. c = *cons.arg;
  574. switch(c) {
  575. case ' ':
  576. case '\t':
  577. case '\n':
  578. case '\0':
  579. return name;
  580. }
  581. if(i < NAMELEN-1)
  582. name[i] = c;
  583. cons.arg++;
  584. }
  585. }
  586. char*
  587. cname(char *name)
  588. {
  589. skipbl(0);
  590. return _cname(name);
  591. }
  592. int
  593. nextelem(void)
  594. {
  595. char *e;
  596. int i, c;
  597. e = elem;
  598. while(*cons.arg == '/')
  599. cons.arg++;
  600. c = *cons.arg;
  601. if(c == 0 || c == ' ')
  602. return 0;
  603. for(i = 0; c = *cons.arg; i++) {
  604. if(c == ' ' || c == '/')
  605. break;
  606. if(i == NAMELEN) {
  607. cprint("path name component too long\n");
  608. return 0;
  609. }
  610. *e++ = c;
  611. cons.arg++;
  612. }
  613. *e = 0;
  614. return 1;
  615. }
  616. long
  617. number(int d, int base)
  618. {
  619. int c, sign, any;
  620. long n;
  621. sign = 0;
  622. any = 0;
  623. n = 0;
  624. c = *cons.arg;
  625. while(c == ' ') {
  626. cons.arg++;
  627. c = *cons.arg;
  628. }
  629. if(c == '-') {
  630. sign = 1;
  631. cons.arg++;
  632. c = *cons.arg;
  633. }
  634. while((c >= '0' && c <= '9') ||
  635. (base == 16 && c >= 'a' && c <= 'f') ||
  636. (base == 16 && c >= 'A' && c <= 'F')) {
  637. n *= base;
  638. if(c >= 'a' && c <= 'f')
  639. n += c - 'a' + 10;
  640. else
  641. if(c >= 'A' && c <= 'F')
  642. n += c - 'A' + 10;
  643. else
  644. n += c - '0';
  645. cons.arg++;
  646. c = *cons.arg;
  647. any = 1;
  648. }
  649. if(!any)
  650. return d;
  651. if(sign)
  652. n = -n;
  653. return n;
  654. }