devcons.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. #include "dat.h"
  2. #include "fns.h"
  3. #include "error.h"
  4. #include "version.h"
  5. #include "mp.h"
  6. #include "libsec.h"
  7. #include "keyboard.h"
  8. extern int cflag;
  9. int exdebug;
  10. extern int keepbroken;
  11. enum
  12. {
  13. Qdir,
  14. Qcons,
  15. Qconsctl,
  16. Qdrivers,
  17. Qhostowner,
  18. Qhoststdin,
  19. Qhoststdout,
  20. Qhoststderr,
  21. Qjit,
  22. Qkeyboard,
  23. Qkprint,
  24. Qmemory,
  25. Qmsec,
  26. Qnotquiterandom,
  27. Qnull,
  28. Qrandom,
  29. Qscancode,
  30. Qsysctl,
  31. Qsysname,
  32. Qtime,
  33. Quser
  34. };
  35. Dirtab contab[] =
  36. {
  37. ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
  38. "cons", {Qcons}, 0, 0666,
  39. "consctl", {Qconsctl}, 0, 0222,
  40. "drivers", {Qdrivers}, 0, 0444,
  41. "hostowner", {Qhostowner}, 0, 0644,
  42. "hoststdin", {Qhoststdin}, 0, 0444,
  43. "hoststdout", {Qhoststdout}, 0, 0222,
  44. "hoststderr", {Qhoststderr}, 0, 0222,
  45. "jit", {Qjit}, 0, 0666,
  46. "keyboard", {Qkeyboard}, 0, 0666,
  47. "kprint", {Qkprint}, 0, 0444,
  48. "memory", {Qmemory}, 0, 0444,
  49. "msec", {Qmsec}, NUMSIZE, 0444,
  50. "notquiterandom", {Qnotquiterandom}, 0, 0444,
  51. "null", {Qnull}, 0, 0666,
  52. "random", {Qrandom}, 0, 0444,
  53. "scancode", {Qscancode}, 0, 0444,
  54. "sysctl", {Qsysctl}, 0, 0644,
  55. "sysname", {Qsysname}, 0, 0644,
  56. "time", {Qtime}, 0, 0644,
  57. "user", {Quser}, 0, 0644,
  58. };
  59. Queue* gkscanq; /* Graphics keyboard raw scancodes */
  60. char* gkscanid; /* name of raw scan format (if defined) */
  61. Queue* gkbdq; /* Graphics keyboard unprocessed input */
  62. Queue* kbdq; /* Console window unprocessed keyboard input */
  63. Queue* lineq; /* processed console input */
  64. char *ossysname;
  65. static struct
  66. {
  67. RWlock l;
  68. Queue* q;
  69. } kprintq;
  70. vlong timeoffset;
  71. extern int dflag;
  72. static int sysconwrite(void*, ulong);
  73. extern char** rebootargv;
  74. static struct
  75. {
  76. QLock q;
  77. QLock gq; /* separate lock for the graphical input */
  78. int raw; /* true if we shouldn't process input */
  79. Ref ctl; /* number of opens to the control file */
  80. Ref ptr; /* number of opens to the ptr file */
  81. int scan; /* true if reading raw scancodes */
  82. int x; /* index into line */
  83. char line[1024]; /* current input line */
  84. Rune c;
  85. int count;
  86. } kbd;
  87. void
  88. kbdslave(void *a)
  89. {
  90. char b;
  91. USED(a);
  92. for(;;) {
  93. b = readkbd();
  94. if(kbd.raw == 0){
  95. switch(b){
  96. case 0x15:
  97. write(1, "^U\n", 3);
  98. break;
  99. default:
  100. write(1, &b, 1);
  101. break;
  102. }
  103. }
  104. qproduce(kbdq, &b, 1);
  105. }
  106. /* pexit("kbdslave", 0); */ /* not reached */
  107. }
  108. void
  109. gkbdputc(Queue *q, int ch)
  110. {
  111. int n;
  112. Rune r;
  113. static uchar kc[5*UTFmax];
  114. static int nk, collecting = 0;
  115. char buf[UTFmax];
  116. r = ch;
  117. if(r == Latin) {
  118. collecting = 1;
  119. nk = 0;
  120. return;
  121. }
  122. if(collecting) {
  123. int c;
  124. nk += runetochar((char*)&kc[nk], &r);
  125. c = latin1(kc, nk);
  126. if(c < -1) /* need more keystrokes */
  127. return;
  128. collecting = 0;
  129. if(c == -1) { /* invalid sequence */
  130. qproduce(q, kc, nk);
  131. return;
  132. }
  133. r = (Rune)c;
  134. }
  135. n = runetochar(buf, &r);
  136. if(n == 0)
  137. return;
  138. /* if(!isdbgkey(r)) */
  139. qproduce(q, buf, n);
  140. }
  141. void
  142. consinit(void)
  143. {
  144. kbdq = qopen(512, 0, nil, nil);
  145. if(kbdq == 0)
  146. panic("no memory");
  147. lineq = qopen(2*1024, 0, nil, nil);
  148. if(lineq == 0)
  149. panic("no memory");
  150. gkbdq = qopen(512, 0, nil, nil);
  151. if(gkbdq == 0)
  152. panic("no memory");
  153. randominit();
  154. }
  155. /*
  156. * return true if current user is eve
  157. */
  158. int
  159. iseve(void)
  160. {
  161. return strcmp(eve, up->env->user) == 0;
  162. }
  163. static Chan*
  164. consattach(char *spec)
  165. {
  166. static int kp;
  167. if(kp == 0 && !dflag) {
  168. kp = 1;
  169. kproc("kbd", kbdslave, 0, 0);
  170. }
  171. return devattach('c', spec);
  172. }
  173. static Walkqid*
  174. conswalk(Chan *c, Chan *nc, char **name, int nname)
  175. {
  176. return devwalk(c, nc, name, nname, contab, nelem(contab), devgen);
  177. }
  178. static int
  179. consstat(Chan *c, uchar *db, int n)
  180. {
  181. return devstat(c, db, n, contab, nelem(contab), devgen);
  182. }
  183. static Chan*
  184. consopen(Chan *c, int omode)
  185. {
  186. c = devopen(c, omode, contab, nelem(contab), devgen);
  187. switch((ulong)c->qid.path) {
  188. case Qconsctl:
  189. incref(&kbd.ctl);
  190. break;
  191. case Qscancode:
  192. qlock(&kbd.gq);
  193. if(gkscanq != nil || gkscanid == nil) {
  194. qunlock(&kbd.q);
  195. c->flag &= ~COPEN;
  196. if(gkscanq)
  197. error(Einuse);
  198. else
  199. error("not supported");
  200. }
  201. gkscanq = qopen(256, 0, nil, nil);
  202. qunlock(&kbd.gq);
  203. break;
  204. case Qkprint:
  205. wlock(&kprintq.l);
  206. if(waserror()){
  207. wunlock(&kprintq.l);
  208. c->flag &= ~COPEN;
  209. nexterror();
  210. }
  211. if(kprintq.q != nil)
  212. error(Einuse);
  213. kprintq.q = qopen(32*1024, Qcoalesce, nil, nil);
  214. if(kprintq.q == nil)
  215. error(Enomem);
  216. qnoblock(kprintq.q, 1);
  217. poperror();
  218. wunlock(&kprintq.l);
  219. c->iounit = qiomaxatomic;
  220. break;
  221. }
  222. return c;
  223. }
  224. static void
  225. consclose(Chan *c)
  226. {
  227. if((c->flag & COPEN) == 0)
  228. return;
  229. switch((ulong)c->qid.path) {
  230. case Qconsctl:
  231. /* last close of control file turns off raw */
  232. if(decref(&kbd.ctl) == 0)
  233. kbd.raw = 0;
  234. break;
  235. case Qscancode:
  236. qlock(&kbd.gq);
  237. if(gkscanq) {
  238. qfree(gkscanq);
  239. gkscanq = nil;
  240. }
  241. qunlock(&kbd.gq);
  242. break;
  243. case Qkprint:
  244. wlock(&kprintq.l);
  245. qfree(kprintq.q);
  246. kprintq.q = nil;
  247. wunlock(&kprintq.l);
  248. break;
  249. }
  250. }
  251. static long
  252. consread(Chan *c, void *va, long n, vlong offset)
  253. {
  254. int send;
  255. char buf[64], ch;
  256. if(c->qid.type & QTDIR)
  257. return devdirread(c, va, n, contab, nelem(contab), devgen);
  258. switch((ulong)c->qid.path) {
  259. default:
  260. error(Egreg);
  261. case Qsysctl:
  262. return readstr(offset, va, n, VERSION);
  263. case Qsysname:
  264. if(ossysname == nil)
  265. return 0;
  266. return readstr(offset, va, n, ossysname);
  267. case Qrandom:
  268. return randomread(va, n);
  269. case Qnotquiterandom:
  270. genrandom(va, n);
  271. return n;
  272. case Qhostowner:
  273. return readstr(offset, va, n, eve);
  274. case Qhoststdin:
  275. return read(0, va, n); /* should be pread */
  276. case Quser:
  277. return readstr(offset, va, n, up->env->user);
  278. case Qjit:
  279. snprint(buf, sizeof(buf), "%d", cflag);
  280. return readstr(offset, va, n, buf);
  281. case Qtime:
  282. snprint(buf, sizeof(buf), "%.lld", timeoffset + osusectime());
  283. return readstr(offset, va, n, buf);
  284. case Qdrivers:
  285. return devtabread(c, va, n, offset);
  286. case Qmemory:
  287. return poolread(va, n, offset);
  288. case Qnull:
  289. return 0;
  290. case Qmsec:
  291. return readnum(offset, va, n, osmillisec(), NUMSIZE);
  292. case Qcons:
  293. qlock(&kbd.q);
  294. if(waserror()){
  295. qunlock(&kbd.q);
  296. nexterror();
  297. }
  298. if(dflag)
  299. error(Enonexist);
  300. while(!qcanread(lineq)) {
  301. if(qread(kbdq, &ch, 1) == 0)
  302. continue;
  303. send = 0;
  304. if(ch == 0){
  305. /* flush output on rawoff -> rawon */
  306. if(kbd.x > 0)
  307. send = !qcanread(kbdq);
  308. }else if(kbd.raw){
  309. kbd.line[kbd.x++] = ch;
  310. send = !qcanread(kbdq);
  311. }else{
  312. switch(ch){
  313. case '\b':
  314. if(kbd.x)
  315. kbd.x--;
  316. break;
  317. case 0x15:
  318. kbd.x = 0;
  319. break;
  320. case 0x04:
  321. send = 1;
  322. break;
  323. case '\n':
  324. send = 1;
  325. default:
  326. kbd.line[kbd.x++] = ch;
  327. break;
  328. }
  329. }
  330. if(send || kbd.x == sizeof kbd.line){
  331. qwrite(lineq, kbd.line, kbd.x);
  332. kbd.x = 0;
  333. }
  334. }
  335. n = qread(lineq, va, n);
  336. qunlock(&kbd.q);
  337. poperror();
  338. return n;
  339. case Qscancode:
  340. if(offset == 0)
  341. return readstr(0, va, n, gkscanid);
  342. return qread(gkscanq, va, n);
  343. case Qkeyboard:
  344. return qread(gkbdq, va, n);
  345. case Qkprint:
  346. rlock(&kprintq.l);
  347. if(waserror()){
  348. runlock(&kprintq.l);
  349. nexterror();
  350. }
  351. n = qread(kprintq.q, va, n);
  352. poperror();
  353. runlock(&kprintq.l);
  354. return n;
  355. }
  356. }
  357. static long
  358. conswrite(Chan *c, void *va, long n, vlong offset)
  359. {
  360. char buf[128], *a, ch;
  361. int x;
  362. if(c->qid.type & QTDIR)
  363. error(Eperm);
  364. switch((ulong)c->qid.path) {
  365. default:
  366. error(Egreg);
  367. case Qcons:
  368. if(canrlock(&kprintq.l)){
  369. if(kprintq.q != nil){
  370. if(waserror()){
  371. runlock(&kprintq.l);
  372. nexterror();
  373. }
  374. qwrite(kprintq.q, va, n);
  375. poperror();
  376. runlock(&kprintq.l);
  377. return n;
  378. }
  379. runlock(&kprintq.l);
  380. }
  381. return write(1, va, n);
  382. case Qsysctl:
  383. return sysconwrite(va, n);
  384. case Qconsctl:
  385. if(n >= sizeof(buf))
  386. n = sizeof(buf)-1;
  387. strncpy(buf, va, n);
  388. buf[n] = 0;
  389. for(a = buf; a;){
  390. if(strncmp(a, "rawon", 5) == 0){
  391. kbd.raw = 1;
  392. /* clumsy hack - wake up reader */
  393. ch = 0;
  394. qwrite(kbdq, &ch, 1);
  395. } else if(strncmp(buf, "rawoff", 6) == 0){
  396. kbd.raw = 0;
  397. }
  398. if((a = strchr(a, ' ')) != nil)
  399. a++;
  400. }
  401. break;
  402. case Qkeyboard:
  403. for(x=0; x<n; ) {
  404. Rune r;
  405. x += chartorune(&r, &((char*)va)[x]);
  406. gkbdputc(gkbdq, r);
  407. }
  408. break;
  409. case Qnull:
  410. break;
  411. case Qtime:
  412. if(n >= sizeof(buf))
  413. n = sizeof(buf)-1;
  414. strncpy(buf, va, n);
  415. buf[n] = '\0';
  416. timeoffset = strtoll(buf, 0, 0)-osusectime();
  417. break;
  418. case Qhostowner:
  419. if(!iseve())
  420. error(Eperm);
  421. if(offset != 0 || n >= sizeof(buf))
  422. error(Ebadarg);
  423. memmove(buf, va, n);
  424. buf[n] = '\0';
  425. if(n > 0 && buf[n-1] == '\n')
  426. buf[--n] = '\0';
  427. if(n == 0)
  428. error(Ebadarg);
  429. /* renameuser(eve, buf); */
  430. /* renameproguser(eve, buf); */
  431. kstrdup(&eve, buf);
  432. kstrdup(&up->env->user, buf);
  433. break;
  434. case Quser:
  435. if(!iseve())
  436. error(Eperm);
  437. if(offset != 0)
  438. error(Ebadarg);
  439. if(n <= 0 || n >= sizeof(buf))
  440. error(Ebadarg);
  441. strncpy(buf, va, n);
  442. buf[n] = '\0';
  443. if(n > 0 && buf[n-1] == '\n')
  444. buf[--n] = '\0';
  445. if(n == 0)
  446. error(Ebadarg);
  447. setid(buf, 0);
  448. break;
  449. case Qhoststdout:
  450. return write(1, va, n);
  451. case Qhoststderr:
  452. return write(2, va, n);
  453. case Qjit:
  454. if(n >= sizeof(buf))
  455. n = sizeof(buf)-1;
  456. strncpy(buf, va, n);
  457. buf[n] = '\0';
  458. x = atoi(buf);
  459. if(x < 0 || x > 9)
  460. error(Ebadarg);
  461. cflag = x;
  462. break;
  463. case Qsysname:
  464. if(offset != 0)
  465. error(Ebadarg);
  466. if(n < 0 || n >= sizeof(buf))
  467. error(Ebadarg);
  468. strncpy(buf, va, n);
  469. buf[n] = '\0';
  470. if(buf[n-1] == '\n')
  471. buf[n-1] = 0;
  472. kstrdup(&ossysname, buf);
  473. break;
  474. }
  475. return n;
  476. }
  477. static int
  478. sysconwrite(void *va, ulong count)
  479. {
  480. Cmdbuf *cb;
  481. int e;
  482. cb = parsecmd(va, count);
  483. if(waserror()){
  484. free(cb);
  485. nexterror();
  486. }
  487. if(cb->nf == 0)
  488. error(Enoctl);
  489. if(strcmp(cb->f[0], "reboot") == 0){
  490. osreboot(rebootargv[0], rebootargv);
  491. error("reboot not supported");
  492. }else if(strcmp(cb->f[0], "halt") == 0){
  493. if(cb->nf > 1)
  494. e = atoi(cb->f[1]);
  495. else
  496. e = 0;
  497. cleanexit(e); /* XXX ignored for the time being (and should be a string anyway) */
  498. }else if(strcmp(cb->f[0], "broken") == 0)
  499. keepbroken = 1;
  500. else if(strcmp(cb->f[0], "nobroken") == 0)
  501. keepbroken = 0;
  502. else if(strcmp(cb->f[0], "exdebug") == 0)
  503. exdebug = !exdebug;
  504. else
  505. error(Enoctl);
  506. poperror();
  507. free(cb);
  508. return count;
  509. }
  510. Dev consdevtab = {
  511. 'c',
  512. "cons",
  513. consinit,
  514. consattach,
  515. conswalk,
  516. consstat,
  517. consopen,
  518. devcreate,
  519. consclose,
  520. consread,
  521. devbread,
  522. conswrite,
  523. devbwrite,
  524. devremove,
  525. devwstat
  526. };
  527. static ulong randn;
  528. static void
  529. seedrand(void)
  530. {
  531. randomread((void*)&randn, sizeof(randn));
  532. }
  533. int
  534. nrand(int n)
  535. {
  536. if(randn == 0)
  537. seedrand();
  538. randn = randn*1103515245 + 12345 + osusectime();
  539. return (randn>>16) % n;
  540. }
  541. int
  542. rand(void)
  543. {
  544. nrand(1);
  545. return randn;
  546. }
  547. ulong
  548. truerand(void)
  549. {
  550. ulong x;
  551. randomread(&x, sizeof(x));
  552. return x;
  553. }
  554. QLock grandomlk;
  555. void
  556. _genrandomqlock(void)
  557. {
  558. qlock(&grandomlk);
  559. }
  560. void
  561. _genrandomqunlock(void)
  562. {
  563. qunlock(&grandomlk);
  564. }