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