diff options
23 files changed, 437 insertions, 23 deletions
diff --git a/native_client_sdk/src/build_tools/sdk_files.list b/native_client_sdk/src/build_tools/sdk_files.list index ffa9720..fd6fc1f 100644 --- a/native_client_sdk/src/build_tools/sdk_files.list +++ b/native_client_sdk/src/build_tools/sdk_files.list @@ -256,6 +256,7 @@ include/json/writer.h include/KHR/khrplatform.h include/nacl_io/error.h include/nacl_io/inode_pool.h +include/nacl_io/ioctl.h include/nacl_io/kernel_handle.h include/nacl_io/kernel_intercept.h include/nacl_io/kernel_object.h @@ -280,6 +281,7 @@ include/nacl_io/osmman.h include/nacl_io/osstat.h include/nacl_io/ostypes.h include/nacl_io/osunistd.h +include/nacl_io/osutime.h include/nacl_io/path.h include/nacl_io/pepper/all_interfaces.h include/nacl_io/pepper/define_empty_macros.h diff --git a/native_client_sdk/src/libraries/nacl_io/ioctl.h b/native_client_sdk/src/libraries/nacl_io/ioctl.h new file mode 100644 index 0000000..0a730e8 --- /dev/null +++ b/native_client_sdk/src/libraries/nacl_io/ioctl.h @@ -0,0 +1,25 @@ +/* Copyright 2013 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef LIBRARIES_NACL_IO_IOCTL_H_ +#define LIBRARIES_NACL_IO_IOCTL_H_ + +/* ioctl to tell a tty mount to prefix every message with a particular + * null-terminated string. Accepts a pointer to a C string which will + * be the prefix. + */ +#define TIOCNACLPREFIX 0xadcd01 + +/* ioctl to feed input to a tty mount. Accepts a pointer to the following + * struct (tioc_nacl_input_string), which contains a pointer to an array + * of characters. + */ +#define TIOCNACLINPUT 0xadcd02 + +struct tioc_nacl_input_string { + size_t length; + const char* buffer; +}; + +#endif // LIBRARIES_NACL_IO_NACL_IO_H_ diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc index ec16700..b237221 100644 --- a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc +++ b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc @@ -173,3 +173,22 @@ int ki_open_resource(const char* file) { return s_kp->open_resource(file); } +int ki_ioctl(int d, int request, char* argp) { + return s_kp->ioctl(d, request, argp); +} + +int ki_chown(const char* path, uid_t owner, gid_t group) { + return s_kp->chown(path, owner, group); +} + +int ki_fchown(int fd, uid_t owner, gid_t group) { + return s_kp->fchown(fd, owner, group); +} + +int ki_lchown(const char* path, uid_t owner, gid_t group) { + return s_kp->lchown(path, owner, group); +} + +int ki_utime(const char* filename, const struct utimbuf* times) { + return s_kp->utime(filename, times); +} diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h index c4b658d..de9e98e 100644 --- a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h +++ b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h @@ -8,6 +8,7 @@ #include <ppapi/c/ppb.h> #include <ppapi/c/pp_instance.h> #include "nacl_io/ostypes.h" +#include "nacl_io/osutime.h" #include "sdk_util/macros.h" EXTERN_C_BEGIN @@ -56,8 +57,12 @@ void* ki_mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset); int ki_munmap(void* addr, size_t length); int ki_open_resource(const char* file); +int ki_ioctl(int d, int request, char* argp); +int ki_chown(const char* path, uid_t owner, gid_t group); +int ki_fchown(int fd, uid_t owner, gid_t group); +int ki_lchown(const char* path, uid_t owner, gid_t group); +int ki_utime(const char* filename, const struct utimbuf* times); EXTERN_C_END #endif // LIBRARIES_NACL_IO_KERNEL_INTERCEPT_H_ - diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc index 47ed887..bc62c37 100644 --- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc +++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc @@ -167,7 +167,7 @@ char* KernelProxy::getwd(char* buf) { } int KernelProxy::chmod(const char* path, mode_t mode) { - int fd = KernelProxy::open(path, O_RDWR); + int fd = KernelProxy::open(path, O_RDONLY); if (-1 == fd) return -1; @@ -176,6 +176,22 @@ int KernelProxy::chmod(const char* path, mode_t mode) { return result; } +int KernelProxy::chown(const char* path, uid_t owner, gid_t group) { + return 0; +} + +int KernelProxy::fchown(int fd, uid_t owner, gid_t group) { + return 0; +} + +int KernelProxy::lchown(const char* path, uid_t owner, gid_t group) { + return 0; +} + +int KernelProxy::utime(const char* filename, const struct utimbuf* times) { + return 0; +} + int KernelProxy::mkdir(const char* path, mode_t mode) { ScopedMount mnt; Path rel; @@ -454,6 +470,23 @@ int KernelProxy::isatty(int fd) { return 0; } +int KernelProxy::ioctl(int d, int request, char* argp) { + ScopedKernelHandle handle; + Error error = AcquireHandle(d, &handle); + if (error) { + errno = error; + return -1; + } + + error = handle->node_->Ioctl(request, argp); + if (error) { + errno = error; + return -1; + } + + return 0; +} + off_t KernelProxy::lseek(int fd, off_t offset, int whence) { ScopedKernelHandle handle; Error error = AcquireHandle(fd, &handle); @@ -511,8 +544,14 @@ int KernelProxy::remove(const char* path) { // TODO(noelallen): Needs implementation. int KernelProxy::fchmod(int fd, int mode) { - errno = EINVAL; - return -1; + ScopedKernelHandle handle; + Error error = AcquireHandle(fd, &handle); + if (error) { + errno = error; + return -1; + } + + return 0; } int KernelProxy::access(const char* path, int amode) { diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h index 7a9a8d1..ac3b936 100644 --- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h +++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h @@ -15,6 +15,7 @@ #include "nacl_io/kernel_object.h" #include "nacl_io/mount.h" #include "nacl_io/ostypes.h" +#include "nacl_io/osutime.h" #include "nacl_io/path.h" class KernelHandle; @@ -43,7 +44,7 @@ class KernelProxy : protected KernelObject { virtual void Init(PepperInterface* ppapi); // KernelHandle and FD allocation and manipulation functions. - virtual int open(const char *path, int oflag); + virtual int open(const char* path, int oflag); virtual int close(int fd); virtual int dup(int fd); virtual int dup2(int fd, int newfd); @@ -56,6 +57,12 @@ class KernelProxy : protected KernelObject { const char *filesystemtype, unsigned long mountflags, const void *data); virtual int umount(const char *path); + // Stub system calls that don't do anything (yet), handled by KernelProxy. + virtual int chown(const char* path, uid_t owner, gid_t group); + virtual int fchown(int fd, uid_t owner, gid_t group); + virtual int lchown(const char* path, uid_t owner, gid_t group); + virtual int utime(const char* filename, const struct utimbuf* times); + // System calls that take a path as an argument: // The kernel proxy will look for the Node associated to the path. To // find the node, the kernel proxy calls the corresponding mount's GetNode() @@ -79,6 +86,7 @@ class KernelProxy : protected KernelObject { virtual int ftruncate(int fd, off_t length); virtual int fsync(int fd); virtual int isatty(int fd); + virtual int ioctl(int d, int request, char *argp); // lseek() relies on the mount's Stat() to determine whether or not the // file handle corresponding to fd is a directory diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h b/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h index 322fe72..ca1ada6 100644 --- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h +++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h @@ -7,6 +7,8 @@ #include <sys/types.h> #include <stdlib.h> +#include "nacl_io/ostypes.h" +#include "nacl_io/osutime.h" #include "sdk_util/macros.h" #if defined(__GLIBC__) @@ -37,9 +39,11 @@ void kernel_wrap_init(); int NAME(access)(const char* path, int amode) NOTHROW; int NAME(chdir)(const char* path) NOTHROW; int NAME(chmod)(const char* path, chmod_mode_t mode) NOTHROW; +int chown(const char* path, uid_t owner, gid_t group); int NAME(close)(int fd); int NAME(dup)(int oldfd) NOTHROW; int NAME(dup2)(int oldfd, int newfd) NOTHROW; +int fchown(int fd, uid_t owner, gid_t group); #if defined(WIN32) int _fstat32(int fd, struct _stat32* buf); int _fstat64(int fd, struct _stat64* buf); @@ -54,7 +58,9 @@ int ftruncate(int fd, off_t length) NOTHROW; char* NAME(getcwd)(char* buf, getcwd_size_t size) NOTHROW; char* getwd(char* buf) NOTHROW; int getdents(int fd, void* buf, unsigned int count) NOTHROW; +int ioctl(int d, int request, char* argp) NOTHROW; int NAME(isatty)(int fd) NOTHROW; +int lchown(const char* path, uid_t owner, gid_t group); int link(const char* oldpath, const char* newpath) NOTHROW; off_t NAME(lseek)(int fd, off_t offset, int whence) NOTHROW; #if defined(WIN32) @@ -82,6 +88,7 @@ int stat(const char* path, struct stat* buf) NOTHROW; int symlink(const char* oldpath, const char* newpath) NOTHROW; int umount(const char* path) NOTHROW; int NAME(unlink)(const char* path) NOTHROW; +int utime(const char* filename, const struct utimbuf* times); read_ssize_t NAME(write)(int fd, const void* buf, size_t nbyte); EXTERN_C_END diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc index 073d8e0..2de85f8 100644 --- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc +++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc @@ -138,6 +138,10 @@ int WRAP(chdir) (const char* pathname) { return (ki_chdir(pathname)) ? errno : 0; } +int chown(const char* path, uid_t owner, gid_t group) { + return ki_chown(path, owner, group); +} + int WRAP(close)(int fd) { return (ki_close(fd) < 0) ? errno : 0; } @@ -151,6 +155,10 @@ int WRAP(dup2)(int fd, int newfd) NOTHROW { return (ki_dup2(fd, newfd) < 0) ? errno : 0; } +int fchown(int fd, uid_t owner, gid_t group) { + return ki_fchown(fd, owner, group); +} + int WRAP(fstat)(int fd, struct nacl_abi_stat *nacl_buf) { struct stat buf; memset(&buf, 0, sizeof(struct stat)); @@ -215,10 +223,18 @@ int WRAP(getdents)(int fd, dirent* nacl_buf, size_t nacl_count, size_t *nread) { return 0; } +int ioctl(int d, int request, char* argp) NOTHROW { + return ki_ioctl(d, request, argp); +} + int isatty(int fd) NOTHROW { return ki_isatty(fd); } +int lchown(const char* path, uid_t owner, gid_t group) { + return ki_lchown(path, owner, group); +} + int link(const char* oldpath, const char* newpath) NOTHROW { return ki_link(oldpath, newpath); } @@ -310,7 +326,11 @@ int unlink(const char* path) NOTHROW { return ki_unlink(path); } -int WRAP(write)(int fd, const void *buf, size_t count, size_t *nwrote) { +int utime(const char* filename, const struct utimbuf* times) { + return ki_utime(filename, times); +} + +int WRAP(write)(int fd, const void* buf, size_t count, size_t* nwrote) { if (!ki_is_initialized()) return REAL(write)(fd, buf, count, nwrote); @@ -326,7 +346,7 @@ int _real_close(int fd) { return REAL(close)(fd); } -int _real_fstat(int fd, struct stat *buf) { +int _real_fstat(int fd, struct stat* buf) { struct nacl_abi_stat st; int err = REAL(fstat)(fd, &st); if (err) { @@ -338,7 +358,7 @@ int _real_fstat(int fd, struct stat *buf) { return 0; } -int _real_getdents(int fd, void* buf, size_t count, size_t *nread) { +int _real_getdents(int fd, void* buf, size_t count, size_t* nread) { // "buf" contains dirent(s); "nacl_buf" contains nacl_abi_dirent(s). // See WRAP(getdents) above. char* nacl_buf = (char*)alloca(count); diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc index 776e55e..d2f8242 100644 --- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc +++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc @@ -63,6 +63,10 @@ int chmod(const char* path, mode_t mode) { return ki_chmod(path, mode); } +int chown(const char* path, uid_t owner, gid_t group) { + return ki_chown(path, owner, group); +} + int WRAP(close)(int fd) { return (ki_close(fd) < 0) ? errno : 0; } @@ -77,7 +81,11 @@ int WRAP(dup2)(int fd, int newfd) { return (newfd < 0) ? errno : 0; } -int WRAP(fstat)(int fd, struct stat *buf) { +int fchown(int fd, uid_t owner, gid_t group) { + return ki_fchown(fd, owner, group); +} + +int WRAP(fstat)(int fd, struct stat* buf) { return (ki_fstat(fd, buf) < 0) ? errno : 0; } @@ -101,14 +109,22 @@ int getdents(int fd, void* buf, unsigned int count) { return ki_getdents(fd, buf, count); } -int WRAP(getdents)(int fd, dirent* buf, size_t count, size_t *nread) { +int WRAP(getdents)(int fd, dirent* buf, size_t count, size_t* nread) { return (ki_getdents(fd, buf, count) < 0) ? errno : 0; } +int ioctl(int d, int request, char* argp) { + return ki_ioctl(d, request, argp); +} + int isatty(int fd) { return ki_isatty(fd); } +int lchown(const char* path, uid_t owner, gid_t group) { + return ki_lchown(path, owner, group); +} + int link(const char* oldpath, const char* newpath) { return ki_link(oldpath, newpath); } @@ -143,7 +159,7 @@ int WRAP(open)(const char* pathname, int oflag, mode_t cmode, int* newfd) { return (*newfd < 0) ? errno : 0; } -int WRAP(read)(int fd, void *buf, size_t count, size_t *nread) { +int WRAP(read)(int fd, void* buf, size_t count, size_t* nread) { if (!ki_is_initialized()) return REAL(read)(fd, buf, count, nread); @@ -181,6 +197,10 @@ int unlink(const char* path) { return ki_unlink(path); } +int utime(const char *filename, const struct utimbuf* times) { + return ki_utime(filename, times); +} + int WRAP(write)(int fd, const void *buf, size_t count, size_t *nwrote) { if (!ki_is_initialized()) return REAL(write)(fd, buf, count, nwrote); diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_win.cc b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_win.cc index 64d24c5..85bfd0c 100644 --- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_win.cc +++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_win.cc @@ -55,6 +55,10 @@ int _chmod(const char* path, mode_t mode) { return ki_chmod(path, mode); } +int chown(const char* path, uid_t owner, gid_t group) { + return ki_chown(path, owner, group); +} + int _close(int fd) { return ki_close(fd); } @@ -71,6 +75,10 @@ int _dup2(int oldfd, int newfd) { return ki_dup2(oldfd, newfd); } +int fchown(int fd, uid_t owner, gid_t group) { + return ki_fchown(fd, owner, group); +} + int _fstat32(int fd, struct _stat32* buf) { struct stat ki_buf; int res = ki_fstat(fd, &ki_buf); @@ -119,10 +127,18 @@ int getdents(int fd, void* buf, unsigned int count) { return ki_getdents(fd, buf, count); } +int ioctl(int d, int request, char* argp) { + return ki_ioctl(d, request, argp); +} + int _isatty(int fd) { return ki_isatty(fd); } +int lchown(const char* path, uid_t owner, gid_t group) { + return ki_lchown(path, owner, group); +} + int link(const char* oldpath, const char* newpath) { return ki_link(oldpath, newpath); } @@ -226,6 +242,10 @@ int _unlink(const char* path) { return ki_unlink(path); } +int _utime(const char* filename, const struct utimbuf* times) { + return ki_utime(filename, times); +} + int _write(int fd, const void* buf, size_t nbyte) { if (!ki_is_initialized()) return 0; diff --git a/native_client_sdk/src/libraries/nacl_io/library.dsc b/native_client_sdk/src/libraries/nacl_io/library.dsc index 4359ff7..c582991 100644 --- a/native_client_sdk/src/libraries/nacl_io/library.dsc +++ b/native_client_sdk/src/libraries/nacl_io/library.dsc @@ -39,6 +39,7 @@ 'FILES': [ "error.h", "inode_pool.h", + "ioctl.h", "kernel_handle.h", "kernel_intercept.h", "kernel_object.h", @@ -63,6 +64,7 @@ "osstat.h", "ostypes.h", "osunistd.h", + "osutime.h", "path.h", "pepper_interface.h", "real_pepper_interface.h", diff --git a/native_client_sdk/src/libraries/nacl_io/mount_dev.cc b/native_client_sdk/src/libraries/nacl_io/mount_dev.cc index 2872013..78b5916 100644 --- a/native_client_sdk/src/libraries/nacl_io/mount_dev.cc +++ b/native_client_sdk/src/libraries/nacl_io/mount_dev.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2012 The Chromium Authors. All rights reserved. +/* Copyright (c) 2013 The Chromium Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ @@ -8,7 +8,12 @@ #include <errno.h> #include <fcntl.h> +#include <pthread.h> #include <string.h> + +#include <deque> + +#include "nacl_io/ioctl.h" #include "nacl_io/kernel_wrap_real.h" #include "nacl_io/mount_dev.h" #include "nacl_io/mount_node.h" @@ -67,11 +72,25 @@ class ConsoleNode : public NullNode { class TtyNode : public NullNode { public: explicit TtyNode(Mount* mount); + ~TtyNode(); + + virtual Error Ioctl(int request, + char* arg); + + virtual Error Read(size_t offs, + void* buf, + size_t count, + int* out_bytes); virtual Error Write(size_t offs, const void* buf, size_t count, int* out_bytes); + + private: + std::deque<char> input_buffer_; + pthread_cond_t is_readable_; + std::string prefix_; }; class ZeroNode : public MountNode { @@ -176,7 +195,14 @@ Error ConsoleNode::Write(size_t offs, return 0; } -TtyNode::TtyNode(Mount* mount) : NullNode(mount) {} +TtyNode::TtyNode(Mount* mount) : NullNode(mount) { + prefix_ = "_default_:"; + pthread_cond_init(&is_readable_, NULL); +} + +TtyNode::~TtyNode() { + pthread_cond_destroy(&is_readable_); +} Error TtyNode::Write(size_t offs, const void* buf, @@ -190,15 +216,68 @@ Error TtyNode::Write(size_t offs, if (!(var_intr && msg_intr)) return ENOSYS; + // We append the prefix_ to the data in buf, then package it up + // and post it as a message. const char* data = static_cast<const char*>(buf); - uint32_t len = static_cast<uint32_t>(count); - struct PP_Var val = var_intr->VarFromUtf8(data, len); + std::string message; + { + AutoLock lock(&lock_); + message = prefix_; + } + message.append(data, count); + uint32_t len = static_cast<uint32_t>(message.size()); + struct PP_Var val = var_intr->VarFromUtf8(message.data(), len); msg_intr->PostMessage(mount_->ppapi()->GetInstance(), val); - *out_bytes = count; return 0; } +Error TtyNode::Read(size_t offs, void* buf, size_t count, int* out_bytes) { + AutoLock lock(&lock_); + while (input_buffer_.size() <= 0) { + pthread_cond_wait(&is_readable_, &lock_); + } + + // Copies data from the input buffer into buf. + size_t bytes_to_copy = std::min(count, input_buffer_.size()); + std::copy(input_buffer_.begin(), input_buffer_.begin() + bytes_to_copy, + static_cast<char*>(buf)); + *out_bytes = bytes_to_copy; + input_buffer_.erase(input_buffer_.begin(), + input_buffer_.begin() + bytes_to_copy); + return 0; +} + +Error TtyNode::Ioctl(int request, char* arg) { + if (request == TIOCNACLPREFIX) { + // This ioctl is used to change the prefix for this tty node. + // The prefix is used to distinguish messages intended for this + // tty node from all the other messages cluttering up the + // javascript postMessage() channel. + AutoLock lock(&lock_); + prefix_ = arg; + return 0; + } else if (request == TIOCNACLINPUT) { + // This ioctl is used to deliver data from the user to this tty node's + // input buffer. We check if the prefix in the input data matches the + // prefix for this node, and only deliver the data if so. + struct tioc_nacl_input_string* message = + reinterpret_cast<struct tioc_nacl_input_string*>(arg); + AutoLock lock(&lock_); + if (message->length >= prefix_.size() && + strncmp(message->buffer, prefix_.data(), prefix_.size()) == 0) { + input_buffer_.insert(input_buffer_.end(), + message->buffer + prefix_.size(), + message->buffer + message->length); + pthread_cond_broadcast(&is_readable_); + return 0; + } + return ENOTTY; + } else { + return EINVAL; + } +} + ZeroNode::ZeroNode(Mount* mount) : MountNode(mount) { stat_.st_mode = S_IFCHR; } Error ZeroNode::Read(size_t offs, void* buf, size_t count, int* out_bytes) { diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node.cc b/native_client_sdk/src/libraries/nacl_io/mount_node.cc index 7c53860..ec77b97 100644 --- a/native_client_sdk/src/libraries/nacl_io/mount_node.cc +++ b/native_client_sdk/src/libraries/nacl_io/mount_node.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2012 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be +x * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "nacl_io/mount_node.h" @@ -8,6 +8,8 @@ #include <fcntl.h> #include <string.h> #include <sys/stat.h> + +#include <algorithm> #include <string> #include "nacl_io/kernel_wrap_real.h" diff --git a/native_client_sdk/src/libraries/nacl_io/ostypes.h b/native_client_sdk/src/libraries/nacl_io/ostypes.h index 5adc6fe..084ec33 100644 --- a/native_client_sdk/src/libraries/nacl_io/ostypes.h +++ b/native_client_sdk/src/libraries/nacl_io/ostypes.h @@ -13,6 +13,8 @@ typedef int mode_t; typedef SSIZE_T ssize_t; +typedef int uid_t; +typedef int gid_t; #endif diff --git a/native_client_sdk/src/libraries/nacl_io/osutime.h b/native_client_sdk/src/libraries/nacl_io/osutime.h new file mode 100644 index 0000000..03d98b9 --- /dev/null +++ b/native_client_sdk/src/libraries/nacl_io/osutime.h @@ -0,0 +1,15 @@ +/* Copyright 2013 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef LIBRARIES_NACL_IO_OSUTIME_H_ +#define LIBRARIES_NACL_IO_OSUTIME_H_ + +#if defined(WIN32) +#define utimbuf _utimbuf +#endif + +struct utimbuf; + +#endif // LIBRARIES_NACL_IO_OSUTIME_H_ + diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h b/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h index d74e886..defd7de 100644 --- a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h +++ b/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h @@ -20,16 +20,20 @@ class KernelProxyMock : public KernelProxy { MOCK_METHOD2(access, int(const char*, int)); MOCK_METHOD1(chdir, int(const char*)); MOCK_METHOD2(chmod, int(const char*, mode_t)); + MOCK_METHOD3(chown, int(const char*, uid_t, gid_t)); MOCK_METHOD1(close, int(int)); MOCK_METHOD1(dup, int(int)); MOCK_METHOD2(dup2, int(int, int)); + MOCK_METHOD3(fchown, int(int, uid_t, gid_t)); MOCK_METHOD2(ftruncate, int(int, off_t)); MOCK_METHOD2(fstat, int(int, struct stat*)); MOCK_METHOD1(fsync, int(int)); MOCK_METHOD2(getcwd, char*(char*, size_t)); MOCK_METHOD3(getdents, int(int, void*, unsigned int)); MOCK_METHOD1(getwd, char*(char*)); + MOCK_METHOD3(ioctl, int(int, int, char*)); MOCK_METHOD1(isatty, int(int)); + MOCK_METHOD3(lchown, int(const char*, uid_t, gid_t)); MOCK_METHOD3(lseek, off_t(int, off_t, int)); MOCK_METHOD2(mkdir, int(const char*, mode_t)); MOCK_METHOD5(mount, int(const char*, const char*, const char*, unsigned long, @@ -41,6 +45,7 @@ class KernelProxyMock : public KernelProxy { MOCK_METHOD2(stat, int(const char*, struct stat*)); MOCK_METHOD1(umount, int(const char*)); MOCK_METHOD1(unlink, int(const char*)); + MOCK_METHOD2(utime, int(const char*, const struct utimbuf*)); MOCK_METHOD3(write, ssize_t(int, const void*, size_t)); MOCK_METHOD2(link, int(const char*, const char*)); MOCK_METHOD2(symlink, int(const char*, const char*)); diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc b/native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc index 348ecae..53856a4 100644 --- a/native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc +++ b/native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2012 The Chromium Authors. All rights reserved. +/* Copyright (c) 2013 The Chromium Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ @@ -73,6 +73,9 @@ void MakeDummyStatbuf(struct stat* statbuf) { statbuf->st_ctime = 11; } +const uid_t kDummyUid = 1001; +const gid_t kDummyGid = 1002; + class KernelWrapTest : public ::testing::Test { public: KernelWrapTest() { @@ -114,6 +117,13 @@ TEST_F(KernelWrapTest, chmod) { chmod("chmod", 23); } +TEST_F(KernelWrapTest, chown) { + uid_t uid = kDummyUid; + gid_t gid = kDummyGid; + EXPECT_CALL(mock, chown(StrEq("chown"), uid, gid)).Times(1); + chown("chown", uid, gid); +} + TEST_F(KernelWrapTest, close) { EXPECT_CALL(mock, close(34)).Times(1); close(34); @@ -129,6 +139,13 @@ TEST_F(KernelWrapTest, dup2) { dup2(123, 234); } +TEST_F(KernelWrapTest, fchown) { + uid_t uid = kDummyUid; + gid_t gid = kDummyGid; + EXPECT_CALL(mock, fchown(123, uid, gid)).Times(1); + fchown(123, uid, gid); +} + TEST_F(KernelWrapTest, fstat) { struct stat in_statbuf; MakeDummyStatbuf(&in_statbuf); @@ -174,11 +191,24 @@ TEST_F(KernelWrapTest, getwd) { #pragma GCC diagnostic warning "-Wdeprecated-declarations" #endif +TEST_F(KernelWrapTest, ioctl) { + char buffer[] = "ioctl"; + EXPECT_CALL(mock, ioctl(012, 345, StrEq("ioctl"))).Times(1); + ioctl(012, 345, buffer); +} + TEST_F(KernelWrapTest, isatty) { EXPECT_CALL(mock, isatty(678)).Times(1); isatty(678); } +TEST_F(KernelWrapTest, lchown) { + uid_t uid = kDummyUid; + gid_t gid = kDummyGid; + EXPECT_CALL(mock, lchown(StrEq("lchown"), uid, gid)).Times(1); + lchown("lchown", uid, gid); +} + TEST_F(KernelWrapTest, lseek) { EXPECT_CALL(mock, lseek(789, 891, 912)).Times(1); lseek(789, 891, 912); @@ -242,6 +272,12 @@ TEST_F(KernelWrapTest, unlink) { unlink("unlink"); } +TEST_F(KernelWrapTest, utime) { + const struct utimbuf* times; + EXPECT_CALL(mock, utime(StrEq("utime"), times)); + utime("utime", times); +} + TEST_F(KernelWrapTest, write) { EXPECT_CALL(mock, write(6789, NULL, 7891)).Times(1); write(6789, NULL, 7891); diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_node_test.cc b/native_client_sdk/src/libraries/nacl_io_test/mount_node_test.cc index 4850aaf..794bbdf 100644 --- a/native_client_sdk/src/libraries/nacl_io_test/mount_node_test.cc +++ b/native_client_sdk/src/libraries/nacl_io_test/mount_node_test.cc @@ -7,7 +7,9 @@ #include <fcntl.h> #include "nacl_io/error.h" +#include "nacl_io/ioctl.h" #include "nacl_io/kernel_proxy.h" +#include "nacl_io/mount_dev.h" #include "nacl_io/mount_node.h" #include "nacl_io/mount_node_dir.h" #include "nacl_io/mount_node_mem.h" @@ -192,4 +194,3 @@ TEST(MountNodeTest, Directory) { file.reset(); EXPECT_EQ(1, s_AllocNum); } - diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_test.cc b/native_client_sdk/src/libraries/nacl_io_test/mount_test.cc index f31689f..d9bb876 100644 --- a/native_client_sdk/src/libraries/nacl_io_test/mount_test.cc +++ b/native_client_sdk/src/libraries/nacl_io_test/mount_test.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2012 The Chromium Authors. All rights reserved. +/* Copyright (c) 2013 The Chromium Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ @@ -10,6 +10,7 @@ #include <string> #include "gtest/gtest.h" +#include "nacl_io/ioctl.h" #include "nacl_io/mount.h" #include "nacl_io/mount_dev.h" #include "nacl_io/mount_mem.h" @@ -299,3 +300,67 @@ TEST(MountTest, DevUrandom) { EXPECT_LE(chi_squared, 293.24); } + +TEST(MountTest, DevTty) { + MountDevMock* mnt = new MountDevMock(); + ScopedMountNode dev_tty; + + ASSERT_EQ(0, mnt->Access(Path("/tty"), R_OK | W_OK)); + ASSERT_EQ(EACCES, mnt->Access(Path("/tty"), X_OK)); + ASSERT_EQ(0, mnt->Open(Path("/tty"), O_RDWR, &dev_tty)); + ASSERT_NE(NULL_NODE, dev_tty.get()); + + // 123 is not a valid ioctl request. + EXPECT_EQ(EINVAL, dev_tty->Ioctl(123, NULL)); + + // TIOCNACLPREFIX is, it should set the prefix. + std::string prefix("__my_awesome_prefix__"); + EXPECT_EQ(0, dev_tty->Ioctl(TIOCNACLPREFIX, + const_cast<char*>(prefix.c_str()))); + + // Now let's try sending some data over. + // First we create the message. + std::string content("hello, how are you?"); + std::string message = prefix.append(content); + struct tioc_nacl_input_string packaged_message; + packaged_message.length = message.size(); + packaged_message.buffer = message.data(); + + // Now we make buffer we'll read into. + // We fill the buffer and a backup buffer with arbitrary data + // and compare them after reading to make sure read doesn't + // clobber parts of the buffer it shouldn't. + int bytes_read; + char buffer[100]; + char backup_buffer[100]; + memset(buffer, 'a', 100); + memset(backup_buffer, 'a', 100); + + // Now we actually send the data + EXPECT_EQ(0, dev_tty->Ioctl(TIOCNACLINPUT, + reinterpret_cast<char*>(&packaged_message))); + + // We read a small chunk first to ensure it doesn't give us + // more than we ask for. + EXPECT_EQ(0, dev_tty->Read(0, buffer, 5, &bytes_read)); + EXPECT_EQ(bytes_read, 5); + EXPECT_EQ(0, memcmp(content.data(), buffer, 5)); + EXPECT_EQ(0, memcmp(buffer + 5, backup_buffer + 5, 95)); + + // Now we ask for more data than is left in the tty, to ensure + // it doesn't give us more than is there. + EXPECT_EQ(0, dev_tty->Read(0, buffer + 5, 95, &bytes_read)); + EXPECT_EQ(bytes_read, content.size() - 5); + EXPECT_EQ(0, memcmp(content.data(), buffer, content.size())); + EXPECT_EQ(0, memcmp(buffer + content.size(), + backup_buffer + content.size(), + 100 - content.size())); + + // Now we try to send something with an invalid prefix + std::string bogus_message("Woah there, this message has no valid prefix"); + struct tioc_nacl_input_string bogus_pack; + bogus_pack.length = bogus_message.size(); + bogus_pack.buffer = bogus_message.data(); + EXPECT_EQ(ENOTTY, dev_tty->Ioctl(TIOCNACLINPUT, + reinterpret_cast<char*>(&bogus_pack))); +} diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc b/native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc index 0b5c634..7388bc9 100644 --- a/native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc +++ b/native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <errno.h> #include <fcntl.h> #include <pthread.h> #include <stdarg.h> @@ -16,6 +17,7 @@ #include <string> #include <vector> +#include "nacl_io/ioctl.h" #include "nacl_io/kernel_wrap.h" #include "nacl_io/nacl_io.h" @@ -89,7 +91,8 @@ PSInstance::PSInstance(PP_Instance instance, const char *argv[]) pp::Graphics3DClient(this), main_loop_(NULL), verbosity_(PSV_LOG), - events_enabled_(PSE_NONE) { + events_enabled_(PSE_NONE), + fd_tty_(-1) { // Set the single Instance object s_InstanceObject = this; @@ -201,6 +204,7 @@ bool PSInstance::ProcessProperties() { const char* stdout_path = GetProperty("ps_stdout", "/dev/stdout"); const char* stderr_path = GetProperty("ps_stderr", "/dev/console3"); const char* verbosity = GetProperty("ps_verbosity", NULL); + const char* tty_prefix = GetProperty("ps_tty_prefix", NULL); // Reset verbosity if passed in if (verbosity) SetVerbosity(static_cast<Verbosity>(atoi(verbosity))); @@ -216,6 +220,15 @@ bool PSInstance::ProcessProperties() { int fd2 = open(stderr_path, O_WRONLY); dup2(fd2, 2); + if (tty_prefix) { + fd_tty_ = open("/dev/tty", O_WRONLY); + if (fd_tty_ >= 0) { + ioctl(fd_tty_, TIOCNACLPREFIX, const_cast<char*>(tty_prefix)); + } else { + Error("Failed to open /dev/tty.\n"); + } + } + // Set line buffering on stdout and stderr #if !defined(WIN32) setvbuf(stderr, NULL, _IOLBF, 0); @@ -299,6 +312,30 @@ void PSInstance::PostEvent(PSEventType type, PP_Resource resource) { void PSInstance::PostEvent(PSEventType type, const PP_Var& var) { assert(PSE_INSTANCE_HANDLEMESSAGE == type); + // If the user has specified a tty_prefix_ (using ioctl), then we'll give the + // tty node a chance to vacuum up any messages beginning with that prefix. If + // the message does not start with the prefix, the ioctl call will return + // ENOENT and we'll pass the message through to the event queue. + if (fd_tty_ >= 0 && var.type == PP_VARTYPE_STRING) { + uint32_t message_len; + const char* message = PSInterfaceVar()->VarToUtf8(var, &message_len); + std::string message_str(message, message + message_len); + + // Since our message may contain null characters, we can't send it as a + // naked C string, so we package it up in this struct before sending it + // to the ioctl. + struct tioc_nacl_input_string ioctl_message; + ioctl_message.length = message_len; + ioctl_message.buffer = message_str.data(); + int ret = + ioctl(fd_tty_, TIOCNACLINPUT, reinterpret_cast<char*>(&ioctl_message)); + if (ret != ENOTTY) { + Error("ioctl returned unexpected error: %d.\n", ret); + } + + return; + } + if (events_enabled_ & type) { PSInterfaceVar()->AddRef(var); PSEvent *env = (PSEvent *) malloc(sizeof(PSEvent)); diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps_instance.h b/native_client_sdk/src/libraries/ppapi_simple/ps_instance.h index 55c5192..9e6318b 100644 --- a/native_client_sdk/src/libraries/ppapi_simple/ps_instance.h +++ b/native_client_sdk/src/libraries/ppapi_simple/ps_instance.h @@ -120,9 +120,14 @@ class PSInstance : public pp::Instance, pp::MouseLock, pp::Graphics3DClient { ThreadSafeQueue<PSEvent> event_queue_; uint32_t events_enabled_; Verbosity verbosity_; + int fd_tty_; PSMainFunc_t main_cb_; + const PPB_Core* ppb_core_; + const PPB_Var* ppb_var_; + const PPB_View* ppb_view_; + friend class PSGraphics3DClient; friend class PSMouseLock; }; diff --git a/native_client_sdk/src/tools/getos.py b/native_client_sdk/src/tools/getos.py index bd312b4..70971a6 100755 --- a/native_client_sdk/src/tools/getos.py +++ b/native_client_sdk/src/tools/getos.py @@ -69,7 +69,7 @@ def GetSDKVersion(): name, value = line.split(':', 1) if name == "Version": version = value.strip() - if name == "Revision": + if name == "Chrome Revision": revision = value.strip() if revision == None or version == None: diff --git a/native_client_sdk/src/tools/tests/getos_test.py b/native_client_sdk/src/tools/tests/getos_test.py index 3a6ad60..99ffb95 100755 --- a/native_client_sdk/src/tools/tests/getos_test.py +++ b/native_client_sdk/src/tools/tests/getos_test.py @@ -145,7 +145,7 @@ class TestGetosWithTempdir(TestCaseExtended): expected_version = (16, 196) with open(os.path.join(self.tempdir, 'README'), 'w') as out: out.write('Version: %s\n' % expected_version[0]) - out.write('Revision: %s\n' % expected_version[1]) + out.write('Chrome Revision: %s\n' % expected_version[1]) version = getos.GetSDKVersion() self.assertEqual(version, expected_version) |