15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 2ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// Use of this source code is governed by a BSD-style license that can be 3ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// found in the LICENSE file. 4ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "nacl_io/devfs/tty_node.h" 6ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 7ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include <assert.h> 8ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include <errno.h> 93551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include <signal.h> 10ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include <stdio.h> 11ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include <string.h> 123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include <sys/ioctl.h> 133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include <unistd.h> 14ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 15ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include <algorithm> 16ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "nacl_io/filesystem.h" 18ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "nacl_io/ioctl.h" 194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "nacl_io/kernel_handle.h" 20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "nacl_io/kernel_intercept.h" 21f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "nacl_io/log.h" 22ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "nacl_io/pepper_interface.h" 23ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "sdk_util/auto_lock.h" 24ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 2546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#define CHECK_LFLAG(TERMIOS, FLAG) (TERMIOS.c_lflag& FLAG) 26ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 27ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#define IS_ECHO CHECK_LFLAG(termios_, ECHO) 28ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#define IS_ECHOE CHECK_LFLAG(termios_, ECHOE) 29ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#define IS_ECHONL CHECK_LFLAG(termios_, ECHONL) 30ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#define IS_ECHOCTL CHECK_LFLAG(termios_, ECHOCTL) 31ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#define IS_ICANON CHECK_LFLAG(termios_, ICANON) 32ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#define DEFAULT_TTY_COLS 80 343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#define DEFAULT_TTY_ROWS 30 353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 36ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochnamespace nacl_io { 37ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TtyNode::TtyNode(Filesystem* filesystem) 395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : CharNode(filesystem), 4068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) emitter_(new EventEmitter), 4168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) rows_(DEFAULT_TTY_ROWS), 4268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) cols_(DEFAULT_TTY_COLS) { 433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) output_handler_.handler = NULL; 44ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch InitTermios(); 4568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 4668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // Output will never block 4768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) emitter_->RaiseEvents_Locked(POLLOUT); 48ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 49ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void TtyNode::InitTermios() { 51ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // Some sane values that produce good result. 52ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch termios_.c_iflag = ICRNL | IXON | IXOFF | IUTF8; 53ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch termios_.c_oflag = OPOST | ONLCR; 54ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch termios_.c_cflag = CREAD | 077; 55ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch termios_.c_lflag = 56ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN; 57c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#if !defined(__BIONIC__) 58ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch termios_.c_ispeed = B38400; 59ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch termios_.c_ospeed = B38400; 60c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#endif 61ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch termios_.c_cc[VINTR] = 3; 62ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch termios_.c_cc[VQUIT] = 28; 63ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch termios_.c_cc[VERASE] = 127; 64ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch termios_.c_cc[VKILL] = 21; 65ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch termios_.c_cc[VEOF] = 4; 66ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch termios_.c_cc[VTIME] = 0; 67ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch termios_.c_cc[VMIN] = 1; 68ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch termios_.c_cc[VSWTC] = 0; 69ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch termios_.c_cc[VSTART] = 17; 70ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch termios_.c_cc[VSTOP] = 19; 71ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch termios_.c_cc[VSUSP] = 26; 72ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch termios_.c_cc[VEOL] = 0; 73ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch termios_.c_cc[VREPRINT] = 18; 74ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch termios_.c_cc[VDISCARD] = 15; 75ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch termios_.c_cc[VWERASE] = 23; 76ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch termios_.c_cc[VLNEXT] = 22; 77ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch termios_.c_cc[VEOL2] = 0; 78ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 79ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 8046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)EventEmitter* TtyNode::GetEventEmitter() { 8146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) return emitter_.get(); 8246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)} 83ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)Error TtyNode::Write(const HandleAttr& attr, 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const void* buf, 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) size_t count, 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int* out_bytes) { 883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) AUTO_LOCK(output_lock_); 89ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch *out_bytes = 0; 90ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // No handler registered. 92116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (output_handler_.handler == NULL) { 93116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // No error here; many of the tests trigger this message. 94116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch LOG_TRACE("No output handler registered."); 953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return EIO; 96116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 97ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int rtn = output_handler_.handler( 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) static_cast<const char*>(buf), count, output_handler_.user_data); 100ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 1013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // Negative return value means an error occured and the return 1023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // value is a negated errno value. 1033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if (rtn < 0) 1043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return -rtn; 105ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 1063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) *out_bytes = rtn; 107ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return 0; 108ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 109ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)Error TtyNode::Read(const HandleAttr& attr, 1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) void* buf, 1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) size_t count, 1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int* out_bytes) { 11468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) EventListenerLock wait(GetEventEmitter()); 11568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) *out_bytes = 0; 116ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 11768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // If interrupted, return 11868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) Error err = wait.WaitOnEvent(POLLIN, -1); 119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (err == ETIMEDOUT) 120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) err = EWOULDBLOCK; 12168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (err != 0) 12268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return err; 123ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 12468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) size_t bytes_to_copy = std::min(count, input_buffer_.size()); 125ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (IS_ICANON) { 126ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // Only read up to (and including) the first newline 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::deque<char>::iterator nl = 1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::find(input_buffer_.begin(), input_buffer_.end(), '\n'); 129ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 130ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (nl != input_buffer_.end()) { 131ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // We found a newline in the buffer, adjust bytes_to_copy accordingly 132ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch size_t line_len = static_cast<size_t>(nl - input_buffer_.begin()) + 1; 133ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch bytes_to_copy = std::min(bytes_to_copy, line_len); 134ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } 135ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } 136ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 137ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // Copies data from the input buffer into buf. 1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::copy(input_buffer_.begin(), 1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) input_buffer_.begin() + bytes_to_copy, 140ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch static_cast<char*>(buf)); 141ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch *out_bytes = bytes_to_copy; 142ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch input_buffer_.erase(input_buffer_.begin(), 143ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch input_buffer_.begin() + bytes_to_copy); 144ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 145ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // mark input as no longer readable if we consumed 146ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // the entire buffer or, in the case of buffered input, 147ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // we consumed the final \n char. 14868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) bool avail; 149ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (IS_ICANON) 1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) avail = std::find(input_buffer_.begin(), input_buffer_.end(), '\n') != 1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) input_buffer_.end(); 152ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch else 15368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) avail = input_buffer_.size() > 0; 15468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 15568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (!avail) 15668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) emitter_->ClearEvents_Locked(POLLIN); 157ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 158ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return 0; 159ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 160ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)Error TtyNode::Echo(const char* string, int count) { 162ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch int wrote; 1634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) HandleAttr data; 1644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) Error error = Write(data, string, count, &wrote); 165ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (error != 0 || wrote != count) { 166ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // TOOD(sbc): Do something more useful in response to a 167ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // failure to echo. 168ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return error; 169ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } 170ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 171ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return 0; 172ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 173ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 174f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Error TtyNode::ProcessInput(PP_Var message) { 175f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (message.type != PP_VARTYPE_STRING) { 176116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch LOG_ERROR("Expected VarString but got %d.", message.type); 177f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return EINVAL; 178f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 179f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 180f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) PepperInterface* ppapi = filesystem_->ppapi(); 181f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!ppapi) { 182116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch LOG_ERROR("ppapi is NULL."); 183f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return EINVAL; 184f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 185f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 186f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VarInterface* var_iface = ppapi->GetVarInterface(); 187f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!var_iface) { 188116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch LOG_ERROR("Got NULL interface: Var"); 189f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return EINVAL; 190f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 191ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 192f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) uint32_t num_bytes; 193f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const char* buffer = var_iface->VarToUtf8(message, &num_bytes); 194f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Error error = ProcessInput(buffer, num_bytes); 195f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return error; 196f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 197f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 198f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Error TtyNode::ProcessInput(const char* buffer, size_t num_bytes) { 199f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) AUTO_LOCK(emitter_->GetLock()) 200ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 2013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) for (size_t i = 0; i < num_bytes; i++) { 202ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch char c = buffer[i]; 203ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // Transform characters according to input flags. 204ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (c == '\r') { 205ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (termios_.c_iflag & IGNCR) 206ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch continue; 207ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (termios_.c_iflag & ICRNL) 208ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch c = '\n'; 209ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } else if (c == '\n') { 210ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (termios_.c_iflag & INLCR) 211ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch c = '\r'; 212ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } 213ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 214ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch bool skip = false; 215ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 216ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // ICANON mode means we wait for a newline before making the 217ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // file readable. 218ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (IS_ICANON) { 219ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (IS_ECHOE && c == termios_.c_cc[VERASE]) { 220ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // Remove previous character in the line if any. 221ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (!input_buffer_.empty()) { 222ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch char char_to_delete = input_buffer_.back(); 223ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (char_to_delete != '\n') { 224ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch input_buffer_.pop_back(); 225ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (IS_ECHO) 226ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch Echo("\b \b", 3); 227ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 228ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // When ECHOCTL is set the echo buffer contains an extra 229ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // char for each control char. 230ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (IS_ECHOCTL && iscntrl(char_to_delete)) 231ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch Echo("\b \b", 3); 232ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } 233ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } 234ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch continue; 235ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } else if (IS_ECHO || (IS_ECHONL && c == '\n')) { 236ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (c == termios_.c_cc[VEOF]) { 237ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // VEOF sequence is not echoed, nor is it sent as 238ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // input. 239ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch skip = true; 240ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } else if (c != '\n' && iscntrl(c) && IS_ECHOCTL) { 241ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // In ECHOCTL mode a control char C is echoed as '^' 242ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // followed by the ascii char which at C + 0x40. 243ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch char visible_char = c + 0x40; 244ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch Echo("^", 1); 245ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch Echo(&visible_char, 1); 246ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } else { 247ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch Echo(&c, 1); 248ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } 249ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } 250ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } 251ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 252ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (!skip) 253ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch input_buffer_.push_back(c); 254ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 255ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (c == '\n' || c == termios_.c_cc[VEOF] || !IS_ICANON) 25668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) emitter_->RaiseEvents_Locked(POLLIN); 2573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 2583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 259ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return 0; 260ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 261ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)Error TtyNode::VIoctl(int request, va_list args) { 2633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) switch (request) { 2643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) case TIOCNACLOUTPUT: { 2654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) struct tioc_nacl_output* arg = va_arg(args, struct tioc_nacl_output*); 2663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) AUTO_LOCK(output_lock_); 2673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if (arg == NULL) { 2683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) output_handler_.handler = NULL; 2693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return 0; 2703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 271116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (output_handler_.handler != NULL) { 272116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch LOG_ERROR("Output handler already set."); 2733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return EALREADY; 274116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 2754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) output_handler_ = *arg; 2763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return 0; 2773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 278f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) case NACL_IOC_HANDLEMESSAGE: { 279f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) struct PP_Var* message = va_arg(args, struct PP_Var*); 280f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return ProcessInput(*message); 2813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 2823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) case TIOCSWINSZ: { 2834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) struct winsize* size = va_arg(args, struct winsize*); 2843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) { 2853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) AUTO_LOCK(node_lock_); 286f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (rows_ == size->ws_row && cols_ == size->ws_col) 287f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return 0; 2883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) rows_ = size->ws_row; 2893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) cols_ = size->ws_col; 2903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 291f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ki_kill(getpid(), SIGWINCH); 29268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) { 29368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // Wake up any thread waiting on Read with POLLERR then immediate 29468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // clear it to signal EINTR. 29568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) AUTO_LOCK(emitter_->GetLock()) 29668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) emitter_->RaiseEvents_Locked(POLLERR); 29768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) emitter_->ClearEvents_Locked(POLLERR); 29868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 2993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return 0; 3003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 3013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) case TIOCGWINSZ: { 3024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) struct winsize* size = va_arg(args, struct winsize*); 3033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) size->ws_row = rows_; 3043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) size->ws_col = cols_; 3053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return 0; 3063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 307f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) default: { 308f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) LOG_ERROR("TtyNode:VIoctl: Unknown request: %#x", request); 309f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 310ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } 3113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 3123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return EINVAL; 313ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 314ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)Error TtyNode::Tcgetattr(struct termios* termios_p) { 316ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch AUTO_LOCK(node_lock_); 317ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch *termios_p = termios_; 318ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return 0; 319ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 320ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)Error TtyNode::Tcsetattr(int optional_actions, 3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const struct termios* termios_p) { 323ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch AUTO_LOCK(node_lock_); 324ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch termios_ = *termios_p; 325ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return 0; 326ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 327ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} // namespace nacl_io 329