tty.c 17 KB

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