TTY.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. #include "TTY.h"
  2. #include "Process.h"
  3. #include <LibC/errno_numbers.h>
  4. #include <LibC/signal_numbers.h>
  5. #include <LibC/sys/ioctl_numbers.h>
  6. //#define TTY_DEBUG
  7. TTY::TTY(unsigned major, unsigned minor)
  8. : CharacterDevice(major, minor)
  9. {
  10. set_default_termios();
  11. }
  12. TTY::~TTY()
  13. {
  14. }
  15. void TTY::set_default_termios()
  16. {
  17. memset(&m_termios, 0, sizeof(m_termios));
  18. m_termios.c_lflag |= ISIG | ECHO;
  19. static const char default_cc[32] = "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0";
  20. memcpy(m_termios.c_cc, default_cc, sizeof(default_cc));
  21. }
  22. ssize_t TTY::read(Process&, byte* buffer, size_t size)
  23. {
  24. return m_buffer.read(buffer, size);
  25. }
  26. ssize_t TTY::write(Process&, const byte* buffer, size_t size)
  27. {
  28. #ifdef TTY_DEBUG
  29. dbgprintf("TTY::write {%u} ", size);
  30. for (size_t i = 0; i < size; ++i) {
  31. dbgprintf("%b ", buffer[i]);
  32. }
  33. dbgprintf("\n");
  34. #endif
  35. on_tty_write(buffer, size);
  36. return size;
  37. }
  38. bool TTY::can_read(Process&) const
  39. {
  40. return !m_buffer.is_empty();
  41. }
  42. bool TTY::can_write(Process&) const
  43. {
  44. return true;
  45. }
  46. void TTY::emit(byte ch)
  47. {
  48. if (should_generate_signals()) {
  49. if (ch == m_termios.c_cc[VINTR]) {
  50. dbgprintf("%s: VINTR pressed!\n", tty_name().characters());
  51. generate_signal(SIGINT);
  52. return;
  53. }
  54. if (ch == m_termios.c_cc[VQUIT]) {
  55. dbgprintf("%s: VQUIT pressed!\n", tty_name().characters());
  56. generate_signal(SIGQUIT);
  57. return;
  58. }
  59. }
  60. m_buffer.write(&ch, 1);
  61. }
  62. void TTY::generate_signal(int signal)
  63. {
  64. if (!pgid())
  65. return;
  66. dbgprintf("%s: Send signal %d to everyone in pgrp %d\n", tty_name().characters(), signal, pgid());
  67. InterruptDisabler disabler; // FIXME: Iterate over a set of process handles instead?
  68. Process::for_each_in_pgrp(pgid(), [&] (auto& process) {
  69. dbgprintf("%s: Send signal %d to %d\n", tty_name().characters(), signal, process.pid());
  70. process.send_signal(signal, nullptr);
  71. return true;
  72. });
  73. }
  74. void TTY::set_termios(const termios& t)
  75. {
  76. m_termios = t;
  77. dbgprintf("%s set_termios: ECHO=%u, ISIG=%u, ICANON=%u\n",
  78. tty_name().characters(),
  79. should_echo_input(),
  80. should_generate_signals(),
  81. in_canonical_mode()
  82. );
  83. dbgprintf("%s set_termios: ECHOE=%u, ECHOK=%u, ECHONL=%u\n",
  84. tty_name().characters(),
  85. (m_termios.c_lflag & ECHOE) != 0,
  86. (m_termios.c_lflag & ECHOK) != 0,
  87. (m_termios.c_lflag & ECHONL) != 0
  88. );
  89. dbgprintf("%s set_termios: ISTRIP=%u, ICRNL=%u, INLCR=%u, IGNCR=%u\n",
  90. tty_name().characters(),
  91. (m_termios.c_iflag & ISTRIP) != 0,
  92. (m_termios.c_iflag & ICRNL) != 0,
  93. (m_termios.c_iflag & INLCR) != 0,
  94. (m_termios.c_iflag & IGNCR) != 0
  95. );
  96. }
  97. int TTY::ioctl(Process& process, unsigned request, unsigned arg)
  98. {
  99. pid_t pgid;
  100. termios* tp;
  101. winsize* ws;
  102. #if 0
  103. // FIXME: When should we block things?
  104. // How do we make this work together with MasterPTY forwarding to us?
  105. if (process.tty() && process.tty() != this) {
  106. return -ENOTTY;
  107. }
  108. #endif
  109. switch (request) {
  110. case TIOCGPGRP:
  111. return m_pgid;
  112. case TIOCSPGRP:
  113. // FIXME: Validate pgid fully.
  114. pgid = static_cast<pid_t>(arg);
  115. if (pgid < 0)
  116. return -EINVAL;
  117. m_pgid = pgid;
  118. return 0;
  119. case TCGETS:
  120. tp = reinterpret_cast<termios*>(arg);
  121. if (!process.validate_write(tp, sizeof(termios)))
  122. return -EFAULT;
  123. *tp = m_termios;
  124. return 0;
  125. case TCSETS:
  126. case TCSETSF:
  127. case TCSETSW:
  128. tp = reinterpret_cast<termios*>(arg);
  129. if (!process.validate_read(tp, sizeof(termios)))
  130. return -EFAULT;
  131. set_termios(*tp);
  132. return 0;
  133. case TIOCGWINSZ:
  134. ws = reinterpret_cast<winsize*>(arg);
  135. if (!process.validate_write(ws, sizeof(winsize)))
  136. return -EFAULT;
  137. ws->ws_row = m_rows;
  138. ws->ws_col = m_columns;
  139. return 0;
  140. case TIOCSWINSZ:
  141. ws = reinterpret_cast<winsize*>(arg);
  142. if (!process.validate_read(ws, sizeof(winsize)))
  143. return -EFAULT;
  144. if (ws->ws_col == m_columns && ws->ws_row == m_rows)
  145. return 0;
  146. m_rows = ws->ws_row;
  147. m_columns = ws->ws_col;
  148. generate_signal(SIGWINCH);
  149. return 0;
  150. case TIOCSCTTY:
  151. process.set_tty(this);
  152. return 0;
  153. case TIOCNOTTY:
  154. process.set_tty(nullptr);
  155. return 0;
  156. }
  157. ASSERT_NOT_REACHED();
  158. return -EINVAL;
  159. }
  160. void TTY::set_size(unsigned short columns, unsigned short rows)
  161. {
  162. m_rows = rows;
  163. m_columns = columns;
  164. }
  165. void TTY::hang_up()
  166. {
  167. generate_signal(SIGHUP);
  168. }