kernel_proxy.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "nacl_io/kernel_proxy.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <assert.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <pthread.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <iterator>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "nacl_io/kernel_handle.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "nacl_io/kernel_wrap_real.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "nacl_io/mount.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "nacl_io/mount_dev.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "nacl_io/mount_html5fs.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "nacl_io/mount_http.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "nacl_io/mount_mem.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "nacl_io/mount_node.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "nacl_io/mount_passthrough.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "nacl_io/osmman.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "nacl_io/osstat.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "nacl_io/path.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "nacl_io/pepper_interface.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "nacl_io/typed_mount_factory.h"
290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "sdk_util/auto_lock.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sdk_util/ref_object.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef MAXPATHLEN
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define MAXPATHLEN 256
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(noelallen) : Grab/Redefine these in the kernel object once available.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define USR_ID 1002
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define GRP_ID 1003
39
40KernelProxy::KernelProxy() : dev_(0), ppapi_(NULL) {}
41
42KernelProxy::~KernelProxy() {
43  // Clean up the MountFactories.
44  for (MountFactoryMap_t::iterator i = factories_.begin();
45       i != factories_.end();
46       ++i) {
47    delete i->second;
48  }
49
50  delete ppapi_;
51}
52
53void KernelProxy::Init(PepperInterface* ppapi) {
54  ppapi_ = ppapi;
55  cwd_ = "/";
56  dev_ = 1;
57
58  factories_["memfs"] = new TypedMountFactory<MountMem>;
59  factories_["dev"] = new TypedMountFactory<MountDev>;
60  factories_["html5fs"] = new TypedMountFactory<MountHtml5Fs>;
61  factories_["httpfs"] = new TypedMountFactory<MountHttp>;
62  factories_["passthroughfs"] = new TypedMountFactory<MountPassthrough>;
63
64  int result;
65  result = mount("", "/", "passthroughfs", 0, NULL);
66  assert(result == 0);
67
68  result = mount("", "/dev", "dev", 0, NULL);
69  assert(result == 0);
70
71  // Open the first three in order to get STDIN, STDOUT, STDERR
72  open("/dev/stdin", O_RDONLY);
73  open("/dev/stdout", O_WRONLY);
74  open("/dev/stderr", O_WRONLY);
75}
76
77int KernelProxy::open(const char* path, int oflags) {
78  Path rel;
79
80  ScopedMount mnt;
81  Error error = AcquireMountAndPath(path, &mnt, &rel);
82  if (error) {
83    errno = error;
84    return -1;
85  }
86
87  ScopedMountNode node;
88  error = mnt->Open(rel, oflags, &node);
89  if (error) {
90    errno = error;
91    return -1;
92  }
93
94  ScopedKernelHandle handle(new KernelHandle(mnt, node));
95  error = handle->Init(oflags);
96  if (error) {
97    errno = error;
98    return -1;
99  }
100
101  return AllocateFD(handle);
102}
103
104int KernelProxy::close(int fd) {
105  ScopedKernelHandle handle;
106  Error error = AcquireHandle(fd, &handle);
107  if (error) {
108    errno = error;
109    return -1;
110  }
111
112  // Remove the FD from the process open file descriptor map
113  FreeFD(fd);
114  return 0;
115}
116
117int KernelProxy::dup(int oldfd) {
118  ScopedKernelHandle handle;
119  Error error = AcquireHandle(oldfd, &handle);
120  if (error) {
121    errno = error;
122    return -1;
123  }
124
125  return AllocateFD(handle);
126}
127
128int KernelProxy::dup2(int oldfd, int newfd) {
129  // If it's the same file handle, just return
130  if (oldfd == newfd)
131    return newfd;
132
133  ScopedKernelHandle old_handle;
134  Error error = AcquireHandle(oldfd, &old_handle);
135  if (error) {
136    errno = error;
137    return -1;
138  }
139
140  FreeAndReassignFD(newfd, old_handle);
141  return newfd;
142}
143
144char* KernelProxy::getcwd(char* buf, size_t size) {
145  AutoLock lock(&process_lock_);
146  if (size <= 0) {
147    errno = EINVAL;
148    return NULL;
149  }
150  // If size is 0, allocate as much as we need.
151  if (size == 0) {
152    size = cwd_.size() + 1;
153  }
154
155  // Verify the buffer is large enough
156  if (size <= cwd_.size()) {
157    errno = ERANGE;
158    return NULL;
159  }
160
161  // Allocate the buffer if needed
162  if (buf == NULL) {
163    buf = static_cast<char*>(malloc(size));
164  }
165
166  strcpy(buf, cwd_.c_str());
167  return buf;
168}
169
170char* KernelProxy::getwd(char* buf) {
171  if (NULL == buf) {
172    errno = EFAULT;
173    return NULL;
174  }
175  return getcwd(buf, MAXPATHLEN);
176}
177
178int KernelProxy::chmod(const char* path, mode_t mode) {
179  int fd = KernelProxy::open(path, O_RDONLY);
180  if (-1 == fd)
181    return -1;
182
183  int result = fchmod(fd, mode);
184  close(fd);
185  return result;
186}
187
188int KernelProxy::chown(const char* path, uid_t owner, gid_t group) {
189  return 0;
190}
191
192int KernelProxy::fchown(int fd, uid_t owner, gid_t group) {
193  return 0;
194}
195
196int KernelProxy::lchown(const char* path, uid_t owner, gid_t group) {
197  return 0;
198}
199
200int KernelProxy::utime(const char* filename, const struct utimbuf* times) {
201  return 0;
202}
203
204int KernelProxy::mkdir(const char* path, mode_t mode) {
205  ScopedMount mnt;
206  Path rel;
207  Error error = AcquireMountAndPath(path, &mnt, &rel);
208  if (error) {
209    errno = error;
210    return -1;
211  }
212
213  error = mnt->Mkdir(rel, mode);
214  if (error) {
215    errno = error;
216    return -1;
217  }
218
219  return 0;
220}
221
222int KernelProxy::rmdir(const char* path) {
223  ScopedMount mnt;
224  Path rel;
225  Error error = AcquireMountAndPath(path, &mnt, &rel);
226  if (error) {
227    errno = error;
228    return -1;
229  }
230
231  error = mnt->Rmdir(rel);
232  if (error) {
233    errno = error;
234    return -1;
235  }
236
237  return 0;
238}
239
240int KernelProxy::stat(const char* path, struct stat* buf) {
241  int fd = open(path, O_RDONLY);
242  if (-1 == fd)
243    return -1;
244
245  int result = fstat(fd, buf);
246  close(fd);
247  return result;
248}
249
250int KernelProxy::chdir(const char* path) {
251  struct stat statbuf;
252  if (stat(path, &statbuf) == -1)
253    return -1;
254
255  bool is_dir = (statbuf.st_mode & S_IFDIR) != 0;
256  if (!is_dir) {
257    errno = ENOTDIR;
258    return -1;
259  }
260
261  AutoLock lock(&process_lock_);
262  cwd_ = GetAbsPathLocked(path).Join();
263  return 0;
264}
265
266int KernelProxy::mount(const char* source,
267                       const char* target,
268                       const char* filesystemtype,
269                       unsigned long mountflags,
270                       const void* data) {
271  // See if it's already mounted
272  std::string abs_targ;
273
274  // Scope this lock to prevent holding both process and kernel locks
275  {
276    AutoLock lock(&process_lock_);
277    abs_targ = GetAbsPathLocked(target).Join();
278  }
279
280  AutoLock lock(&kernel_lock_);
281  if (mounts_.find(abs_targ) != mounts_.end()) {
282    errno = EBUSY;
283    return -1;
284  }
285
286  // Find a factory of that type
287  MountFactoryMap_t::iterator factory = factories_.find(filesystemtype);
288  if (factory == factories_.end()) {
289    errno = ENODEV;
290    return -1;
291  }
292
293  StringMap_t smap;
294  smap["SOURCE"] = source;
295  smap["TARGET"] = abs_targ;
296
297  if (data) {
298    char* str = strdup(static_cast<const char*>(data));
299    char* ptr = strtok(str, ",");
300    char* val;
301    while (ptr != NULL) {
302      val = strchr(ptr, '=');
303      if (val) {
304        *val = 0;
305        smap[ptr] = val + 1;
306      } else {
307        smap[ptr] = "TRUE";
308      }
309      ptr = strtok(NULL, ",");
310    }
311    free(str);
312  }
313
314  Error error =
315      factory->second->CreateMount(dev_++, smap, ppapi_, &mounts_[abs_targ]);
316  if (error) {
317    errno = error;
318    return -1;
319  }
320
321  return 0;
322}
323
324int KernelProxy::umount(const char* path) {
325  Path abs_path;
326
327  // Scope this lock to prevent holding both process and kernel locks
328  {
329    AutoLock lock(&process_lock_);
330    abs_path = GetAbsPathLocked(path);
331  }
332
333  AutoLock lock(&kernel_lock_);
334  MountMap_t::iterator it = mounts_.find(abs_path.Join());
335
336  if (mounts_.end() == it) {
337    errno = EINVAL;
338    return -1;
339  }
340
341  if (it->second->RefCount() != 1) {
342    errno = EBUSY;
343    return -1;
344  }
345
346  mounts_.erase(it);
347  return 0;
348}
349
350ssize_t KernelProxy::read(int fd, void* buf, size_t nbytes) {
351  ScopedKernelHandle handle;
352  Error error = AcquireHandle(fd, &handle);
353  if (error) {
354    errno = error;
355    return -1;
356  }
357
358  AutoLock lock(&handle->lock_);
359  int cnt = 0;
360  error = handle->node_->Read(handle->offs_, buf, nbytes, &cnt);
361  if (error) {
362    errno = error;
363    return -1;
364  }
365
366  if (cnt > 0)
367    handle->offs_ += cnt;
368
369  return cnt;
370}
371
372ssize_t KernelProxy::write(int fd, const void* buf, size_t nbytes) {
373  ScopedKernelHandle handle;
374  Error error = AcquireHandle(fd, &handle);
375  if (error) {
376    errno = error;
377    return -1;
378  }
379
380  AutoLock lock(&handle->lock_);
381  int cnt = 0;
382  error = handle->node_->Write(handle->offs_, buf, nbytes, &cnt);
383  if (error) {
384    errno = error;
385    return -1;
386  }
387
388  if (cnt > 0)
389    handle->offs_ += cnt;
390
391  return cnt;
392}
393
394int KernelProxy::fstat(int fd, struct stat* buf) {
395  ScopedKernelHandle handle;
396  Error error = AcquireHandle(fd, &handle);
397  if (error) {
398    errno = error;
399    return -1;
400  }
401
402  error = handle->node_->GetStat(buf);
403  if (error) {
404    errno = error;
405    return -1;
406  }
407
408  return 0;
409}
410
411int KernelProxy::getdents(int fd, void* buf, unsigned int count) {
412  ScopedKernelHandle handle;
413  Error error = AcquireHandle(fd, &handle);
414  if (error) {
415    errno = error;
416    return -1;
417  }
418
419  AutoLock lock(&handle->lock_);
420  int cnt = 0;
421  error = handle->node_
422      ->GetDents(handle->offs_, static_cast<dirent*>(buf), count, &cnt);
423  if (error)
424    errno = error;
425
426  if (cnt > 0)
427    handle->offs_ += cnt;
428
429  return cnt;
430}
431
432int KernelProxy::ftruncate(int fd, off_t length) {
433  ScopedKernelHandle handle;
434  Error error = AcquireHandle(fd, &handle);
435  if (error) {
436    errno = error;
437    return -1;
438  }
439
440  error = handle->node_->FTruncate(length);
441  if (error) {
442    errno = error;
443    return -1;
444  }
445
446  return 0;
447}
448
449int KernelProxy::fsync(int fd) {
450  ScopedKernelHandle handle;
451  Error error = AcquireHandle(fd, &handle);
452  if (error) {
453    errno = error;
454    return -1;
455  }
456
457  error = handle->node_->FSync();
458  if (error) {
459    errno = error;
460    return -1;
461  }
462
463  return 0;
464}
465
466int KernelProxy::isatty(int fd) {
467  ScopedKernelHandle handle;
468  Error error = AcquireHandle(fd, &handle);
469  if (error) {
470    errno = error;
471    return -1;
472  }
473
474  error = handle->node_->IsaTTY();
475  if (error) {
476    errno = error;
477    return -1;
478  }
479
480  return 0;
481}
482
483int KernelProxy::ioctl(int d, int request, char* argp) {
484  ScopedKernelHandle handle;
485  Error error = AcquireHandle(d, &handle);
486  if (error) {
487    errno = error;
488    return -1;
489  }
490
491  error = handle->node_->Ioctl(request, argp);
492  if (error) {
493    errno = error;
494    return -1;
495  }
496
497  return 0;
498}
499
500off_t KernelProxy::lseek(int fd, off_t offset, int whence) {
501  ScopedKernelHandle handle;
502  Error error = AcquireHandle(fd, &handle);
503  if (error) {
504    errno = error;
505    return -1;
506  }
507
508  AutoLock lock(&handle->lock_);
509  off_t new_offset;
510  error = handle->Seek(offset, whence, &new_offset);
511  if (error) {
512    errno = error;
513    return -1;
514  }
515
516  return new_offset;
517}
518
519int KernelProxy::unlink(const char* path) {
520  ScopedMount mnt;
521  Path rel;
522  Error error = AcquireMountAndPath(path, &mnt, &rel);
523  if (error) {
524    errno = error;
525    return -1;
526  }
527
528  error = mnt->Unlink(rel);
529  if (error) {
530    errno = error;
531    return -1;
532  }
533
534  return 0;
535}
536
537int KernelProxy::remove(const char* path) {
538  ScopedMount mnt;
539  Path rel;
540  Error error = AcquireMountAndPath(path, &mnt, &rel);
541  if (error) {
542    errno = error;
543    return -1;
544  }
545
546  error = mnt->Remove(rel);
547  if (error) {
548    errno = error;
549    return -1;
550  }
551
552  return 0;
553}
554
555// TODO(noelallen): Needs implementation.
556int KernelProxy::fchmod(int fd, int mode) {
557  ScopedKernelHandle handle;
558  Error error = AcquireHandle(fd, &handle);
559  if (error) {
560    errno = error;
561    return -1;
562  }
563
564  return 0;
565}
566
567int KernelProxy::access(const char* path, int amode) {
568  Path rel;
569
570  ScopedMount mnt;
571  Error error = AcquireMountAndPath(path, &mnt, &rel);
572  if (error) {
573    errno = error;
574    return -1;
575  }
576
577  error = mnt->Access(rel, amode);
578  if (error) {
579    errno = error;
580    return -1;
581  }
582  return 0;
583}
584
585// TODO(noelallen): Needs implementation.
586int KernelProxy::link(const char* oldpath, const char* newpath) {
587  errno = EINVAL;
588  return -1;
589}
590
591int KernelProxy::symlink(const char* oldpath, const char* newpath) {
592  errno = EINVAL;
593  return -1;
594}
595
596void* KernelProxy::mmap(void* addr,
597                        size_t length,
598                        int prot,
599                        int flags,
600                        int fd,
601                        size_t offset) {
602  // We shouldn't be getting anonymous mmaps here.
603  assert((flags & MAP_ANONYMOUS) == 0);
604  assert(fd != -1);
605
606  ScopedKernelHandle handle;
607  Error error = AcquireHandle(fd, &handle);
608  if (error) {
609    errno = error;
610    return MAP_FAILED;
611  }
612
613  void* new_addr;
614  AutoLock lock(&handle->lock_);
615  error = handle->node_->MMap(addr, length, prot, flags, offset, &new_addr);
616  if (error) {
617    errno = error;
618    return MAP_FAILED;
619  }
620
621  return new_addr;
622}
623
624int KernelProxy::munmap(void* addr, size_t length) {
625  // NOTE: The comment below is from a previous discarded implementation that
626  // tracks mmap'd regions. For simplicity, we no longer do this; because we
627  // "snapshot" the contents of the file in mmap(), and don't support
628  // write-back or updating the mapped region when the file is written, holding
629  // on to the KernelHandle is pointless.
630  //
631  // If we ever do, these threading issues should be considered.
632
633  //
634  // WARNING: this function may be called by free().
635  //
636  // There is a potential deadlock scenario:
637  // Thread 1: open() -> takes lock1 -> free() -> takes lock2
638  // Thread 2: free() -> takes lock2 -> munmap() -> takes lock1
639  //
640  // Note that open() above could be any function that takes a lock that is
641  // shared with munmap (this includes munmap!)
642  //
643  // To prevent this, we avoid taking locks in munmap() that are used by other
644  // nacl_io functions that may call free. Specifically, we only take the
645  // mmap_lock, which is only shared with mmap() above. There is still a
646  // possibility of deadlock if mmap() or munmap() calls free(), so this is not
647  // allowed.
648  //
649  // Unfortunately, munmap still needs to acquire other locks; see the call to
650  // ReleaseHandle below which takes the process lock. This is safe as long as
651  // this is never executed from free() -- we can be reasonably sure this is
652  // true, because malloc only makes anonymous mmap() requests, and should only
653  // be munmapping those allocations. We never add to mmap_info_list_ for
654  // anonymous maps, so the unmap_list should always be empty when called from
655  // free().
656  return 0;
657}
658
659int KernelProxy::open_resource(const char* path) {
660  ScopedMount mnt;
661  Path rel;
662  Error error = AcquireMountAndPath(path, &mnt, &rel);
663  if (error) {
664    errno = error;
665    return -1;
666  }
667
668  ScopedMountNode node;
669  error = mnt->OpenResource(rel, &node);
670  if (error) {
671    // OpenResource failed, try Open().
672    error = mnt->Open(rel, O_RDONLY, &node);
673    if (error) {
674      errno = error;
675      return -1;
676    }
677  }
678
679  ScopedKernelHandle handle(new KernelHandle(mnt, node));
680  error = handle->Init(O_RDONLY);
681  if (error) {
682    errno = error;
683    return -1;
684  }
685
686  return AllocateFD(handle);
687}
688
689