Home | History | Annotate | Download | only in devfs
      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