summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--native_client_sdk/src/build_tools/sdk_files.list2
-rw-r--r--native_client_sdk/src/libraries/nacl_io/ioctl.h25
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc19
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_intercept.h7
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc45
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_proxy.h10
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_wrap.h7
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc26
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc26
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_wrap_win.cc20
-rw-r--r--native_client_sdk/src/libraries/nacl_io/library.dsc2
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_dev.cc89
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node.cc4
-rw-r--r--native_client_sdk/src/libraries/nacl_io/ostypes.h2
-rw-r--r--native_client_sdk/src/libraries/nacl_io/osutime.h15
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h5
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc38
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/mount_node_test.cc3
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/mount_test.cc67
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc39
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/ps_instance.h5
-rwxr-xr-xnative_client_sdk/src/tools/getos.py2
-rwxr-xr-xnative_client_sdk/src/tools/tests/getos_test.py2
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)