1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
9 #include <sys/select.h>
14 #include "dev_fs_for_testing.h"
15 #include "gtest/gtest.h"
16 #include "nacl_io/devfs/dev_fs.h"
17 #include "nacl_io/filesystem.h"
18 #include "nacl_io/ioctl.h"
19 #include "nacl_io/kernel_intercept.h"
20 #include "nacl_io/kernel_proxy.h"
21 #include "nacl_io/osdirent.h"
23 using namespace nacl_io;
27 class TtyNodeTest : public ::testing::Test {
29 TtyNodeTest() : fs_(&pepper_) {}
32 ASSERT_EQ(0, fs_.Access(Path("/tty"), R_OK | W_OK));
33 ASSERT_EQ(EACCES, fs_.Access(Path("/tty"), X_OK));
34 ASSERT_EQ(0, fs_.Open(Path("/tty"), O_RDWR, &dev_tty_));
35 ASSERT_NE(NULL_NODE, dev_tty_.get());
39 FakePepperInterface pepper_;
44 class TtyTest : public ::testing::Test {
47 ASSERT_EQ(0, ki_push_state_for_testing());
48 ASSERT_EQ(0, ki_init(&kp_));
59 TEST_F(TtyNodeTest, InvalidIoctl) {
60 // 123 is not a valid ioctl request.
61 EXPECT_EQ(EINVAL, dev_tty_->Ioctl(123));
64 TEST_F(TtyNodeTest, TtyInput) {
65 // Now let's try sending some data over.
66 // First we create the message.
67 std::string message("hello, how are you?\n");
68 struct tioc_nacl_input_string packaged_message;
69 packaged_message.length = message.size();
70 packaged_message.buffer = message.data();
72 // Now we make buffer we'll read into.
73 // We fill the buffer and a backup buffer with arbitrary data
74 // and compare them after reading to make sure read doesn't
75 // clobber parts of the buffer it shouldn't.
78 char backup_buffer[100];
79 memset(buffer, 'a', 100);
80 memset(backup_buffer, 'a', 100);
82 // Now we actually send the data
83 EXPECT_EQ(0, dev_tty_->Ioctl(TIOCNACLINPUT, &packaged_message));
85 // We read a small chunk first to ensure it doesn't give us
86 // more than we ask for.
88 EXPECT_EQ(0, dev_tty_->Read(attrs, buffer, 5, &bytes_read));
89 EXPECT_EQ(5, bytes_read);
90 EXPECT_EQ(0, memcmp(message.data(), buffer, 5));
91 EXPECT_EQ(0, memcmp(buffer + 5, backup_buffer + 5, 95));
93 // Now we ask for more data than is left in the tty, to ensure
94 // it doesn't give us more than is there.
95 EXPECT_EQ(0, dev_tty_->Read(attrs, buffer + 5, 95, &bytes_read));
96 EXPECT_EQ(bytes_read, message.size() - 5);
97 EXPECT_EQ(0, memcmp(message.data(), buffer, message.size()));
98 EXPECT_EQ(0, memcmp(buffer + message.size(),
99 backup_buffer + message.size(),
100 100 - message.size()));
104 const char* output_buf;
108 static ssize_t output_handler(const char* buf, size_t count, void* data) {
109 user_data_t* user_data = static_cast<user_data_t*>(data);
110 user_data->output_buf = buf;
111 user_data->output_count = count;
115 TEST_F(TtyNodeTest, TtyOutput) {
116 // When no handler is registered then all writes should return EIO
117 int bytes_written = 10;
118 const char* message = "hello\n";
119 int message_len = strlen(message);
121 EXPECT_EQ(EIO, dev_tty_->Write(attrs, message, message_len, &bytes_written));
123 // Setup output handler with user_data to record calls.
124 user_data_t user_data;
125 user_data.output_buf = NULL;
126 user_data.output_count = 0;
128 tioc_nacl_output handler;
129 handler.handler = output_handler;
130 handler.user_data = &user_data;
132 EXPECT_EQ(0, dev_tty_->Ioctl(TIOCNACLOUTPUT, &handler));
134 EXPECT_EQ(0, dev_tty_->Write(attrs, message, message_len, &bytes_written));
135 EXPECT_EQ(message_len, bytes_written);
136 EXPECT_EQ(message_len, user_data.output_count);
137 EXPECT_EQ(0, strncmp(user_data.output_buf, message, message_len));
140 static int ki_ioctl_wrapper(int fd, int request, ...) {
142 va_start(ap, request);
143 int rtn = ki_ioctl(fd, request, ap);
148 static int TtyWrite(int fd, const char* string) {
149 struct tioc_nacl_input_string input;
150 input.buffer = string;
151 input.length = strlen(input.buffer);
152 return ki_ioctl_wrapper(fd, TIOCNACLINPUT, &input);
158 // -1 -> Error occured
159 static int IsReadable(int fd) {
160 struct timeval timeout = {0, 0};
165 FD_SET(fd, &readfds);
166 FD_SET(fd, &errorfds);
167 int rtn = ki_select(fd + 1, &readfds, NULL, &errorfds, &timeout);
169 return 0; // not readable
172 if (FD_ISSET(fd, &errorfds))
174 if (!FD_ISSET(fd, &readfds))
176 return 1; // readable
179 TEST_F(TtyTest, TtySelect) {
180 struct timeval timeout;
185 int tty_fd = ki_open("/dev/tty", O_RDONLY);
186 ASSERT_GT(tty_fd, 0) << "tty open failed: " << errno;
190 FD_SET(tty_fd, &readfds);
191 FD_SET(tty_fd, &errorfds);
192 // 10 millisecond timeout
194 timeout.tv_usec = 10 * 1000;
195 // Should timeout when no input is available.
196 int rtn = ki_select(tty_fd + 1, &readfds, NULL, &errorfds, &timeout);
197 ASSERT_EQ(0, rtn) << "select failed: " << rtn << " err=" << strerror(errno);
198 ASSERT_FALSE(FD_ISSET(tty_fd, &readfds));
199 ASSERT_FALSE(FD_ISSET(tty_fd, &errorfds));
204 FD_SET(tty_fd, &readfds);
205 FD_SET(tty_fd, &writefds);
206 FD_SET(tty_fd, &errorfds);
207 // TTY should be writable on startup.
208 rtn = ki_select(tty_fd + 1, &readfds, &writefds, &errorfds, NULL);
210 ASSERT_TRUE(FD_ISSET(tty_fd, &writefds));
211 ASSERT_FALSE(FD_ISSET(tty_fd, &readfds));
212 ASSERT_FALSE(FD_ISSET(tty_fd, &errorfds));
214 // Send 4 bytes to TTY input
215 ASSERT_EQ(0, TtyWrite(tty_fd, "input:test"));
217 // TTY should not be readable until newline in written
218 ASSERT_EQ(IsReadable(tty_fd), 0);
219 ASSERT_EQ(0, TtyWrite(tty_fd, "input:\n"));
221 // TTY should now be readable
222 ASSERT_EQ(1, IsReadable(tty_fd));
227 TEST_F(TtyTest, TtyICANON) {
228 int tty_fd = ki_open("/dev/tty", O_RDONLY);
230 ASSERT_EQ(0, IsReadable(tty_fd));
232 struct termios tattr;
233 ki_tcgetattr(tty_fd, &tattr);
234 tattr.c_lflag &= ~(ICANON | ECHO); /* Clear ICANON and ECHO. */
235 ki_tcsetattr(tty_fd, TCSAFLUSH, &tattr);
237 ASSERT_EQ(0, IsReadable(tty_fd));
239 // Set some bytes to the TTY, not including newline
240 ASSERT_EQ(0, TtyWrite(tty_fd, "a"));
242 // Since we are not in canonical mode the bytes should be
243 // immediately readable.
244 ASSERT_EQ(1, IsReadable(tty_fd));
246 // Read byte from tty.
248 ASSERT_EQ(1, ki_read(tty_fd, &c, 1));
251 ASSERT_EQ(0, IsReadable(tty_fd));
254 static int g_received_signal;
256 static void sighandler(int sig) { g_received_signal = sig; }
258 TEST_F(TtyTest, WindowSize) {
259 // Get current window size
260 struct winsize old_winsize = {0};
261 int tty_fd = ki_open("/dev/tty", O_RDONLY);
262 ASSERT_EQ(0, ki_ioctl_wrapper(tty_fd, TIOCGWINSZ, &old_winsize));
264 // Install signal handler
265 sighandler_t new_handler = sighandler;
266 sighandler_t old_handler = ki_signal(SIGWINCH, new_handler);
267 ASSERT_NE(SIG_ERR, old_handler) << "signal return error: " << errno;
269 g_received_signal = 0;
271 // Set a new windows size
272 struct winsize winsize;
273 winsize.ws_col = 100;
274 winsize.ws_row = 200;
275 EXPECT_EQ(0, ki_ioctl_wrapper(tty_fd, TIOCSWINSZ, &winsize));
276 EXPECT_EQ(SIGWINCH, g_received_signal);
278 // Restore old signal handler
279 EXPECT_EQ(new_handler, ki_signal(SIGWINCH, old_handler));
281 // Verify new window size can be queried correctly.
284 EXPECT_EQ(0, ki_ioctl_wrapper(tty_fd, TIOCGWINSZ, &winsize));
285 EXPECT_EQ(100, winsize.ws_col);
286 EXPECT_EQ(200, winsize.ws_row);
288 // Restore original windows size.
289 EXPECT_EQ(0, ki_ioctl_wrapper(tty_fd, TIOCSWINSZ, &old_winsize));
293 * Sleep for 50ms then send a resize event to /dev/tty.
295 static void* resize_thread_main(void* arg) {
298 int* tty_fd = static_cast<int*>(arg);
299 struct winsize winsize;
300 winsize.ws_col = 100;
301 winsize.ws_row = 200;
302 ki_ioctl_wrapper(*tty_fd, TIOCSWINSZ, &winsize);
306 TEST_F(TtyTest, ResizeDuringSelect) {
307 // Test that a window resize during a call
308 // to select(3) will cause it to fail with EINTR.
309 int tty_fd = ki_open("/dev/tty", O_RDONLY);
315 FD_SET(tty_fd, &readfds);
316 FD_SET(tty_fd, &errorfds);
318 pthread_t resize_thread;
319 pthread_create(&resize_thread, NULL, resize_thread_main, &tty_fd);
321 struct timeval timeout;
325 // TTY should not be readable either before or after the
326 // call to select(3).
327 ASSERT_EQ(0, IsReadable(tty_fd));
329 int rtn = ki_select(tty_fd + 1, &readfds, NULL, &errorfds, &timeout);
330 pthread_join(resize_thread, NULL);
332 ASSERT_EQ(EINTR, errno);
333 ASSERT_EQ(0, IsReadable(tty_fd));
337 * Sleep for 50ms then send some input to the /dev/tty.
339 static void* input_thread_main(void* arg) {
342 int fd = ki_open("/dev/tty", O_RDONLY);
343 TtyWrite(fd, "test\n");
347 TEST_F(TtyTest, InputDuringSelect) {
348 // Test that input which occurs while in select causes
350 int tty_fd = ki_open("/dev/tty", O_RDONLY);
356 FD_SET(tty_fd, &readfds);
357 FD_SET(tty_fd, &errorfds);
359 pthread_t resize_thread;
360 pthread_create(&resize_thread, NULL, input_thread_main, NULL);
362 struct timeval timeout;
366 int rtn = ki_select(tty_fd + 1, &readfds, NULL, &errorfds, &timeout);
367 pthread_join(resize_thread, NULL);