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