#include "TTY.h" #include "Process.h" #include #include #include TTY::TTY(unsigned major, unsigned minor) : CharacterDevice(major, minor) { memset(&m_termios, 0, sizeof(m_termios)); m_termios.c_lflag |= ISIG | ECHO; } TTY::~TTY() { } ssize_t TTY::read(byte* buffer, size_t size) { ssize_t nread = min(m_buffer.size(), size); memcpy(buffer, m_buffer.data(), nread); if (nread == (ssize_t)m_buffer.size()) m_buffer.clear(); else { kprintf("had %u, read %u\n", m_buffer.size(), nread); ASSERT_NOT_REACHED(); } return nread; } ssize_t TTY::write(const byte* buffer, size_t size) { onTTYWrite(buffer, size); return 0; } bool TTY::hasDataAvailableForRead() const { return !m_buffer.isEmpty(); } void TTY::emit(byte ch) { m_buffer.append(ch); } void TTY::interrupt() { if (!should_generate_signals()) return; dbgprintf("%s: Interrupt ^C pressed!\n", ttyName().characters()); if (pgid()) { dbgprintf("%s: Send SIGINT to everyone in pgrp %d\n", ttyName().characters(), pgid()); InterruptDisabler disabler; Process::for_each_in_pgrp(pgid(), [this] (auto& process) { dbgprintf("%s: Send SIGINT to %d\n", ttyName().characters(), process.pid()); process.send_signal(SIGINT, nullptr); return true; }); } } void TTY::set_termios(const Unix::termios& t) { m_termios = t; dbgprintf("%s set_termios: IECHO? %u, ISIG? %u\n", ttyName().characters(), should_echo_input(), should_generate_signals()); } int TTY::ioctl(Process& process, unsigned request, unsigned arg) { pid_t pgid; Unix::termios* tp; if (process.tty() != this) return -ENOTTY; switch (request) { case TIOCGPGRP: return m_pgid; case TIOCSPGRP: // FIXME: Validate pgid fully. pgid = static_cast(arg); if (pgid < 0) return -EINVAL; m_pgid = pgid; return 0; case TCGETS: tp = reinterpret_cast(arg); if (!process.validate_write(tp, sizeof(Unix::termios))) return -EFAULT; *tp = m_termios; return 0; case TCSETS: tp = reinterpret_cast(arg); if (!process.validate_read(tp, sizeof(Unix::termios))) return -EFAULT; set_termios(*tp); return 0; } ASSERT_NOT_REACHED(); return -EINVAL; }