diff options
Diffstat (limited to 'src/node_process.cc')
-rw-r--r-- | src/node_process.cc | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/src/node_process.cc b/src/node_process.cc index d816c32f8d..8db1ab5ec0 100644 --- a/src/node_process.cc +++ b/src/node_process.cc @@ -25,23 +25,38 @@ typedef int mode_t; #include <grp.h> // getgrnam() #endif +#ifdef __APPLE__ +#include <crt_externs.h> +#define environ (*_NSGetEnviron()) +#elif !defined(_MSC_VER) +extern char **environ; +#endif + namespace node { using v8::Array; using v8::ArrayBuffer; using v8::BigUint64Array; +using v8::Boolean; +using v8::Context; using v8::Float64Array; +using v8::Function; using v8::FunctionCallbackInfo; using v8::HeapStatistics; using v8::Integer; using v8::Isolate; using v8::Local; +using v8::Name; using v8::Number; +using v8::PropertyCallbackInfo; using v8::String; using v8::Uint32; using v8::Uint32Array; using v8::Value; +Mutex process_mutex; +Mutex environ_mutex; + // Microseconds in a second, as a float, used in CPUUsage() below #define MICROS_PER_SEC 1e6 // used in Hrtime() below @@ -557,4 +572,216 @@ void InitGroups(const FunctionCallbackInfo<Value>& args) { #endif // __POSIX__ && !defined(__ANDROID__) && !defined(__CloudABI__) +void ProcessTitleGetter(Local<Name> property, + const PropertyCallbackInfo<Value>& info) { + char buffer[512]; + uv_get_process_title(buffer, sizeof(buffer)); + info.GetReturnValue().Set(String::NewFromUtf8(info.GetIsolate(), buffer, + v8::NewStringType::kNormal).ToLocalChecked()); +} + + +void ProcessTitleSetter(Local<Name> property, + Local<Value> value, + const PropertyCallbackInfo<void>& info) { + node::Utf8Value title(info.GetIsolate(), value); + TRACE_EVENT_METADATA1("__metadata", "process_name", "name", + TRACE_STR_COPY(*title)); + uv_set_process_title(*title); +} + +void EnvGetter(Local<Name> property, + const PropertyCallbackInfo<Value>& info) { + Isolate* isolate = info.GetIsolate(); + if (property->IsSymbol()) { + return info.GetReturnValue().SetUndefined(); + } + Mutex::ScopedLock lock(environ_mutex); +#ifdef __POSIX__ + node::Utf8Value key(isolate, property); + const char* val = getenv(*key); + if (val) { + return info.GetReturnValue().Set(String::NewFromUtf8(isolate, val, + v8::NewStringType::kNormal).ToLocalChecked()); + } +#else // _WIN32 + node::TwoByteValue key(isolate, property); + WCHAR buffer[32767]; // The maximum size allowed for environment variables. + SetLastError(ERROR_SUCCESS); + DWORD result = GetEnvironmentVariableW(reinterpret_cast<WCHAR*>(*key), + buffer, + arraysize(buffer)); + // If result >= sizeof buffer the buffer was too small. That should never + // happen. If result == 0 and result != ERROR_SUCCESS the variable was not + // found. + if ((result > 0 || GetLastError() == ERROR_SUCCESS) && + result < arraysize(buffer)) { + const uint16_t* two_byte_buffer = reinterpret_cast<const uint16_t*>(buffer); + Local<String> rc = String::NewFromTwoByte(isolate, two_byte_buffer); + return info.GetReturnValue().Set(rc); + } +#endif +} + + +void EnvSetter(Local<Name> property, + Local<Value> value, + const PropertyCallbackInfo<Value>& info) { + Environment* env = Environment::GetCurrent(info); + if (env->options()->pending_deprecation && env->EmitProcessEnvWarning() && + !value->IsString() && !value->IsNumber() && !value->IsBoolean()) { + if (ProcessEmitDeprecationWarning( + env, + "Assigning any value other than a string, number, or boolean to a " + "process.env property is deprecated. Please make sure to convert the " + "value to a string before setting process.env with it.", + "DEP0104").IsNothing()) + return; + } + + Mutex::ScopedLock lock(environ_mutex); +#ifdef __POSIX__ + node::Utf8Value key(info.GetIsolate(), property); + node::Utf8Value val(info.GetIsolate(), value); + setenv(*key, *val, 1); +#else // _WIN32 + node::TwoByteValue key(info.GetIsolate(), property); + node::TwoByteValue val(info.GetIsolate(), value); + WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key); + // Environment variables that start with '=' are read-only. + if (key_ptr[0] != L'=') { + SetEnvironmentVariableW(key_ptr, reinterpret_cast<WCHAR*>(*val)); + } +#endif + // Whether it worked or not, always return value. + info.GetReturnValue().Set(value); +} + + +void EnvQuery(Local<Name> property, const PropertyCallbackInfo<Integer>& info) { + Mutex::ScopedLock lock(environ_mutex); + int32_t rc = -1; // Not found unless proven otherwise. + if (property->IsString()) { +#ifdef __POSIX__ + node::Utf8Value key(info.GetIsolate(), property); + if (getenv(*key)) + rc = 0; +#else // _WIN32 + node::TwoByteValue key(info.GetIsolate(), property); + WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key); + SetLastError(ERROR_SUCCESS); + if (GetEnvironmentVariableW(key_ptr, nullptr, 0) > 0 || + GetLastError() == ERROR_SUCCESS) { + rc = 0; + if (key_ptr[0] == L'=') { + // Environment variables that start with '=' are hidden and read-only. + rc = static_cast<int32_t>(v8::ReadOnly) | + static_cast<int32_t>(v8::DontDelete) | + static_cast<int32_t>(v8::DontEnum); + } + } +#endif + } + if (rc != -1) + info.GetReturnValue().Set(rc); +} + + +void EnvDeleter(Local<Name> property, + const PropertyCallbackInfo<Boolean>& info) { + Mutex::ScopedLock lock(environ_mutex); + if (property->IsString()) { +#ifdef __POSIX__ + node::Utf8Value key(info.GetIsolate(), property); + unsetenv(*key); +#else + node::TwoByteValue key(info.GetIsolate(), property); + WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key); + SetEnvironmentVariableW(key_ptr, nullptr); +#endif + } + + // process.env never has non-configurable properties, so always + // return true like the tc39 delete operator. + info.GetReturnValue().Set(true); +} + + +void EnvEnumerator(const PropertyCallbackInfo<Array>& info) { + Environment* env = Environment::GetCurrent(info); + Isolate* isolate = env->isolate(); + Local<Context> ctx = env->context(); + Local<Function> fn = env->push_values_to_array_function(); + Local<Value> argv[NODE_PUSH_VAL_TO_ARRAY_MAX]; + size_t idx = 0; + + Mutex::ScopedLock lock(environ_mutex); +#ifdef __POSIX__ + int size = 0; + while (environ[size]) + size++; + + Local<Array> envarr = Array::New(isolate); + + for (int i = 0; i < size; ++i) { + const char* var = environ[i]; + const char* s = strchr(var, '='); + const int length = s ? s - var : strlen(var); + argv[idx] = String::NewFromUtf8(isolate, + var, + v8::NewStringType::kNormal, + length).ToLocalChecked(); + if (++idx >= arraysize(argv)) { + fn->Call(ctx, envarr, idx, argv).ToLocalChecked(); + idx = 0; + } + } + if (idx > 0) { + fn->Call(ctx, envarr, idx, argv).ToLocalChecked(); + } +#else // _WIN32 + WCHAR* environment = GetEnvironmentStringsW(); + if (environment == nullptr) + return; // This should not happen. + Local<Array> envarr = Array::New(isolate); + WCHAR* p = environment; + while (*p) { + WCHAR* s; + if (*p == L'=') { + // If the key starts with '=' it is a hidden environment variable. + p += wcslen(p) + 1; + continue; + } else { + s = wcschr(p, L'='); + } + if (!s) { + s = p + wcslen(p); + } + const uint16_t* two_byte_buffer = reinterpret_cast<const uint16_t*>(p); + const size_t two_byte_buffer_len = s - p; + argv[idx] = String::NewFromTwoByte(isolate, + two_byte_buffer, + String::kNormalString, + two_byte_buffer_len); + if (++idx >= arraysize(argv)) { + fn->Call(ctx, envarr, idx, argv).ToLocalChecked(); + idx = 0; + } + p = s + wcslen(s) + 1; + } + if (idx > 0) { + fn->Call(ctx, envarr, idx, argv).ToLocalChecked(); + } + FreeEnvironmentStringsW(environment); +#endif + + info.GetReturnValue().Set(envarr); +} + +void GetParentProcessId(Local<Name> property, + const PropertyCallbackInfo<Value>& info) { + info.GetReturnValue().Set(Integer::New(info.GetIsolate(), uv_os_getppid())); +} + + } // namespace node |