summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2018-08-21 09:49:59 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2018-08-22 13:44:40 +0100
commita745d0cb810146352f02edd463ec338e75605f89 (patch)
tree96e172ceb7b2d66d65bda269b095e3e6405d82af
parentb4673e15b303e011d8d61e595f3f26abaeb1b7bb (diff)
igt/shell: First attempt at instantiating an object to wrap OS
-rw-r--r--shell/include/os.h10
-rw-r--r--shell/lib/os-file.cc88
-rw-r--r--shell/lib/os.cc109
-rw-r--r--shell/meson.build2
-rw-r--r--shell/samples/os.sleep.js9
5 files changed, 218 insertions, 0 deletions
diff --git a/shell/include/os.h b/shell/include/os.h
new file mode 100644
index 00000000..6e1f01de
--- /dev/null
+++ b/shell/include/os.h
@@ -0,0 +1,10 @@
+#ifndef OS_H
+#define OS_H
+
+#include "v8.h"
+
+extern void os_file_ctor(v8::Isolate *iso, v8::Handle<v8::ObjectTemplate> os);
+
+extern void os_throw_errno(v8::Isolate *iso, int err);
+
+#endif /* OS_H */
diff --git a/shell/lib/os-file.cc b/shell/lib/os-file.cc
new file mode 100644
index 00000000..c10f02df
--- /dev/null
+++ b/shell/lib/os-file.cc
@@ -0,0 +1,88 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "igt-shell.h"
+#include "os.h"
+#include "v8-helpers.h"
+
+using namespace v8;
+
+static void os_open(const FunctionCallbackInfo<Value>& args)
+{
+ auto iso = args.GetIsolate();
+
+ if (args.Length() < 1 || args.Length() > 2)
+ return;
+
+ if (!args[0]->IsString()) {
+ return;
+ }
+
+ int mode = O_RDONLY | O_CLOEXEC;
+ if (args.Length() > 1 && args[1]->IsUint32())
+ mode = args[1]->Uint32Value();
+
+ String::Utf8Value filename(iso, Local<String>::Cast(args[0]));
+ int fd = open(*filename, mode);
+ if (fd < 0) {
+ os_throw_errno(iso, errno);
+ return;
+ }
+
+ args.GetReturnValue().Set(fd);
+}
+
+static void os_reopen(const FunctionCallbackInfo<Value>& args)
+{
+ auto iso = args.GetIsolate();
+
+ if (args.Length() < 1 || !args[0]->IsInt32()) {
+ iso->ThrowException(Exception::TypeError(AsString(iso, "not an int32").ToLocalChecked()));
+ return;
+ }
+
+ char path[256];
+ snprintf(path, sizeof(path), "/proc/self/fd/%d", args[0]->Int32Value());
+
+ int mode = O_RDONLY | O_CLOEXEC;
+ if (args.Length() > 1 && args[1]->IsUint32())
+ mode = args[1]->Uint32Value();
+
+ int fd = open(path, mode);
+ if (fd < 0)
+ os_throw_errno(iso, errno);
+
+ args.GetReturnValue().Set(fd);
+}
+
+static void os_close(const FunctionCallbackInfo<Value>& args)
+{
+ auto iso = args.GetIsolate();
+
+ for (int i = 0; i < args.Length(); i++) {
+ Local<Value> v = args[i];
+
+ if (!v->IsInt32()) {
+ iso->ThrowException(Exception::TypeError(AsString(iso, "not an int32").ToLocalChecked()));
+ continue;
+ }
+
+ if (close(v->Int32Value()))
+ os_throw_errno(iso, errno);
+ }
+}
+
+void os_file_ctor(Isolate *iso, Handle<ObjectTemplate> os)
+{
+ HandleScope handle_scope(iso);
+
+ static const struct v8_helper_fn funcs[] = {
+ { "open", os_open },
+ { "reopen", os_reopen },
+ { "close", os_close },
+
+ {}
+ };
+ v8_helper_funcs(iso, os, funcs);
+}
diff --git a/shell/lib/os.cc b/shell/lib/os.cc
new file mode 100644
index 00000000..64fe64eb
--- /dev/null
+++ b/shell/lib/os.cc
@@ -0,0 +1,109 @@
+#include <pwd.h>
+#include <grp.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "igt-shell.h"
+#include "os.h"
+#include "v8-helpers.h"
+
+using namespace v8;
+
+void os_throw_errno(Isolate *iso, int err)
+{
+ iso->ThrowException(Exception::Error(AsString(iso, "syscall").ToLocalChecked()));
+}
+
+static void os_drop_root(const FunctionCallbackInfo<Value>& args)
+{
+ auto iso = args.GetIsolate();
+
+ /* Arbitrary default values for nobody:video */
+ uid_t uid = 65534;
+ gid_t gid = 44;
+
+ if (getuid())
+ return; /* already a user */
+
+ struct passwd *pw = getpwnam("nobody");
+ if (pw)
+ uid = pw->pw_uid, gid = pw->pw_gid;
+
+ struct group *grp = getgrnam("video");
+ if (grp)
+ gid = grp->gr_gid;
+
+ if (setgid(gid) || setuid(uid)) {
+ os_throw_errno(iso, errno);
+ return;
+ }
+}
+
+static void os_uid(Local<String> prop, const PropertyCallbackInfo<Value>& info)
+{
+ info.GetReturnValue().Set(Int32::New(info.GetIsolate(), getuid()));
+}
+
+static void os_sleep(const FunctionCallbackInfo<Value>& args)
+{
+ if (!args.Length()) {
+ sleep(0);
+ return;
+ }
+
+ auto iso = args.GetIsolate();
+ auto ctx = iso->GetCurrentContext();
+
+ if (!args[0]->IsNumber()) {
+ iso->ThrowException(Exception::TypeError(AsString(iso, "bad arg[0], expecting a Number").ToLocalChecked()));
+ return;
+ }
+
+ double t = args[0]->NumberValue(ctx).FromMaybe(0);
+ struct timespec ts = { (long)t, (long)(1e9*t) % 1000000000 };
+ nanosleep(&ts, NULL);
+}
+
+static void os_now(Local<String> prop, const PropertyCallbackInfo<Value>& info)
+{
+ auto iso = info.GetIsolate();
+
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
+ os_throw_errno(iso, errno);
+ return;
+ }
+ info.GetReturnValue().Set(Number::New(iso, 1e3*ts.tv_sec + 1e-6*ts.tv_nsec));
+}
+
+static void os_builtin_ctor(Isolate *iso, Handle<ObjectTemplate> igt)
+{
+ HandleScope handle_scope(iso);
+
+ auto tmpl = ObjectTemplate::New(iso);
+
+ static const struct v8_helper_fn os_funcs[] = {
+ { "drop_root", os_drop_root },
+ { "sleep", os_sleep },
+ {}
+ };
+ v8_helper_funcs(iso, tmpl, os_funcs);
+
+ tmpl->SetAccessor(AsString(iso, "uid").ToLocalChecked(), os_uid);
+ tmpl->SetAccessor(AsString(iso, "now").ToLocalChecked(), os_now);
+
+ os_file_ctor(iso, tmpl);
+
+ igt->Set(iso, "os", tmpl);
+}
+
+static struct igt_builtin os_builtin = {
+ .name = "os",
+ .ctor = os_builtin_ctor
+};
+
+__attribute__((constructor))
+static void __os_register_builtin__(void)
+{
+ igt_register_builtin(&os_builtin);
+}
diff --git a/shell/meson.build b/shell/meson.build
index 9868549e..a361172b 100644
--- a/shell/meson.build
+++ b/shell/meson.build
@@ -2,6 +2,8 @@ executable('igt', [
'igt-shell.cc',
'lib/igt.cc',
'lib/igt-toy.cc',
+ 'lib/os.cc',
+ 'lib/os-file.cc',
'lib/v8-helpers.cc',
],
objects: 'v8/libv8_monolith.a',
diff --git a/shell/samples/os.sleep.js b/shell/samples/os.sleep.js
new file mode 100644
index 00000000..19f6aac9
--- /dev/null
+++ b/shell/samples/os.sleep.js
@@ -0,0 +1,9 @@
+let elapsed = -igt.os.now;
+let expected = 0;
+for (var i = 2; i > 0.1; i /= 2) {
+ print("Sleeping for " + i + "s");
+ igt.os.sleep(i);
+ expected += i;
+}
+elapsed += igt.os.now;
+print("Elapsed " + elapsed + "ms, expected " + expected*1000 + "ms");