diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2018-08-21 09:49:59 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2018-08-22 13:44:40 +0100 |
commit | a745d0cb810146352f02edd463ec338e75605f89 (patch) | |
tree | 96e172ceb7b2d66d65bda269b095e3e6405d82af | |
parent | b4673e15b303e011d8d61e595f3f26abaeb1b7bb (diff) |
igt/shell: First attempt at instantiating an object to wrap OS
-rw-r--r-- | shell/include/os.h | 10 | ||||
-rw-r--r-- | shell/lib/os-file.cc | 88 | ||||
-rw-r--r-- | shell/lib/os.cc | 109 | ||||
-rw-r--r-- | shell/meson.build | 2 | ||||
-rw-r--r-- | shell/samples/os.sleep.js | 9 |
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"); |