TTY.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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(byte* buffer, size_t size)
  23. {
  24. return m_buffer.read(buffer, size);
  25. }
  26. ssize_t TTY::write(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::has_data_available_for_reading(Process&) const
  39. {
  40. return !m_buffer.is_empty();
  41. }
  42. void TTY::emit(byte ch)
  43. {
  44. if (should_generate_signals()) {
  45. if (ch == m_termios.c_cc[VINTR]) {
  46. dbgprintf("%s: VINTR pressed!\n", tty_name().characters());
  47. generate_signal(SIGINT);
  48. return;
  49. }
  50. if (ch == m_termios.c_cc[VQUIT]) {
  51. dbgprintf("%s: VQUIT pressed!\n", tty_name().characters());
  52. generate_signal(SIGQUIT);
  53. return;
  54. }
  55. }
  56. m_buffer.write(&ch, 1);
  57. }
  58. void TTY::generate_signal(int signal)
  59. {
  60. if (!pgid())
  61. return;
  62. dbgprintf("%s: Send signal %d to everyone in pgrp %d\n", tty_name().characters(), signal, pgid());
  63. InterruptDisabler disabler; // FIXME: Iterate over a set of process handles instead?
  64. Process::for_each_in_pgrp(pgid(), [&] (auto& process) {
  65. dbgprintf("%s: Send signal %d to %d\n", tty_name().characters(), signal, process.pid());
  66. process.send_signal(signal, nullptr);
  67. return true;
  68. });
  69. }
  70. void TTY::set_termios(const Unix::termios& t)
  71. {
  72. m_termios = t;
  73. dbgprintf("%s set_termios: ECHO=%u, ISIG=%u, ICANON=%u\n",
  74. tty_name().characters(),
  75. should_echo_input(),
  76. should_generate_signals(),
  77. in_canonical_mode()
  78. );
  79. dbgprintf("%s set_termios: ECHOE=%u, ECHOK=%u, ECHONL=%u\n",
  80. tty_name().characters(),
  81. (m_termios.c_lflag & ECHOE) != 0,
  82. (m_termios.c_lflag & ECHOK) != 0,
  83. (m_termios.c_lflag & ECHONL) != 0
  84. );
  85. dbgprintf("%s set_termios: ISTRIP=%u, ICRNL=%u, INLCR=%u, IGNCR=%u\n",
  86. tty_name().characters(),
  87. (m_termios.c_iflag & ISTRIP) != 0,
  88. (m_termios.c_iflag & ICRNL) != 0,
  89. (m_termios.c_iflag & INLCR) != 0,
  90. (m_termios.c_iflag & IGNCR) != 0
  91. );
  92. }
  93. int TTY::ioctl(Process& process, unsigned request, unsigned arg)
  94. {
  95. pid_t pgid;
  96. Unix::termios* tp;
  97. Unix::winsize* ws;
  98. if (process.tty() && process.tty() != this)
  99. return -ENOTTY;
  100. switch (request) {
  101. case TIOCGPGRP:
  102. return m_pgid;
  103. case TIOCSPGRP:
  104. // FIXME: Validate pgid fully.
  105. pgid = static_cast<pid_t>(arg);
  106. if (pgid < 0)
  107. return -EINVAL;
  108. m_pgid = pgid;
  109. return 0;
  110. case TCGETS:
  111. tp = reinterpret_cast<Unix::termios*>(arg);
  112. if (!process.validate_write(tp, sizeof(Unix::termios)))
  113. return -EFAULT;
  114. *tp = m_termios;
  115. return 0;
  116. case TCSETS:
  117. case TCSETSF:
  118. case TCSETSW:
  119. tp = reinterpret_cast<Unix::termios*>(arg);
  120. if (!process.validate_read(tp, sizeof(Unix::termios)))
  121. return -EFAULT;
  122. set_termios(*tp);
  123. return 0;
  124. case TIOCGWINSZ:
  125. ws = reinterpret_cast<Unix::winsize*>(arg);
  126. if (!process.validate_write(ws, sizeof(Unix::winsize)))
  127. return -EFAULT;
  128. ws->ws_row = m_rows;
  129. ws->ws_col = m_columns;
  130. return 0;
  131. case TIOCSCTTY:
  132. process.set_tty(this);
  133. return 0;
  134. case TIOCNOTTY:
  135. process.set_tty(nullptr);
  136. return 0;
  137. }
  138. ASSERT_NOT_REACHED();
  139. return -EINVAL;
  140. }
  141. void TTY::set_size(unsigned short columns, unsigned short rows)
  142. {
  143. m_rows = rows;
  144. m_columns = columns;
  145. }