1// Copyright (c) 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 <errno.h> 10#include <fcntl.h> 11#include <pthread.h> 12#include <string.h> 13 14#include "nacl_io/kernel_wrap_real.h" 15#include "nacl_io/mount_dev.h" 16#include "nacl_io/mount_node.h" 17#include "nacl_io/mount_node_dir.h" 18#include "nacl_io/mount_node_tty.h" 19#include "nacl_io/osunistd.h" 20#include "nacl_io/pepper_interface.h" 21#include "sdk_util/auto_lock.h" 22 23#if defined(__native_client__) 24#include <irt.h> 25#elif defined(WIN32) 26#include <stdlib.h> 27#endif 28 29namespace nacl_io { 30 31namespace { 32 33class RealNode : public MountNode { 34 public: 35 RealNode(Mount* mount, int fd); 36 37 virtual Error Read(size_t offs, void* buf, size_t count, int* out_bytes); 38 virtual Error Write(size_t offs, 39 const void* buf, 40 size_t count, 41 int* out_bytes); 42 virtual Error GetStat(struct stat* stat); 43 44 protected: 45 int fd_; 46}; 47 48class NullNode : public MountNodeCharDevice { 49 public: 50 explicit NullNode(Mount* mount) : MountNodeCharDevice(mount) {} 51 52 virtual Error Read(size_t offs, void* buf, size_t count, int* out_bytes); 53 virtual Error Write(size_t offs, 54 const void* buf, 55 size_t count, 56 int* out_bytes); 57}; 58 59class ConsoleNode : public MountNodeCharDevice { 60 public: 61 ConsoleNode(Mount* mount, PP_LogLevel level); 62 63 virtual Error Write(size_t offs, 64 const void* buf, 65 size_t count, 66 int* out_bytes); 67 68 private: 69 PP_LogLevel level_; 70}; 71 72class ZeroNode : public MountNode { 73 public: 74 explicit ZeroNode(Mount* mount); 75 76 virtual Error Read(size_t offs, void* buf, size_t count, int* out_bytes); 77 virtual Error Write(size_t offs, 78 const void* buf, 79 size_t count, 80 int* out_bytes); 81}; 82 83class UrandomNode : public MountNode { 84 public: 85 explicit UrandomNode(Mount* mount); 86 87 virtual Error Read(size_t offs, void* buf, size_t count, int* out_bytes); 88 virtual Error Write(size_t offs, 89 const void* buf, 90 size_t count, 91 int* out_bytes); 92 93 private: 94#if defined(__native_client__) 95 nacl_irt_random random_interface_; 96 bool interface_ok_; 97#endif 98}; 99 100RealNode::RealNode(Mount* mount, int fd) : MountNode(mount), fd_(fd) { 101 stat_.st_mode = S_IFCHR; 102} 103 104Error RealNode::Read(size_t offs, void* buf, size_t count, int* out_bytes) { 105 *out_bytes = 0; 106 107 size_t readcnt; 108 int err = _real_read(fd_, buf, count, &readcnt); 109 if (err) 110 return err; 111 112 *out_bytes = static_cast<int>(readcnt); 113 return 0; 114} 115 116Error RealNode::Write(size_t offs, 117 const void* buf, 118 size_t count, 119 int* out_bytes) { 120 *out_bytes = 0; 121 122 size_t writecnt; 123 int err = _real_write(fd_, buf, count, &writecnt); 124 if (err) 125 return err; 126 127 *out_bytes = static_cast<int>(writecnt); 128 return 0; 129} 130 131Error RealNode::GetStat(struct stat* stat) { return _real_fstat(fd_, stat); } 132 133Error NullNode::Read(size_t offs, void* buf, size_t count, int* out_bytes) { 134 *out_bytes = 0; 135 return 0; 136} 137 138Error NullNode::Write(size_t offs, 139 const void* buf, 140 size_t count, 141 int* out_bytes) { 142 *out_bytes = count; 143 return 0; 144} 145 146ConsoleNode::ConsoleNode(Mount* mount, PP_LogLevel level) 147 : MountNodeCharDevice(mount), level_(level) { 148} 149 150Error ConsoleNode::Write(size_t offs, 151 const void* buf, 152 size_t count, 153 int* out_bytes) { 154 *out_bytes = 0; 155 156 ConsoleInterface* con_intr = mount_->ppapi()->GetConsoleInterface(); 157 VarInterface* var_intr = mount_->ppapi()->GetVarInterface(); 158 159 if (!(var_intr && con_intr)) 160 return ENOSYS; 161 162 const char* data = static_cast<const char*>(buf); 163 uint32_t len = static_cast<uint32_t>(count); 164 struct PP_Var val = var_intr->VarFromUtf8(data, len); 165 con_intr->Log(mount_->ppapi()->GetInstance(), level_, val); 166 167 *out_bytes = count; 168 return 0; 169} 170 171ZeroNode::ZeroNode(Mount* mount) : MountNode(mount) { stat_.st_mode = S_IFCHR; } 172 173Error ZeroNode::Read(size_t offs, void* buf, size_t count, int* out_bytes) { 174 memset(buf, 0, count); 175 *out_bytes = count; 176 return 0; 177} 178 179Error ZeroNode::Write(size_t offs, 180 const void* buf, 181 size_t count, 182 int* out_bytes) { 183 *out_bytes = count; 184 return 0; 185} 186 187UrandomNode::UrandomNode(Mount* mount) : MountNode(mount) { 188 stat_.st_mode = S_IFCHR; 189#if defined(__native_client__) 190 size_t result = nacl_interface_query( 191 NACL_IRT_RANDOM_v0_1, &random_interface_, sizeof(random_interface_)); 192 interface_ok_ = result != 0; 193#endif 194} 195 196Error UrandomNode::Read(size_t offs, void* buf, size_t count, int* out_bytes) { 197 *out_bytes = 0; 198 199#if defined(__native_client__) 200 if (!interface_ok_) 201 return EBADF; 202 203 size_t nread; 204 int error = (*random_interface_.get_random_bytes)(buf, count, &nread); 205 if (error) 206 return error; 207 208 *out_bytes = count; 209 return 0; 210#elif defined(WIN32) 211 char* out = static_cast<char*>(buf); 212 size_t bytes_left = count; 213 while (bytes_left) { 214 unsigned int random_int; 215 errno_t err = rand_s(&random_int); 216 if (err) { 217 *out_bytes = count - bytes_left; 218 return err; 219 } 220 221 int bytes_to_copy = std::min(bytes_left, sizeof(random_int)); 222 memcpy(out, &random_int, bytes_to_copy); 223 out += bytes_to_copy; 224 bytes_left -= bytes_to_copy; 225 } 226 227 *out_bytes = count; 228 return 0; 229#endif 230} 231 232Error UrandomNode::Write(size_t offs, 233 const void* buf, 234 size_t count, 235 int* out_bytes) { 236 *out_bytes = count; 237 return 0; 238} 239 240} // namespace 241 242Error MountDev::Access(const Path& path, int a_mode) { 243 ScopedMountNode node; 244 int error = root_->FindChild(path.Join(), &node); 245 if (error) 246 return error; 247 248 // Don't allow execute access. 249 if (a_mode & X_OK) 250 return EACCES; 251 252 return 0; 253} 254 255Error MountDev::Open(const Path& path, int mode, ScopedMountNode* out_node) { 256 out_node->reset(NULL); 257 258 // Don't allow creating any files. 259 if (mode & O_CREAT) 260 return EINVAL; 261 262 return root_->FindChild(path.Join(), out_node); 263} 264 265Error MountDev::Unlink(const Path& path) { return EINVAL; } 266 267Error MountDev::Mkdir(const Path& path, int permissions) { return EINVAL; } 268 269Error MountDev::Rmdir(const Path& path) { return EINVAL; } 270 271Error MountDev::Remove(const Path& path) { return EINVAL; } 272 273MountDev::MountDev() {} 274 275#define INITIALIZE_DEV_NODE(path, klass) \ 276 error = root_->AddChild(path, ScopedMountNode(new klass(this))); \ 277 if (error) \ 278 return error; 279 280#define INITIALIZE_DEV_NODE_1(path, klass, arg) \ 281 error = root_->AddChild(path, ScopedMountNode(new klass(this, arg))); \ 282 if (error) \ 283 return error; 284 285Error MountDev::Init(int dev, StringMap_t& args, PepperInterface* ppapi) { 286 Error error = Mount::Init(dev, args, ppapi); 287 if (error) 288 return error; 289 290 root_.reset(new MountNodeDir(this)); 291 292 INITIALIZE_DEV_NODE("/null", NullNode); 293 INITIALIZE_DEV_NODE("/zero", ZeroNode); 294 INITIALIZE_DEV_NODE("/urandom", UrandomNode); 295 INITIALIZE_DEV_NODE_1("/console0", ConsoleNode, PP_LOGLEVEL_TIP); 296 INITIALIZE_DEV_NODE_1("/console1", ConsoleNode, PP_LOGLEVEL_LOG); 297 INITIALIZE_DEV_NODE_1("/console2", ConsoleNode, PP_LOGLEVEL_WARNING); 298 INITIALIZE_DEV_NODE_1("/console3", ConsoleNode, PP_LOGLEVEL_ERROR); 299 INITIALIZE_DEV_NODE("/tty", MountNodeTty); 300 INITIALIZE_DEV_NODE_1("/stdin", RealNode, 0); 301 INITIALIZE_DEV_NODE_1("/stdout", RealNode, 1); 302 INITIALIZE_DEV_NODE_1("/stderr", RealNode, 2); 303 304 return 0; 305} 306 307} // namespace nacl_io 308 309