| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "nacl_io/devfs/tty_node.h" | 5 #include "nacl_io/devfs/tty_node.h" |
| 6 | 6 |
| 7 #include <assert.h> | 7 #include <assert.h> |
| 8 #include <errno.h> | 8 #include <errno.h> |
| 9 #include <signal.h> | 9 #include <signal.h> |
| 10 #include <stdio.h> | 10 #include <stdio.h> |
| 11 #include <string.h> | 11 #include <string.h> |
| 12 #include <sys/ioctl.h> | 12 #include <sys/ioctl.h> |
| 13 #include <unistd.h> | 13 #include <unistd.h> |
| 14 | 14 |
| 15 #include <algorithm> | 15 #include <algorithm> |
| 16 | 16 |
| 17 #include "nacl_io/filesystem.h" | 17 #include "nacl_io/filesystem.h" |
| 18 #include "nacl_io/ioctl.h" | 18 #include "nacl_io/ioctl.h" |
| 19 #include "nacl_io/kernel_handle.h" | 19 #include "nacl_io/kernel_handle.h" |
| 20 #include "nacl_io/kernel_intercept.h" | 20 #include "nacl_io/kernel_intercept.h" |
| 21 #include "nacl_io/log.h" |
| 21 #include "nacl_io/pepper_interface.h" | 22 #include "nacl_io/pepper_interface.h" |
| 22 #include "sdk_util/auto_lock.h" | 23 #include "sdk_util/auto_lock.h" |
| 23 | 24 |
| 24 #define CHECK_LFLAG(TERMIOS, FLAG) (TERMIOS.c_lflag& FLAG) | 25 #define CHECK_LFLAG(TERMIOS, FLAG) (TERMIOS.c_lflag& FLAG) |
| 25 | 26 |
| 26 #define IS_ECHO CHECK_LFLAG(termios_, ECHO) | 27 #define IS_ECHO CHECK_LFLAG(termios_, ECHO) |
| 27 #define IS_ECHOE CHECK_LFLAG(termios_, ECHOE) | 28 #define IS_ECHOE CHECK_LFLAG(termios_, ECHOE) |
| 28 #define IS_ECHONL CHECK_LFLAG(termios_, ECHONL) | 29 #define IS_ECHONL CHECK_LFLAG(termios_, ECHONL) |
| 29 #define IS_ECHOCTL CHECK_LFLAG(termios_, ECHOCTL) | 30 #define IS_ECHOCTL CHECK_LFLAG(termios_, ECHOCTL) |
| 30 #define IS_ICANON CHECK_LFLAG(termios_, ICANON) | 31 #define IS_ICANON CHECK_LFLAG(termios_, ICANON) |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 160 Error error = Write(data, string, count, &wrote); | 161 Error error = Write(data, string, count, &wrote); |
| 161 if (error != 0 || wrote != count) { | 162 if (error != 0 || wrote != count) { |
| 162 // TOOD(sbc): Do something more useful in response to a | 163 // TOOD(sbc): Do something more useful in response to a |
| 163 // failure to echo. | 164 // failure to echo. |
| 164 return error; | 165 return error; |
| 165 } | 166 } |
| 166 | 167 |
| 167 return 0; | 168 return 0; |
| 168 } | 169 } |
| 169 | 170 |
| 170 Error TtyNode::ProcessInput(struct tioc_nacl_input_string* message) { | 171 Error TtyNode::ProcessInput(PP_Var message) { |
| 172 if (message.type != PP_VARTYPE_STRING) { |
| 173 LOG_ERROR("ProcessInput: expected VarString but got %d.", message.type); |
| 174 return EINVAL; |
| 175 } |
| 176 |
| 177 PepperInterface* ppapi = filesystem_->ppapi(); |
| 178 if (!ppapi) { |
| 179 LOG_ERROR("ProcessInput: ppapi is NULL."); |
| 180 return EINVAL; |
| 181 } |
| 182 |
| 183 VarInterface* var_iface = ppapi->GetVarInterface(); |
| 184 if (!var_iface) { |
| 185 LOG_ERROR("ProcessInput: Var interface pointer is NULL."); |
| 186 return EINVAL; |
| 187 } |
| 188 |
| 189 uint32_t num_bytes; |
| 190 const char* buffer = var_iface->VarToUtf8(message, &num_bytes); |
| 191 Error error = ProcessInput(buffer, num_bytes); |
| 192 return error; |
| 193 } |
| 194 |
| 195 Error TtyNode::ProcessInput(const char* buffer, size_t num_bytes) { |
| 171 AUTO_LOCK(emitter_->GetLock()) | 196 AUTO_LOCK(emitter_->GetLock()) |
| 172 | 197 |
| 173 const char* buffer = message->buffer; | |
| 174 size_t num_bytes = message->length; | |
| 175 | |
| 176 for (size_t i = 0; i < num_bytes; i++) { | 198 for (size_t i = 0; i < num_bytes; i++) { |
| 177 char c = buffer[i]; | 199 char c = buffer[i]; |
| 178 // Transform characters according to input flags. | 200 // Transform characters according to input flags. |
| 179 if (c == '\r') { | 201 if (c == '\r') { |
| 180 if (termios_.c_iflag & IGNCR) | 202 if (termios_.c_iflag & IGNCR) |
| 181 continue; | 203 continue; |
| 182 if (termios_.c_iflag & ICRNL) | 204 if (termios_.c_iflag & ICRNL) |
| 183 c = '\n'; | 205 c = '\n'; |
| 184 } else if (c == '\n') { | 206 } else if (c == '\n') { |
| 185 if (termios_.c_iflag & INLCR) | 207 if (termios_.c_iflag & INLCR) |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 241 AUTO_LOCK(output_lock_); | 263 AUTO_LOCK(output_lock_); |
| 242 if (arg == NULL) { | 264 if (arg == NULL) { |
| 243 output_handler_.handler = NULL; | 265 output_handler_.handler = NULL; |
| 244 return 0; | 266 return 0; |
| 245 } | 267 } |
| 246 if (output_handler_.handler != NULL) | 268 if (output_handler_.handler != NULL) |
| 247 return EALREADY; | 269 return EALREADY; |
| 248 output_handler_ = *arg; | 270 output_handler_ = *arg; |
| 249 return 0; | 271 return 0; |
| 250 } | 272 } |
| 251 case TIOCNACLINPUT: { | 273 case NACL_IOC_HANDLEMESSAGE: { |
| 252 // This ioctl is used to deliver data from the user to this tty node's | 274 struct PP_Var* message = va_arg(args, struct PP_Var*); |
| 253 // input buffer. | 275 return ProcessInput(*message); |
| 254 struct tioc_nacl_input_string* message = | |
| 255 va_arg(args, struct tioc_nacl_input_string*); | |
| 256 return ProcessInput(message); | |
| 257 } | 276 } |
| 258 case TIOCSWINSZ: { | 277 case TIOCSWINSZ: { |
| 259 struct winsize* size = va_arg(args, struct winsize*); | 278 struct winsize* size = va_arg(args, struct winsize*); |
| 260 { | 279 { |
| 261 AUTO_LOCK(node_lock_); | 280 AUTO_LOCK(node_lock_); |
| 262 if (rows_ == size->ws_row && cols_ == size->ws_col) | 281 if (rows_ == size->ws_row && cols_ == size->ws_col) |
| 263 return 0; | 282 return 0; |
| 264 rows_ = size->ws_row; | 283 rows_ = size->ws_row; |
| 265 cols_ = size->ws_col; | 284 cols_ = size->ws_col; |
| 266 } | 285 } |
| 267 ki_kill(getpid(), SIGWINCH); | 286 ki_kill(getpid(), SIGWINCH); |
| 268 { | 287 { |
| 269 // Wake up any thread waiting on Read with POLLERR then immediate | 288 // Wake up any thread waiting on Read with POLLERR then immediate |
| 270 // clear it to signal EINTR. | 289 // clear it to signal EINTR. |
| 271 AUTO_LOCK(emitter_->GetLock()) | 290 AUTO_LOCK(emitter_->GetLock()) |
| 272 emitter_->RaiseEvents_Locked(POLLERR); | 291 emitter_->RaiseEvents_Locked(POLLERR); |
| 273 emitter_->ClearEvents_Locked(POLLERR); | 292 emitter_->ClearEvents_Locked(POLLERR); |
| 274 } | 293 } |
| 275 return 0; | 294 return 0; |
| 276 } | 295 } |
| 277 case TIOCGWINSZ: { | 296 case TIOCGWINSZ: { |
| 278 struct winsize* size = va_arg(args, struct winsize*); | 297 struct winsize* size = va_arg(args, struct winsize*); |
| 279 size->ws_row = rows_; | 298 size->ws_row = rows_; |
| 280 size->ws_col = cols_; | 299 size->ws_col = cols_; |
| 281 return 0; | 300 return 0; |
| 282 } | 301 } |
| 302 default: { |
| 303 LOG_ERROR("TtyNode:VIoctl: Unknown request: %#x", request); |
| 304 } |
| 283 } | 305 } |
| 284 | 306 |
| 285 return EINVAL; | 307 return EINVAL; |
| 286 } | 308 } |
| 287 | 309 |
| 288 Error TtyNode::Tcgetattr(struct termios* termios_p) { | 310 Error TtyNode::Tcgetattr(struct termios* termios_p) { |
| 289 AUTO_LOCK(node_lock_); | 311 AUTO_LOCK(node_lock_); |
| 290 *termios_p = termios_; | 312 *termios_p = termios_; |
| 291 return 0; | 313 return 0; |
| 292 } | 314 } |
| 293 | 315 |
| 294 Error TtyNode::Tcsetattr(int optional_actions, | 316 Error TtyNode::Tcsetattr(int optional_actions, |
| 295 const struct termios* termios_p) { | 317 const struct termios* termios_p) { |
| 296 AUTO_LOCK(node_lock_); | 318 AUTO_LOCK(node_lock_); |
| 297 termios_ = *termios_p; | 319 termios_ = *termios_p; |
| 298 return 0; | 320 return 0; |
| 299 } | 321 } |
| 300 | 322 |
| 301 } // namespace nacl_io | 323 } // namespace nacl_io |
| OLD | NEW |