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