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