TTY.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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. void DoubleBuffer::flip()
  8. {
  9. ASSERT(m_read_buffer_index == m_read_buffer->size());
  10. swap(m_read_buffer, m_write_buffer);
  11. m_write_buffer->clear();
  12. m_read_buffer_index = 0;
  13. }
  14. Unix::ssize_t DoubleBuffer::write(const byte* data, size_t size)
  15. {
  16. m_write_buffer->append(data, size);
  17. return size;
  18. }
  19. Unix::ssize_t DoubleBuffer::read(byte* data, size_t size)
  20. {
  21. if (m_read_buffer_index >= m_read_buffer->size() && !m_write_buffer->isEmpty())
  22. flip();
  23. if (m_read_buffer_index >= m_read_buffer->size())
  24. return 0;
  25. ssize_t nread = min(m_read_buffer->size() - m_read_buffer_index, size);
  26. memcpy(data, m_read_buffer->data() + m_read_buffer_index, nread);
  27. m_read_buffer_index += nread;
  28. return nread;
  29. }
  30. TTY::TTY(unsigned major, unsigned minor)
  31. : CharacterDevice(major, minor)
  32. {
  33. memset(&m_termios, 0, sizeof(m_termios));
  34. m_termios.c_lflag |= ISIG | ECHO;
  35. static const char default_cc[32] = "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0";
  36. memcpy(m_termios.c_cc, default_cc, sizeof(default_cc));
  37. }
  38. TTY::~TTY()
  39. {
  40. }
  41. ssize_t TTY::read(byte* buffer, size_t size)
  42. {
  43. return m_buffer.read(buffer, size);
  44. }
  45. ssize_t TTY::write(const byte* buffer, size_t size)
  46. {
  47. #ifdef TTY_DEBUG
  48. dbgprintf("TTY::write %b {%u}\n", buffer[0], size);
  49. #endif
  50. onTTYWrite(buffer, size);
  51. return 0;
  52. }
  53. bool TTY::hasDataAvailableForRead() const
  54. {
  55. return !m_buffer.is_empty();
  56. }
  57. void TTY::emit(byte ch)
  58. {
  59. if (should_generate_signals()) {
  60. if (ch == m_termios.c_cc[VINTR]) {
  61. dbgprintf("%s: VINTR pressed!\n", ttyName().characters());
  62. generate_signal(SIGINT);
  63. return;
  64. }
  65. if (ch == m_termios.c_cc[VQUIT]) {
  66. dbgprintf("%s: VQUIT pressed!\n", ttyName().characters());
  67. generate_signal(SIGQUIT);
  68. return;
  69. }
  70. }
  71. m_buffer.write(&ch, 1);
  72. }
  73. void TTY::generate_signal(int signal)
  74. {
  75. if (!pgid())
  76. return;
  77. dbgprintf("%s: Send signal %d to everyone in pgrp %d\n", ttyName().characters(), signal, pgid());
  78. InterruptDisabler disabler; // FIXME: Iterate over a set of process handles instead?
  79. Process::for_each_in_pgrp(pgid(), [&] (auto& process) {
  80. dbgprintf("%s: Send signal %d to %d\n", ttyName().characters(), signal, process.pid());
  81. process.send_signal(signal, nullptr);
  82. return true;
  83. });
  84. }
  85. void TTY::set_termios(const Unix::termios& t)
  86. {
  87. m_termios = t;
  88. dbgprintf("%s set_termios: IECHO? %u, ISIG? %u, ICANON? %u\n",
  89. ttyName().characters(),
  90. should_echo_input(),
  91. should_generate_signals(),
  92. in_canonical_mode()
  93. );
  94. }
  95. int TTY::ioctl(Process& process, unsigned request, unsigned arg)
  96. {
  97. pid_t pgid;
  98. Unix::termios* tp;
  99. Unix::winsize* ws;
  100. if (process.tty() != this)
  101. return -ENOTTY;
  102. switch (request) {
  103. case TIOCGPGRP:
  104. return m_pgid;
  105. case TIOCSPGRP:
  106. // FIXME: Validate pgid fully.
  107. pgid = static_cast<pid_t>(arg);
  108. if (pgid < 0)
  109. return -EINVAL;
  110. m_pgid = pgid;
  111. return 0;
  112. case TCGETS:
  113. tp = reinterpret_cast<Unix::termios*>(arg);
  114. if (!process.validate_write(tp, sizeof(Unix::termios)))
  115. return -EFAULT;
  116. *tp = m_termios;
  117. return 0;
  118. case TCSETS:
  119. case TCSETSF:
  120. case TCSETSW:
  121. tp = reinterpret_cast<Unix::termios*>(arg);
  122. if (!process.validate_read(tp, sizeof(Unix::termios)))
  123. return -EFAULT;
  124. set_termios(*tp);
  125. return 0;
  126. case TIOCGWINSZ:
  127. ws = reinterpret_cast<Unix::winsize*>(arg);
  128. if (!process.validate_write(ws, sizeof(Unix::winsize)))
  129. return -EFAULT;
  130. ws->ws_row = m_rows;
  131. ws->ws_col = m_columns;
  132. return 0;
  133. }
  134. ASSERT_NOT_REACHED();
  135. return -EINVAL;
  136. }
  137. void TTY::set_size(unsigned short columns, unsigned short rows)
  138. {
  139. m_rows = rows;
  140. m_columns = columns;
  141. }