tty.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2013-2018 K. Lange
  5. */
  6. #include <kernel/system.h>
  7. #include <kernel/fs.h>
  8. #include <kernel/pipe.h>
  9. #include <kernel/logging.h>
  10. #include <kernel/printf.h>
  11. #include <kernel/ringbuffer.h>
  12. #include <kernel/pty.h>
  13. #include <toaru/hashmap.h>
  14. #include <sys/ioctl.h>
  15. #include <sys/termios.h>
  16. #define TTY_BUFFER_SIZE 4096
  17. static int _pty_counter = 0;
  18. static hashmap_t * _pty_index = NULL;
  19. static fs_node_t * _pty_dir = NULL;
  20. static fs_node_t * _dev_tty = NULL;
  21. static void pty_write_in(pty_t * pty, uint8_t c) {
  22. ring_buffer_write(pty->in, 1, &c);
  23. }
  24. static void pty_write_out(pty_t * pty, uint8_t c) {
  25. ring_buffer_write(pty->out, 1, &c);
  26. }
  27. #define IN(character) pty->write_in(pty, (uint8_t)character)
  28. #define OUT(character) pty->write_out(pty, (uint8_t)character)
  29. static void dump_input_buffer(pty_t * pty) {
  30. char * c = pty->canon_buffer;
  31. while (pty->canon_buflen > 0) {
  32. IN(*c);
  33. pty->canon_buflen--;
  34. c++;
  35. }
  36. }
  37. static void clear_input_buffer(pty_t * pty) {
  38. pty->canon_buflen = 0;
  39. pty->canon_buffer[0] = '\0';
  40. }
  41. #define output_process_slave tty_output_process_slave
  42. #define output_process tty_output_process
  43. #define input_process tty_input_process
  44. void tty_output_process_slave(pty_t * pty, uint8_t c) {
  45. if (c == '\n' && (pty->tios.c_oflag & ONLCR)) {
  46. c = '\n';
  47. OUT(c);
  48. c = '\r';
  49. OUT(c);
  50. return;
  51. }
  52. if (c == '\r' && (pty->tios.c_oflag & ONLRET)) {
  53. return;
  54. }
  55. if (c >= 'a' && c <= 'z' && (pty->tios.c_oflag & OLCUC)) {
  56. c = c + 'a' - 'A';
  57. OUT(c);
  58. return;
  59. }
  60. OUT(c);
  61. }
  62. void tty_output_process(pty_t * pty, uint8_t c) {
  63. if (ring_buffer_available(pty->out) < 2) return; /* uh oh */
  64. output_process_slave(pty, c);
  65. }
  66. static int is_control(int c) {
  67. return c < ' ' || c == 0x7F;
  68. }
  69. static void erase_one(pty_t * pty, int erase) {
  70. if (pty->canon_buflen > 0) {
  71. /* How many do we backspace? */
  72. int vwidth = 1;
  73. pty->canon_buflen--;
  74. if (is_control(pty->canon_buffer[pty->canon_buflen])) {
  75. /* Erase ^@ */
  76. vwidth = 2;
  77. }
  78. pty->canon_buffer[pty->canon_buflen] = '\0';
  79. if (pty->tios.c_lflag & ECHO) {
  80. if (erase) {
  81. for (int i = 0; i < vwidth; ++i) {
  82. output_process(pty, '\010');
  83. output_process(pty, ' ');
  84. output_process(pty, '\010');
  85. }
  86. }
  87. }
  88. }
  89. }
  90. void tty_input_process(pty_t * pty, uint8_t c) {
  91. if (pty->next_is_verbatim) {
  92. pty->next_is_verbatim = 0;
  93. if (pty->canon_buflen < pty->canon_bufsize) {
  94. pty->canon_buffer[pty->canon_buflen] = c;
  95. pty->canon_buflen++;
  96. }
  97. if (pty->tios.c_lflag & ECHO) {
  98. if (is_control(c)) {
  99. output_process(pty, '^');
  100. output_process(pty, ('@'+c) % 128);
  101. } else {
  102. output_process(pty, c);
  103. }
  104. }
  105. return;
  106. }
  107. if (pty->tios.c_lflag & ISIG) {
  108. int sig = -1;
  109. if (c == pty->tios.c_cc[VINTR]) {
  110. sig = SIGINT;
  111. } else if (c == pty->tios.c_cc[VQUIT]) {
  112. sig = SIGQUIT;
  113. } else if (c == pty->tios.c_cc[VSUSP]) {
  114. sig = SIGTSTP;
  115. }
  116. /* VSUSP */
  117. if (sig != -1) {
  118. if (pty->tios.c_lflag & ECHO) {
  119. output_process(pty, '^');
  120. output_process(pty, ('@' + c) % 128);
  121. output_process(pty, '\n');
  122. }
  123. clear_input_buffer(pty);
  124. if (pty->fg_proc) {
  125. group_send_signal(pty->fg_proc, sig, 1);
  126. }
  127. return;
  128. }
  129. }
  130. #if 0
  131. if (pty->tios.c_lflag & IXON ) {
  132. /* VSTOP, VSTART */
  133. }
  134. #endif
  135. /* ISTRIP: Strip eighth bit */
  136. if (pty->tios.c_iflag & ISTRIP) {
  137. c &= 0x7F;
  138. }
  139. /* IGNCR: Ignore carriage return. */
  140. if ((pty->tios.c_iflag & IGNCR) && c == '\r') {
  141. return;
  142. }
  143. if ((pty->tios.c_iflag & INLCR) && c == '\n') {
  144. /* INLCR: Translate NL to CR. */
  145. c = '\r';
  146. } else if ((pty->tios.c_iflag & ICRNL) && c == '\r') {
  147. /* ICRNL: Convert carriage return. */
  148. c = '\n';
  149. }
  150. if (pty->tios.c_lflag & ICANON) {
  151. if (c == pty->tios.c_cc[VLNEXT] && (pty->tios.c_lflag & IEXTEN)) {
  152. pty->next_is_verbatim = 1;
  153. output_process(pty, '^');
  154. output_process(pty, '\010');
  155. return;
  156. }
  157. if (c == pty->tios.c_cc[VKILL]) {
  158. while (pty->canon_buflen > 0) {
  159. erase_one(pty, pty->tios.c_lflag & ECHOK);
  160. }
  161. if ((pty->tios.c_lflag & ECHO) && ! (pty->tios.c_lflag & ECHOK)) {
  162. output_process(pty, '^');
  163. output_process(pty, ('@' + c) % 128);
  164. }
  165. return;
  166. }
  167. if (c == pty->tios.c_cc[VERASE]) {
  168. /* Backspace */
  169. erase_one(pty, pty->tios.c_lflag & ECHOE);
  170. if ((pty->tios.c_lflag & ECHO) && ! (pty->tios.c_lflag & ECHOE)) {
  171. output_process(pty, '^');
  172. output_process(pty, ('@' + c) % 128);
  173. }
  174. return;
  175. }
  176. if (c == pty->tios.c_cc[VWERASE] && (pty->tios.c_lflag & IEXTEN)) {
  177. while (pty->canon_buflen && pty->canon_buffer[pty->canon_buflen-1] == ' ') {
  178. erase_one(pty, pty->tios.c_lflag & ECHOE);
  179. }
  180. while (pty->canon_buflen && pty->canon_buffer[pty->canon_buflen-1] != ' ') {
  181. erase_one(pty, pty->tios.c_lflag & ECHOE);
  182. }
  183. if ((pty->tios.c_lflag & ECHO) && ! (pty->tios.c_lflag & ECHOE)) {
  184. output_process(pty, '^');
  185. output_process(pty, ('@' + c) % 128);
  186. }
  187. return;
  188. }
  189. if (c == pty->tios.c_cc[VEOF]) {
  190. if (pty->canon_buflen) {
  191. dump_input_buffer(pty);
  192. } else {
  193. ring_buffer_interrupt(pty->in);
  194. }
  195. return;
  196. }
  197. if (pty->canon_buflen < pty->canon_bufsize) {
  198. pty->canon_buffer[pty->canon_buflen] = c;
  199. pty->canon_buflen++;
  200. }
  201. if (pty->tios.c_lflag & ECHO) {
  202. if (is_control(c) && c != '\n') {
  203. output_process(pty, '^');
  204. output_process(pty, ('@' + c) % 128);
  205. } else {
  206. output_process(pty, c);
  207. }
  208. }
  209. if (c == '\n' || (pty->tios.c_cc[VEOL] && c == pty->tios.c_cc[VEOL])) {
  210. if (!(pty->tios.c_lflag & ECHO) && (pty->tios.c_lflag & ECHONL)) {
  211. output_process(pty, c);
  212. }
  213. pty->canon_buffer[pty->canon_buflen-1] = c;
  214. dump_input_buffer(pty);
  215. return;
  216. }
  217. return;
  218. } else if (pty->tios.c_lflag & ECHO) {
  219. output_process(pty, c);
  220. }
  221. IN(c);
  222. }
  223. int pty_ioctl(pty_t * pty, int request, void * argp) {
  224. switch (request) {
  225. case IOCTLDTYPE:
  226. /*
  227. * This is a special toaru-specific call to get a simple
  228. * integer that describes the kind of device this is.
  229. * It's more specific than just "character device" or "file",
  230. * but for here we just need to say we're a TTY.
  231. */
  232. return IOCTL_DTYPE_TTY;
  233. case IOCTLTTYNAME:
  234. if (!argp) return -EINVAL;
  235. validate(argp);
  236. ((char*)argp)[0] = '\0';
  237. sprintf((char*)argp, "/dev/pts/%d", pty->name);
  238. return 0;
  239. case IOCTLTTYLOGIN:
  240. /* Set the user id of the login user */
  241. if (current_process->user != 0) return -EPERM;
  242. if (!argp) return -EINVAL;
  243. validate(argp);
  244. pty->slave->uid = *(int*)argp;
  245. pty->master->uid = *(int*)argp;
  246. return 0;
  247. case TIOCSWINSZ:
  248. if (!argp) return -EINVAL;
  249. validate(argp);
  250. memcpy(&pty->size, argp, sizeof(struct winsize));
  251. group_send_signal(pty->fg_proc, SIGWINCH, 1);
  252. return 0;
  253. case TIOCGWINSZ:
  254. if (!argp) return -EINVAL;
  255. validate(argp);
  256. memcpy(argp, &pty->size, sizeof(struct winsize));
  257. return 0;
  258. case TCGETS:
  259. if (!argp) return -EINVAL;
  260. validate(argp);
  261. memcpy(argp, &pty->tios, sizeof(struct termios));
  262. return 0;
  263. case TIOCSPGRP:
  264. if (!argp) return -EINVAL;
  265. validate(argp);
  266. pty->fg_proc = *(pid_t *)argp;
  267. debug_print(NOTICE, "Setting PTY group to %d", pty->fg_proc);
  268. return 0;
  269. case TIOCGPGRP:
  270. if (!argp) return -EINVAL;
  271. validate(argp);
  272. *(pid_t *)argp = pty->fg_proc;
  273. return 0;
  274. case TCSETS:
  275. case TCSETSW:
  276. case TCSETSF:
  277. if (!argp) return -EINVAL;
  278. validate(argp);
  279. if (!(((struct termios *)argp)->c_lflag & ICANON) && (pty->tios.c_lflag & ICANON)) {
  280. /* Switch out of canonical mode, the dump the input buffer */
  281. dump_input_buffer(pty);
  282. }
  283. memcpy(&pty->tios, argp, sizeof(struct termios));
  284. return 0;
  285. default:
  286. return -EINVAL;
  287. }
  288. }
  289. uint32_t read_pty_master(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) {
  290. pty_t * pty = (pty_t *)node->device;
  291. /* Standard pipe read */
  292. return ring_buffer_read(pty->out, size, buffer);
  293. }
  294. uint32_t write_pty_master(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) {
  295. pty_t * pty = (pty_t *)node->device;
  296. size_t l = 0;
  297. for (uint8_t * c = buffer; l < size; ++c, ++l) {
  298. input_process(pty, *c);
  299. }
  300. return l;
  301. }
  302. void open_pty_master(fs_node_t * node, unsigned int flags) {
  303. return;
  304. }
  305. void close_pty_master(fs_node_t * node) {
  306. return;
  307. }
  308. uint32_t read_pty_slave(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) {
  309. pty_t * pty = (pty_t *)node->device;
  310. if (pty->tios.c_lflag & ICANON) {
  311. return ring_buffer_read(pty->in, size, buffer);
  312. } else {
  313. if (pty->tios.c_cc[VMIN] == 0) {
  314. return ring_buffer_read(pty->in, MIN(size, ring_buffer_unread(pty->in)), buffer);
  315. } else {
  316. return ring_buffer_read(pty->in, MIN(pty->tios.c_cc[VMIN], size), buffer);
  317. }
  318. }
  319. }
  320. uint32_t write_pty_slave(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) {
  321. pty_t * pty = (pty_t *)node->device;
  322. size_t l = 0;
  323. for (uint8_t * c = buffer; l < size; ++c, ++l) {
  324. output_process_slave(pty, *c);
  325. }
  326. return l;
  327. }
  328. void open_pty_slave(fs_node_t * node, unsigned int flags) {
  329. return;
  330. }
  331. void close_pty_slave(fs_node_t * node) {
  332. pty_t * pty = (pty_t *)node->device;
  333. hashmap_remove(_pty_index, (void*)pty->name);
  334. return;
  335. }
  336. /*
  337. * These are separate functions just in case I ever feel the need to do
  338. * things differently in the slave or master.
  339. */
  340. int ioctl_pty_master(fs_node_t * node, int request, void * argp) {
  341. pty_t * pty = (pty_t *)node->device;
  342. return pty_ioctl(pty, request, argp);
  343. }
  344. int ioctl_pty_slave(fs_node_t * node, int request, void * argp) {
  345. pty_t * pty = (pty_t *)node->device;
  346. return pty_ioctl(pty, request, argp);
  347. }
  348. int pty_available_input(fs_node_t * node) {
  349. pty_t * pty = (pty_t *)node->device;
  350. return ring_buffer_unread(pty->in);
  351. }
  352. int pty_available_output(fs_node_t * node) {
  353. pty_t * pty = (pty_t *)node->device;
  354. return ring_buffer_unread(pty->out);
  355. }
  356. static int check_pty_master(fs_node_t * node) {
  357. pty_t * pty = (pty_t *)node->device;
  358. if (ring_buffer_unread(pty->out) > 0) {
  359. return 0;
  360. }
  361. return 1;
  362. }
  363. static int check_pty_slave(fs_node_t * node) {
  364. pty_t * pty = (pty_t *)node->device;
  365. if (ring_buffer_unread(pty->in) > 0) {
  366. return 0;
  367. }
  368. return 1;
  369. }
  370. static int wait_pty_master(fs_node_t * node, void * process) {
  371. pty_t * pty = (pty_t *)node->device;
  372. ring_buffer_select_wait(pty->out, process);
  373. return 0;
  374. }
  375. static int wait_pty_slave(fs_node_t * node, void * process) {
  376. pty_t * pty = (pty_t *)node->device;
  377. ring_buffer_select_wait(pty->in, process);
  378. return 0;
  379. }
  380. fs_node_t * pty_master_create(pty_t * pty) {
  381. fs_node_t * fnode = malloc(sizeof(fs_node_t));
  382. memset(fnode, 0x00, sizeof(fs_node_t));
  383. fnode->name[0] = '\0';
  384. sprintf(fnode->name, "pty master");
  385. fnode->uid = current_process->user;
  386. fnode->gid = 0;
  387. fnode->mask = 0666;
  388. fnode->flags = FS_PIPE;
  389. fnode->read = read_pty_master;
  390. fnode->write = write_pty_master;
  391. fnode->open = open_pty_master;
  392. fnode->close = close_pty_master;
  393. fnode->selectcheck = check_pty_master;
  394. fnode->selectwait = wait_pty_master;
  395. fnode->readdir = NULL;
  396. fnode->finddir = NULL;
  397. fnode->ioctl = ioctl_pty_master;
  398. fnode->get_size = pty_available_output;
  399. fnode->ctime = now();
  400. fnode->mtime = now();
  401. fnode->atime = now();
  402. fnode->device = pty;
  403. return fnode;
  404. }
  405. fs_node_t * pty_slave_create(pty_t * pty) {
  406. fs_node_t * fnode = malloc(sizeof(fs_node_t));
  407. memset(fnode, 0x00, sizeof(fs_node_t));
  408. fnode->name[0] = '\0';
  409. sprintf(fnode->name, "pty slave");
  410. fnode->uid = current_process->user;
  411. fnode->gid = 0;
  412. fnode->mask = 0666;
  413. fnode->flags = FS_PIPE;
  414. fnode->read = read_pty_slave;
  415. fnode->write = write_pty_slave;
  416. fnode->open = open_pty_slave;
  417. fnode->close = close_pty_slave;
  418. fnode->selectcheck = check_pty_slave;
  419. fnode->selectwait = wait_pty_slave;
  420. fnode->readdir = NULL;
  421. fnode->finddir = NULL;
  422. fnode->ioctl = ioctl_pty_slave;
  423. fnode->get_size = pty_available_input;
  424. fnode->ctime = now();
  425. fnode->mtime = now();
  426. fnode->atime = now();
  427. fnode->device = pty;
  428. return fnode;
  429. }
  430. static int isatty(fs_node_t * node) {
  431. if (!node) return 0;
  432. if (!node->ioctl) return 0;
  433. return ioctl_fs(node, IOCTLDTYPE, NULL) == IOCTL_DTYPE_TTY;
  434. }
  435. static int readlink_dev_tty(fs_node_t * node, char * buf, size_t size) {
  436. pty_t * pty = NULL;
  437. for (unsigned int i = 0; i < ((current_process->fds->length < 3) ? current_process->fds->length : 3); ++i) {
  438. if (isatty(current_process->fds->entries[i])) {
  439. pty = (pty_t *)current_process->fds->entries[i]->device;
  440. break;
  441. }
  442. }
  443. char tmp[30];
  444. size_t req;
  445. if (!pty) {
  446. sprintf(tmp, "/dev/null");
  447. } else {
  448. sprintf(tmp, "/dev/pts/%d", pty->name);
  449. }
  450. req = strlen(tmp) + 1;
  451. if (size < req) {
  452. memcpy(buf, tmp, size);
  453. buf[size-1] = '\0';
  454. return size-1;
  455. }
  456. if (size > req) size = req;
  457. memcpy(buf, tmp, size);
  458. return size-1;
  459. }
  460. static fs_node_t * create_dev_tty(void) {
  461. fs_node_t * fnode = malloc(sizeof(fs_node_t));
  462. memset(fnode, 0x00, sizeof(fs_node_t));
  463. fnode->inode = 0;
  464. strcpy(fnode->name, "tty");
  465. fnode->mask = 0777;
  466. fnode->uid = 0;
  467. fnode->gid = 0;
  468. fnode->flags = FS_FILE | FS_SYMLINK;
  469. fnode->readlink = readlink_dev_tty;
  470. fnode->length = 1;
  471. fnode->nlink = 1;
  472. fnode->ctime = now();
  473. fnode->mtime = now();
  474. fnode->atime = now();
  475. return fnode;
  476. }
  477. static struct dirent * readdir_pty(fs_node_t *node, uint32_t index) {
  478. if (index == 0) {
  479. struct dirent * out = malloc(sizeof(struct dirent));
  480. memset(out, 0x00, sizeof(struct dirent));
  481. out->ino = 0;
  482. strcpy(out->name, ".");
  483. return out;
  484. }
  485. if (index == 1) {
  486. struct dirent * out = malloc(sizeof(struct dirent));
  487. memset(out, 0x00, sizeof(struct dirent));
  488. out->ino = 0;
  489. strcpy(out->name, "..");
  490. return out;
  491. }
  492. index -= 2;
  493. pty_t * out_pty = NULL;
  494. list_t * values = hashmap_values(_pty_index);
  495. foreach(node, values) {
  496. if (index == 0) {
  497. out_pty = node->value;
  498. break;
  499. }
  500. index--;
  501. }
  502. list_free(values);
  503. if (out_pty) {
  504. struct dirent * out = malloc(sizeof(struct dirent));
  505. memset(out, 0x00, sizeof(struct dirent));
  506. out->ino = out_pty->name;
  507. out->name[0] = '\0';
  508. sprintf(out->name, "%d", out_pty->name);
  509. return out;
  510. } else {
  511. return NULL;
  512. }
  513. }
  514. static fs_node_t * finddir_pty(fs_node_t * node, char * name) {
  515. if (!name) return NULL;
  516. if (strlen(name) < 1) return NULL;
  517. int c = 0;
  518. for (int i = 0; name[i]; ++i) {
  519. if (name[i] < '0' || name[i] > '9') {
  520. return NULL;
  521. }
  522. c = c * 10 + name[i] - '0';
  523. }
  524. pty_t * _pty = hashmap_get(_pty_index, (void*)c);
  525. if (!_pty) {
  526. debug_print(ERROR, "Invalid PTY number: %d\n", c);
  527. return NULL;
  528. }
  529. return _pty->slave;
  530. }
  531. static fs_node_t * create_pty_dir(void) {
  532. fs_node_t * fnode = malloc(sizeof(fs_node_t));
  533. memset(fnode, 0x00, sizeof(fs_node_t));
  534. fnode->inode = 0;
  535. strcpy(fnode->name, "pty");
  536. fnode->mask = 0555;
  537. fnode->uid = 0;
  538. fnode->gid = 0;
  539. fnode->flags = FS_DIRECTORY;
  540. fnode->read = NULL;
  541. fnode->write = NULL;
  542. fnode->open = NULL;
  543. fnode->close = NULL;
  544. fnode->readdir = readdir_pty;
  545. fnode->finddir = finddir_pty;
  546. fnode->nlink = 1;
  547. fnode->ctime = now();
  548. fnode->mtime = now();
  549. fnode->atime = now();
  550. return fnode;
  551. }
  552. void pty_install(void) {
  553. _pty_index = hashmap_create_int(10);
  554. _pty_dir = create_pty_dir();
  555. _dev_tty = create_dev_tty();
  556. vfs_mount("/dev/pts", _pty_dir);
  557. vfs_mount("/dev/tty", _dev_tty);
  558. }
  559. pty_t * pty_new(struct winsize * size) {
  560. if (!_pty_index) {
  561. pty_install();
  562. }
  563. pty_t * pty = malloc(sizeof(pty_t));
  564. pty->next_is_verbatim = 0;
  565. /* stdin linkage; characters from terminal → PTY slave */
  566. pty->in = ring_buffer_create(TTY_BUFFER_SIZE);
  567. pty->out = ring_buffer_create(TTY_BUFFER_SIZE);
  568. pty->in->discard = 1;
  569. /* Master endpoint - writes go to stdin, reads come from stdout */
  570. pty->master = pty_master_create(pty);
  571. /* Slave endpoint, reads come from stdin, writes go to stdout */
  572. pty->slave = pty_slave_create(pty);
  573. /* tty name */
  574. pty->name = _pty_counter++;
  575. pty->write_in = pty_write_in;
  576. pty->write_out = pty_write_out;
  577. hashmap_set(_pty_index, (void*)pty->name, pty);
  578. if (size) {
  579. memcpy(&pty->size, size, sizeof(struct winsize));
  580. } else {
  581. /* Sane defaults */
  582. pty->size.ws_row = 25;
  583. pty->size.ws_col = 80;
  584. }
  585. /* Controlling and foreground processes are set to 0 by default */
  586. pty->ct_proc = 0;
  587. pty->fg_proc = 0;
  588. pty->tios.c_iflag = ICRNL | BRKINT;
  589. pty->tios.c_oflag = ONLCR | OPOST;
  590. pty->tios.c_lflag = ECHO | ECHOE | ECHOK | ICANON | ISIG | IEXTEN;
  591. pty->tios.c_cflag = CREAD | CS8;
  592. pty->tios.c_cc[VEOF] = 4; /* ^D */
  593. pty->tios.c_cc[VEOL] = 0; /* Not set */
  594. pty->tios.c_cc[VERASE] = 0x7f; /* ^? */
  595. pty->tios.c_cc[VINTR] = 3; /* ^C */
  596. pty->tios.c_cc[VKILL] = 21; /* ^U */
  597. pty->tios.c_cc[VMIN] = 1;
  598. pty->tios.c_cc[VQUIT] = 28; /* ^\ */
  599. pty->tios.c_cc[VSTART] = 17; /* ^Q */
  600. pty->tios.c_cc[VSTOP] = 19; /* ^S */
  601. pty->tios.c_cc[VSUSP] = 26; /* ^Z */
  602. pty->tios.c_cc[VTIME] = 0;
  603. pty->tios.c_cc[VLNEXT] = 22; /* ^V */
  604. pty->tios.c_cc[VWERASE] = 23; /* ^W */
  605. pty->canon_buffer = malloc(TTY_BUFFER_SIZE);
  606. pty->canon_bufsize = TTY_BUFFER_SIZE-2;
  607. pty->canon_buflen = 0;
  608. return pty;
  609. }
  610. int pty_create(void *size, fs_node_t ** fs_master, fs_node_t ** fs_slave) {
  611. pty_t * pty = pty_new(size);
  612. *fs_master = pty->master;
  613. *fs_slave = pty->slave;
  614. return 0;
  615. }