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. 4 5 #if defined(WIN32) 6 #define _CRT_RAND_S 7 #endif 8 9 #include "nacl_io/devfs/dev_fs.h" 10 11 #include <errno.h> 12 #include <fcntl.h> 13 #include <pthread.h> 14 #include <stdio.h> 15 #include <string.h> 16 17 #include "nacl_io/devfs/jspipe_node.h" 18 #include "nacl_io/devfs/tty_node.h" 19 #include "nacl_io/dir_node.h" 20 #include "nacl_io/kernel_wrap_real.h" 21 #include "nacl_io/node.h" 22 #include "nacl_io/osunistd.h" 23 #include "nacl_io/passthroughfs/real_node.h" 24 #include "nacl_io/pepper_interface.h" 25 #include "sdk_util/auto_lock.h" 26 27 #if defined(__native_client__) 28 #include <irt.h> 29 #elif defined(WIN32) 30 #include <stdlib.h> 31 #endif 32 33 namespace nacl_io { 34 35 namespace { 36 37 class NullNode : public CharNode { 38 public: 39 explicit NullNode(Filesystem* filesystem) : CharNode(filesystem) {} 40 41 virtual Error Read(const HandleAttr& attr, 42 void* buf, 43 size_t count, 44 int* out_bytes); 45 virtual Error Write(const HandleAttr& attr, 46 const void* buf, 47 size_t count, 48 int* out_bytes); 49 }; 50 51 class ConsoleNode : public CharNode { 52 public: 53 ConsoleNode(Filesystem* filesystem, PP_LogLevel level); 54 55 virtual Error Write(const HandleAttr& attr, 56 const void* buf, 57 size_t count, 58 int* out_bytes); 59 60 private: 61 PP_LogLevel level_; 62 }; 63 64 class ZeroNode : public Node { 65 public: 66 explicit ZeroNode(Filesystem* filesystem); 67 68 virtual Error Read(const HandleAttr& attr, 69 void* buf, 70 size_t count, 71 int* out_bytes); 72 virtual Error Write(const HandleAttr& attr, 73 const void* buf, 74 size_t count, 75 int* out_bytes); 76 }; 77 78 class UrandomNode : public Node { 79 public: 80 explicit UrandomNode(Filesystem* filesystem); 81 82 virtual Error Read(const HandleAttr& attr, 83 void* buf, 84 size_t count, 85 int* out_bytes); 86 virtual Error Write(const HandleAttr& attr, 87 const void* buf, 88 size_t count, 89 int* out_bytes); 90 91 private: 92 #if defined(__native_client__) 93 nacl_irt_random random_interface_; 94 bool interface_ok_; 95 #endif 96 }; 97 98 class FsNode : public Node { 99 public: 100 FsNode(Filesystem* filesystem, Filesystem* other_fs); 101 102 virtual Error VIoctl(int request, va_list args); 103 104 private: 105 // Don't addref the filesystem. We are relying on the fact that the 106 // KernelObject will keep the filsystem around as long as we need it, and 107 // this node will be destroyed when the filesystem is destroyed. 108 Filesystem* other_fs_; 109 }; 110 111 Error NullNode::Read(const HandleAttr& attr, 112 void* buf, 113 size_t count, 114 int* out_bytes) { 115 *out_bytes = 0; 116 return 0; 117 } 118 119 Error NullNode::Write(const HandleAttr& attr, 120 const void* buf, 121 size_t count, 122 int* out_bytes) { 123 *out_bytes = count; 124 return 0; 125 } 126 127 ConsoleNode::ConsoleNode(Filesystem* filesystem, PP_LogLevel level) 128 : CharNode(filesystem), level_(level) { 129 } 130 131 Error ConsoleNode::Write(const HandleAttr& attr, 132 const void* buf, 133 size_t count, 134 int* out_bytes) { 135 *out_bytes = 0; 136 137 ConsoleInterface* con_iface = filesystem_->ppapi()->GetConsoleInterface(); 138 VarInterface* var_iface = filesystem_->ppapi()->GetVarInterface(); 139 140 if (!(var_iface && con_iface)) { 141 LOG_ERROR("Got NULL interface(s): %s%s", 142 con_iface ? "" : "Console ", 143 var_iface ? "" : "Var"); 144 return ENOSYS; 145 } 146 147 const char* var_data = static_cast<const char*>(buf); 148 uint32_t len = static_cast<uint32_t>(count); 149 struct PP_Var val = var_iface->VarFromUtf8(var_data, len); 150 con_iface->Log(filesystem_->ppapi()->GetInstance(), level_, val); 151 var_iface->Release(val); 152 153 *out_bytes = count; 154 return 0; 155 } 156 157 ZeroNode::ZeroNode(Filesystem* filesystem) : Node(filesystem) { 158 SetType(S_IFCHR); 159 } 160 161 Error ZeroNode::Read(const HandleAttr& attr, 162 void* buf, 163 size_t count, 164 int* out_bytes) { 165 memset(buf, 0, count); 166 *out_bytes = count; 167 return 0; 168 } 169 170 Error ZeroNode::Write(const HandleAttr& attr, 171 const void* buf, 172 size_t count, 173 int* out_bytes) { 174 *out_bytes = count; 175 return 0; 176 } 177 178 UrandomNode::UrandomNode(Filesystem* filesystem) : Node(filesystem) { 179 SetType(S_IFCHR); 180 #if defined(__native_client__) 181 size_t result = nacl_interface_query( 182 NACL_IRT_RANDOM_v0_1, &random_interface_, sizeof(random_interface_)); 183 interface_ok_ = result != 0; 184 #endif 185 } 186 187 Error UrandomNode::Read(const HandleAttr& attr, 188 void* buf, 189 size_t count, 190 int* out_bytes) { 191 *out_bytes = 0; 192 193 #if defined(__native_client__) 194 if (!interface_ok_) { 195 LOG_ERROR("NACL_IRT_RANDOM_v0_1 interface not avaiable."); 196 return EBADF; 197 } 198 199 size_t nread; 200 int error = (*random_interface_.get_random_bytes)(buf, count, &nread); 201 if (error) 202 return error; 203 #elif defined(WIN32) 204 char* out = static_cast<char*>(buf); 205 size_t bytes_left = count; 206 while (bytes_left) { 207 unsigned int random_int; 208 errno_t err = rand_s(&random_int); 209 if (err) { 210 *out_bytes = count - bytes_left; 211 return err; 212 } 213 214 int bytes_to_copy = std::min(bytes_left, sizeof(random_int)); 215 memcpy(out, &random_int, bytes_to_copy); 216 out += bytes_to_copy; 217 bytes_left -= bytes_to_copy; 218 } 219 #endif 220 221 *out_bytes = count; 222 return 0; 223 } 224 225 Error UrandomNode::Write(const HandleAttr& attr, 226 const void* buf, 227 size_t count, 228 int* out_bytes) { 229 *out_bytes = count; 230 return 0; 231 } 232 233 FsNode::FsNode(Filesystem* filesystem, Filesystem* other_fs) 234 : Node(filesystem), other_fs_(other_fs) { 235 } 236 237 Error FsNode::VIoctl(int request, va_list args) { 238 return other_fs_->Filesystem_VIoctl(request, args); 239 } 240 241 } // namespace 242 243 Error DevFs::OpenWithMode(const Path& path, int open_flags, 244 mode_t mode, ScopedNode* out_node) { 245 out_node->reset(NULL); 246 int error; 247 if (path.Part(1) == "fs") { 248 if (path.Size() == 3) { 249 error = fs_dir_->FindChild(path.Part(2), out_node); 250 } else { 251 LOG_TRACE("Bad devfs path: %s", path.Join().c_str()); 252 error = ENOENT; 253 } 254 } else { 255 error = root_->FindChild(path.Join(), out_node); 256 } 257 258 // Only return EACCES when trying to create a node that does not exist. 259 if ((error == ENOENT) && (open_flags & O_CREAT)) { 260 LOG_TRACE("Cannot create devfs node: %s", path.Join().c_str()); 261 return EACCES; 262 } 263 264 return error; 265 } 266 267 Error DevFs::Unlink(const Path& path) { 268 LOG_ERROR("unlink not supported."); 269 return EPERM; 270 } 271 272 Error DevFs::Mkdir(const Path& path, int permissions) { 273 LOG_ERROR("mkdir not supported."); 274 return EPERM; 275 } 276 277 Error DevFs::Rmdir(const Path& path) { 278 LOG_ERROR("rmdir not supported."); 279 return EPERM; 280 } 281 282 Error DevFs::Remove(const Path& path) { 283 LOG_ERROR("remove not supported."); 284 return EPERM; 285 } 286 287 Error DevFs::Rename(const Path& path, const Path& newpath) { 288 LOG_ERROR("rename not supported."); 289 return EPERM; 290 } 291 292 Error DevFs::CreateFsNode(Filesystem* other_fs) { 293 int dev = other_fs->dev(); 294 char path[32]; 295 snprintf(path, 32, "%d", dev); 296 ScopedNode new_node(new FsNode(this, other_fs)); 297 return fs_dir_->AddChild(path, new_node); 298 } 299 300 Error DevFs::DestroyFsNode(Filesystem* other_fs) { 301 int dev = other_fs->dev(); 302 char path[32]; 303 snprintf(path, 32, "%d", dev); 304 return fs_dir_->RemoveChild(path); 305 } 306 307 DevFs::DevFs() { 308 } 309 310 #define INITIALIZE_DEV_NODE(path, klass) \ 311 new_node = ScopedNode(new klass(this)); \ 312 error = root_->AddChild(path, new_node); \ 313 if (error) \ 314 return error; 315 316 #define INITIALIZE_DEV_NODE_1(path, klass, arg) \ 317 new_node = ScopedNode(new klass(this, arg)); \ 318 error = root_->AddChild(path, new_node); \ 319 if (error) \ 320 return error; 321 322 Error DevFs::Init(const FsInitArgs& args) { 323 Error error = Filesystem::Init(args); 324 if (error) 325 return error; 326 327 root_.reset(new DirNode(this)); 328 329 ScopedNode new_node; 330 INITIALIZE_DEV_NODE("/null", NullNode); 331 INITIALIZE_DEV_NODE("/zero", ZeroNode); 332 INITIALIZE_DEV_NODE("/urandom", UrandomNode); 333 INITIALIZE_DEV_NODE_1("/console0", ConsoleNode, PP_LOGLEVEL_TIP); 334 INITIALIZE_DEV_NODE_1("/console1", ConsoleNode, PP_LOGLEVEL_LOG); 335 INITIALIZE_DEV_NODE_1("/console2", ConsoleNode, PP_LOGLEVEL_WARNING); 336 INITIALIZE_DEV_NODE_1("/console3", ConsoleNode, PP_LOGLEVEL_ERROR); 337 INITIALIZE_DEV_NODE("/tty", TtyNode); 338 INITIALIZE_DEV_NODE_1("/stdin", RealNode, 0); 339 INITIALIZE_DEV_NODE_1("/stdout", RealNode, 1); 340 INITIALIZE_DEV_NODE_1("/stderr", RealNode, 2); 341 INITIALIZE_DEV_NODE("/jspipe1", JSPipeNode); 342 new_node->Ioctl(NACL_IOC_PIPE_SETNAME, "jspipe1"); 343 INITIALIZE_DEV_NODE("/jspipe2", JSPipeNode); 344 new_node->Ioctl(NACL_IOC_PIPE_SETNAME, "jspipe2"); 345 INITIALIZE_DEV_NODE("/jspipe3", JSPipeNode); 346 new_node->Ioctl(NACL_IOC_PIPE_SETNAME, "jspipe3"); 347 348 // Add a directory for "fs" nodes; they represent all currently-mounted 349 // filesystems. We can ioctl these nodes to make changes or provide input to 350 // a mounted filesystem. 351 INITIALIZE_DEV_NODE("/fs", DirNode); 352 fs_dir_ = new_node; 353 354 return 0; 355 } 356 357 } // namespace nacl_io 358