15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
23551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
33551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// found in the LICENSE file.
43551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
53551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include <errno.h>
63551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include <fcntl.h>
73551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include <string.h>
83551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include <sys/ioctl.h>
93551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include <sys/select.h>
103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include <sys/stat.h>
113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include <sys/time.h>
123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include <string>
133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "dev_fs_for_testing.h"
153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "gtest/gtest.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "nacl_io/devfs/dev_fs.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "nacl_io/filesystem.h"
183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "nacl_io/ioctl.h"
193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "nacl_io/kernel_intercept.h"
203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "nacl_io/kernel_proxy.h"
213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "nacl_io/osdirent.h"
223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)using namespace nacl_io;
243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)namespace {
263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)static int ki_ioctl_wrapper(int fd, int request, ...) {
28f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  va_list ap;
29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  va_start(ap, request);
30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  int rtn = ki_ioctl(fd, request, ap);
31f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  va_end(ap);
32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return rtn;
33f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
34f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
35010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)class TtyNodeTest : public ::testing::Test {
363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) public:
37f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  TtyNodeTest() : fs_(&ppapi_) {}
38010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  void SetUp() {
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ASSERT_EQ(0, fs_.Open(Path("/tty"), O_RDWR, &dev_tty_));
413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    ASSERT_NE(NULL_NODE, dev_tty_.get());
421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    struct stat buf;
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ASSERT_EQ(0, dev_tty_->GetStat(&buf));
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ASSERT_EQ(S_IRUSR | S_IWUSR, buf.st_mode & S_IRWXU);
453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) protected:
48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  FakePepperInterface ppapi_;
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DevFsForTesting fs_;
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ScopedNode dev_tty_;
513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)};
523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
53010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)class TtyTest : public ::testing::Test {
54010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) public:
55010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  void SetUp() {
56010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    ASSERT_EQ(0, ki_push_state_for_testing());
57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ASSERT_EQ(0, ki_init_interface(&kp_, &ppapi_));
58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    var_iface_ = ppapi_.GetVarInterface();
60010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
61010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
62010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  void TearDown() {
63010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    ki_uninit();
64010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
65010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  int TtyWrite(int fd, const char* string) {
67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    PP_Var message_var = var_iface_->VarFromUtf8(string, strlen(string));
68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    int result = ki_ioctl_wrapper(fd, NACL_IOC_HANDLEMESSAGE, &message_var);
69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    var_iface_->Release(message_var);
70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return result;
71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
73010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) protected:
74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  FakePepperInterface ppapi_;
75010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  KernelProxy kp_;
76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  VarInterface* var_iface_;
77010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)};
78010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
79010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)TEST_F(TtyNodeTest, InvalidIoctl) {
803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // 123 is not a valid ioctl request.
814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_EQ(EINVAL, dev_tty_->Ioctl(123));
823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
84010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)TEST_F(TtyNodeTest, TtyInput) {
853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Now let's try sending some data over.
863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // First we create the message.
873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::string message("hello, how are you?\n");
88f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  VarInterface* var_iface = ppapi_.GetVarInterface();
89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  PP_Var message_var = var_iface->VarFromUtf8(message.data(), message.size());
903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Now we make buffer we'll read into.
923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // We fill the buffer and a backup buffer with arbitrary data
933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // and compare them after reading to make sure read doesn't
943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // clobber parts of the buffer it shouldn't.
953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int bytes_read;
963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  char buffer[100];
973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  char backup_buffer[100];
983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  memset(buffer, 'a', 100);
993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  memset(backup_buffer, 'a', 100);
1003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Now we actually send the data
102f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(0, dev_tty_->Ioctl(NACL_IOC_HANDLEMESSAGE, &message_var));
103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  var_iface->Release(message_var);
1053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // We read a small chunk first to ensure it doesn't give us
1073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // more than we ask for.
1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  HandleAttr attrs;
1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_EQ(0, dev_tty_->Read(attrs, buffer, 5, &bytes_read));
110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  EXPECT_EQ(5, bytes_read);
1113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(0, memcmp(message.data(), buffer, 5));
1123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(0, memcmp(buffer + 5, backup_buffer + 5, 95));
1133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Now we ask for more data than is left in the tty, to ensure
1153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // it doesn't give us more than is there.
1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_EQ(0, dev_tty_->Read(attrs, buffer + 5, 95, &bytes_read));
1173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(bytes_read, message.size() - 5);
1183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(0, memcmp(message.data(), buffer, message.size()));
1193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(0, memcmp(buffer + message.size(),
1203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                      backup_buffer + message.size(),
1213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                      100 - message.size()));
1223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)struct user_data_t {
1253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const char* output_buf;
1263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  size_t output_count;
1273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)};
1283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)static ssize_t output_handler(const char* buf, size_t count, void* data) {
1303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  user_data_t* user_data = static_cast<user_data_t*>(data);
1313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  user_data->output_buf = buf;
1323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  user_data->output_count = count;
1333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return count;
1343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
136010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)TEST_F(TtyNodeTest, TtyOutput) {
1373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // When no handler is registered then all writes should return EIO
1383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int bytes_written = 10;
1393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const char* message = "hello\n";
1403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int message_len = strlen(message);
1414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  HandleAttr attrs;
1424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_EQ(EIO, dev_tty_->Write(attrs, message, message_len, &bytes_written));
1433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Setup output handler with user_data to record calls.
1453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  user_data_t user_data;
1463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  user_data.output_buf = NULL;
1473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  user_data.output_count = 0;
1483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  tioc_nacl_output handler;
1503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  handler.handler = output_handler;
1513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  handler.user_data = &user_data;
1523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_EQ(0, dev_tty_->Ioctl(TIOCNACLOUTPUT, &handler));
1543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_EQ(0, dev_tty_->Write(attrs, message, message_len, &bytes_written));
1563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(message_len, bytes_written);
1573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(message_len, user_data.output_count);
1583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(0, strncmp(user_data.output_buf, message, message_len));
1593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Returns:
1623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)//   0 -> Not readable
1633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)//   1 -> Readable
1643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)//  -1 -> Error occured
1653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)static int IsReadable(int fd) {
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  struct timeval timeout = {0, 0};
1673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  fd_set readfds;
1683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  fd_set errorfds;
1693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  FD_ZERO(&readfds);
1703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  FD_ZERO(&errorfds);
1713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  FD_SET(fd, &readfds);
1723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  FD_SET(fd, &errorfds);
1733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int rtn = ki_select(fd + 1, &readfds, NULL, &errorfds, &timeout);
1743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (rtn == 0)
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return 0;  // not readable
1763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (rtn != 1)
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return -1;  // error
1783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (FD_ISSET(fd, &errorfds))
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return -2;  // error
1803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!FD_ISSET(fd, &readfds))
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return -3;  // error
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return 1;     // readable
1833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)TEST_F(TtyTest, TtySelect) {
1863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  struct timeval timeout;
1873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  fd_set readfds;
1883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  fd_set writefds;
1893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  fd_set errorfds;
1903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  int tty_fd = ki_open("/dev/tty", O_RDONLY, 0);
192f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ASSERT_GT(tty_fd, 0) << "tty open failed: " << errno;
1933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  FD_ZERO(&readfds);
1953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  FD_ZERO(&errorfds);
1963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  FD_SET(tty_fd, &readfds);
1973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  FD_SET(tty_fd, &errorfds);
1983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // 10 millisecond timeout
1993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  timeout.tv_sec = 0;
2003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  timeout.tv_usec = 10 * 1000;
2013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Should timeout when no input is available.
2023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int rtn = ki_select(tty_fd + 1, &readfds, NULL, &errorfds, &timeout);
203f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ASSERT_EQ(0, rtn) << "select failed: " << rtn << " err=" << strerror(errno);
2043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ASSERT_FALSE(FD_ISSET(tty_fd, &readfds));
2053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ASSERT_FALSE(FD_ISSET(tty_fd, &errorfds));
2063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  FD_ZERO(&readfds);
2083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  FD_ZERO(&writefds);
2093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  FD_ZERO(&errorfds);
2103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  FD_SET(tty_fd, &readfds);
2113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  FD_SET(tty_fd, &writefds);
2123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  FD_SET(tty_fd, &errorfds);
2133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // TTY should be writable on startup.
2143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  rtn = ki_select(tty_fd + 1, &readfds, &writefds, &errorfds, NULL);
215f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ASSERT_EQ(1, rtn);
2163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ASSERT_TRUE(FD_ISSET(tty_fd, &writefds));
2173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ASSERT_FALSE(FD_ISSET(tty_fd, &readfds));
2183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ASSERT_FALSE(FD_ISSET(tty_fd, &errorfds));
2193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Send 4 bytes to TTY input
22168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_EQ(0, TtyWrite(tty_fd, "input:test"));
2223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // TTY should not be readable until newline in written
2243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ASSERT_EQ(IsReadable(tty_fd), 0);
22568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_EQ(0, TtyWrite(tty_fd, "input:\n"));
2263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // TTY should now be readable
228f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ASSERT_EQ(1, IsReadable(tty_fd));
2293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ki_close(tty_fd);
2313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
2323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
23368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)TEST_F(TtyTest, TtyICANON) {
2341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  int tty_fd = ki_open("/dev/tty", O_RDONLY, 0);
23568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
236f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ASSERT_EQ(0, IsReadable(tty_fd));
23768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
23868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  struct termios tattr;
239f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ki_tcgetattr(tty_fd, &tattr);
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  tattr.c_lflag &= ~(ICANON | ECHO); /* Clear ICANON and ECHO. */
241f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ki_tcsetattr(tty_fd, TCSAFLUSH, &tattr);
24268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
243f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ASSERT_EQ(0, IsReadable(tty_fd));
24468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
24568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Set some bytes to the TTY, not including newline
24668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_EQ(0, TtyWrite(tty_fd, "a"));
24768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
24868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Since we are not in canonical mode the bytes should be
24968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // immediately readable.
250f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ASSERT_EQ(1, IsReadable(tty_fd));
25168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
25268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Read byte from tty.
25368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  char c;
254f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ASSERT_EQ(1, ki_read(tty_fd, &c, 1));
25568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_EQ('a', c);
25668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
257f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ASSERT_EQ(0, IsReadable(tty_fd));
25868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
25968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
260010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)static int g_received_signal;
2613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
262010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)static void sighandler(int sig) { g_received_signal = sig; }
2633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)TEST_F(TtyTest, WindowSize) {
2653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Get current window size
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  struct winsize old_winsize = {0};
2671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  int tty_fd = ki_open("/dev/tty", O_RDONLY, 0);
268010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  ASSERT_EQ(0, ki_ioctl_wrapper(tty_fd, TIOCGWINSZ, &old_winsize));
2693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Install signal handler
2713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  sighandler_t new_handler = sighandler;
2723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  sighandler_t old_handler = ki_signal(SIGWINCH, new_handler);
273f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ASSERT_NE(SIG_ERR, old_handler) << "signal return error: " << errno;
274f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
275010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  g_received_signal = 0;
2763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Set a new windows size
2783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  struct winsize winsize;
2793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  winsize.ws_col = 100;
2803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  winsize.ws_row = 200;
281010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  EXPECT_EQ(0, ki_ioctl_wrapper(tty_fd, TIOCSWINSZ, &winsize));
282010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  EXPECT_EQ(SIGWINCH, g_received_signal);
2833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Restore old signal handler
2853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(new_handler, ki_signal(SIGWINCH, old_handler));
2863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Verify new window size can be queried correctly.
2883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  winsize.ws_col = 0;
2893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  winsize.ws_row = 0;
290010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  EXPECT_EQ(0, ki_ioctl_wrapper(tty_fd, TIOCGWINSZ, &winsize));
291f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  EXPECT_EQ(100, winsize.ws_col);
292f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  EXPECT_EQ(200, winsize.ws_row);
2933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Restore original windows size.
295010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  EXPECT_EQ(0, ki_ioctl_wrapper(tty_fd, TIOCSWINSZ, &old_winsize));
2963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
2973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
29868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)/*
29968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) * Sleep for 50ms then send a resize event to /dev/tty.
30068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) */
30168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)static void* resize_thread_main(void* arg) {
30268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  usleep(50 * 1000);
30368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
30468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  int* tty_fd = static_cast<int*>(arg);
30568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  struct winsize winsize;
30668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  winsize.ws_col = 100;
30768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  winsize.ws_row = 200;
3084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ki_ioctl_wrapper(*tty_fd, TIOCSWINSZ, &winsize);
30968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return NULL;
31068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
31168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
31268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)TEST_F(TtyTest, ResizeDuringSelect) {
31368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Test that a window resize during a call
31468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // to select(3) will cause it to fail with EINTR.
3151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  int tty_fd = ki_open("/dev/tty", O_RDONLY, 0);
31668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
31768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  fd_set readfds;
31868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  fd_set errorfds;
31968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  FD_ZERO(&readfds);
32068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  FD_ZERO(&errorfds);
32168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  FD_SET(tty_fd, &readfds);
32268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  FD_SET(tty_fd, &errorfds);
32368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
32468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  pthread_t resize_thread;
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  pthread_create(&resize_thread, NULL, resize_thread_main, &tty_fd);
32668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
32768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  struct timeval timeout;
32868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  timeout.tv_sec = 20;
32968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  timeout.tv_usec = 0;
33068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
33168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // TTY should not be readable either before or after the
33268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // call to select(3).
333f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ASSERT_EQ(0, IsReadable(tty_fd));
33468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
33568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  int rtn = ki_select(tty_fd + 1, &readfds, NULL, &errorfds, &timeout);
33668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  pthread_join(resize_thread, NULL);
33768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_EQ(-1, rtn);
33868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_EQ(EINTR, errno);
339f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ASSERT_EQ(0, IsReadable(tty_fd));
34068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
34168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
34268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)/*
34368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) * Sleep for 50ms then send some input to the /dev/tty.
34468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) */
34568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)static void* input_thread_main(void* arg) {
346f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  TtyTest* thiz = static_cast<TtyTest*>(arg);
347f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
34868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  usleep(50 * 1000);
34968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
3501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  int fd = ki_open("/dev/tty", O_RDONLY, 0);
351f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  thiz->TtyWrite(fd, "test\n");
35268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return NULL;
35368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
35468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
35568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)TEST_F(TtyTest, InputDuringSelect) {
35668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Test that input which occurs while in select causes
35768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // select to return.
3581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  int tty_fd = ki_open("/dev/tty", O_RDONLY, 0);
35968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
36068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  fd_set readfds;
36168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  fd_set errorfds;
36268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  FD_ZERO(&readfds);
36368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  FD_ZERO(&errorfds);
36468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  FD_SET(tty_fd, &readfds);
36568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  FD_SET(tty_fd, &errorfds);
36668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
36768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  pthread_t resize_thread;
368f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  pthread_create(&resize_thread, NULL, input_thread_main, this);
36968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
37068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  struct timeval timeout;
37168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  timeout.tv_sec = 20;
37268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  timeout.tv_usec = 0;
37368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
37468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  int rtn = ki_select(tty_fd + 1, &readfds, NULL, &errorfds, &timeout);
37568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  pthread_join(resize_thread, NULL);
37668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
37768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_EQ(1, rtn);
37868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
379f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
380f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}  // namespace
381