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.
9 #include "nacl_io/devfs/dev_fs.h"
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"
27 #if defined(__native_client__)
37 class NullNode
: public CharNode
{
39 explicit NullNode(Filesystem
* filesystem
) : CharNode(filesystem
) {}
41 virtual Error
Read(const HandleAttr
& attr
,
45 virtual Error
Write(const HandleAttr
& attr
,
51 class ConsoleNode
: public CharNode
{
53 ConsoleNode(Filesystem
* filesystem
, PP_LogLevel level
);
55 virtual Error
Write(const HandleAttr
& attr
,
64 class ZeroNode
: public Node
{
66 explicit ZeroNode(Filesystem
* filesystem
);
68 virtual Error
Read(const HandleAttr
& attr
,
72 virtual Error
Write(const HandleAttr
& attr
,
78 class UrandomNode
: public Node
{
80 explicit UrandomNode(Filesystem
* filesystem
);
82 virtual Error
Read(const HandleAttr
& attr
,
86 virtual Error
Write(const HandleAttr
& attr
,
92 #if defined(__native_client__)
93 nacl_irt_random random_interface_
;
98 class FsNode
: public Node
{
100 FsNode(Filesystem
* filesystem
, Filesystem
* other_fs
);
102 virtual Error
VIoctl(int request
, va_list args
);
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_
;
111 Error
NullNode::Read(const HandleAttr
& attr
,
119 Error
NullNode::Write(const HandleAttr
& attr
,
127 ConsoleNode::ConsoleNode(Filesystem
* filesystem
, PP_LogLevel level
)
128 : CharNode(filesystem
), level_(level
) {
131 Error
ConsoleNode::Write(const HandleAttr
& attr
,
137 ConsoleInterface
* con_iface
= filesystem_
->ppapi()->GetConsoleInterface();
138 VarInterface
* var_iface
= filesystem_
->ppapi()->GetVarInterface();
140 if (!(var_iface
&& con_iface
)) {
141 LOG_ERROR("Got NULL interface(s): %s%s",
142 con_iface
? "" : "Console ",
143 var_iface
? "" : "Var");
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
);
157 ZeroNode::ZeroNode(Filesystem
* filesystem
) : Node(filesystem
) {
161 Error
ZeroNode::Read(const HandleAttr
& attr
,
165 memset(buf
, 0, count
);
170 Error
ZeroNode::Write(const HandleAttr
& attr
,
178 UrandomNode::UrandomNode(Filesystem
* filesystem
) : Node(filesystem
) {
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;
187 Error
UrandomNode::Read(const HandleAttr
& attr
,
193 #if defined(__native_client__)
194 if (!interface_ok_
) {
195 LOG_ERROR("NACL_IRT_RANDOM_v0_1 interface not avaiable.");
200 int error
= (*random_interface_
.get_random_bytes
)(buf
, count
, &nread
);
204 char* out
= static_cast<char*>(buf
);
205 size_t bytes_left
= count
;
207 unsigned int random_int
;
208 errno_t err
= rand_s(&random_int
);
210 *out_bytes
= count
- bytes_left
;
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
;
225 Error
UrandomNode::Write(const HandleAttr
& attr
,
233 FsNode::FsNode(Filesystem
* filesystem
, Filesystem
* other_fs
)
234 : Node(filesystem
), other_fs_(other_fs
) {
237 Error
FsNode::VIoctl(int request
, va_list args
) {
238 return other_fs_
->Filesystem_VIoctl(request
, args
);
243 Error
DevFs::OpenWithMode(const Path
& path
, int open_flags
,
244 mode_t mode
, ScopedNode
* out_node
) {
245 out_node
->reset(NULL
);
247 if (path
.Part(1) == "fs") {
248 if (path
.Size() == 3) {
249 error
= fs_dir_
->FindChild(path
.Part(2), out_node
);
251 LOG_TRACE("Bad devfs path: %s", path
.Join().c_str());
255 error
= root_
->FindChild(path
.Join(), out_node
);
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());
267 Error
DevFs::Unlink(const Path
& path
) {
268 LOG_ERROR("unlink not supported.");
272 Error
DevFs::Mkdir(const Path
& path
, int permissions
) {
273 LOG_ERROR("mkdir not supported.");
277 Error
DevFs::Rmdir(const Path
& path
) {
278 LOG_ERROR("rmdir not supported.");
282 Error
DevFs::Remove(const Path
& path
) {
283 LOG_ERROR("remove not supported.");
287 Error
DevFs::Rename(const Path
& path
, const Path
& newpath
) {
288 LOG_ERROR("rename not supported.");
292 Error
DevFs::CreateFsNode(Filesystem
* other_fs
) {
293 int dev
= other_fs
->dev();
295 snprintf(path
, 32, "%d", dev
);
296 ScopedNode
new_node(new FsNode(this, other_fs
));
297 return fs_dir_
->AddChild(path
, new_node
);
300 Error
DevFs::DestroyFsNode(Filesystem
* other_fs
) {
301 int dev
= other_fs
->dev();
303 snprintf(path
, 32, "%d", dev
);
304 return fs_dir_
->RemoveChild(path
);
310 #define INITIALIZE_DEV_NODE(path, klass) \
311 new_node = ScopedNode(new klass(this)); \
312 error = root_->AddChild(path, new_node); \
316 #define INITIALIZE_DEV_NODE_1(path, klass, arg) \
317 new_node = ScopedNode(new klass(this, arg)); \
318 error = root_->AddChild(path, new_node); \
322 Error
DevFs::Init(const FsInitArgs
& args
) {
323 Error error
= Filesystem::Init(args
);
327 root_
.reset(new DirNode(this, S_IRALL
| S_IXALL
));
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");
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_1("/fs", DirNode
, S_IRALL
| S_IWALL
| S_IXALL
);
357 } // namespace nacl_io