con.c 13 KB

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