From a13c175e336bbd5cf6050a09bce674375cab19b1 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 6 Oct 2021 10:22:21 +0900 Subject: [PATCH] src: add flags for controlling process behavior --- src/node.cc | 110 +++++++++++++++++++++++++------------------ src/node.h | 25 ++++++++-- src/node_internals.h | 3 +- 3 files changed, 87 insertions(+), 51 deletions(-) diff --git a/src/node.cc b/src/node.cc index e942c108a15a3c..292f018e8e3023 100644 --- a/src/node.cc +++ b/src/node.cc @@ -842,7 +842,15 @@ static std::atomic_bool init_called{false}; int InitializeNodeWithArgs(std::vector* argv, std::vector* exec_argv, - std::vector* errors) { + std::vector* errors, + ProcessFlags::Flags flags) { + // Set some flags if only kDefaultFlags was passed. This can make API version + // transitions easier for embedders. + if (flags & EnvironmentFlags::kDefaultFlags) { + flags = static_cast( + flags | ProcessFlags::kDisableStdioInheritance); + } + // Make sure InitializeNodeWithArgs() is called only once. CHECK(!init_called.exchange(true)); @@ -853,7 +861,8 @@ int InitializeNodeWithArgs(std::vector* argv, binding::RegisterBuiltinModules(); // Make inherited handles noninheritable. - uv_disable_stdio_inheritance(); + if (flags & ProcessFlags::kDisableStdioInheritance) + uv_disable_stdio_inheritance(); // Cache the original command line to be // used in diagnostic reports. @@ -869,67 +878,73 @@ int InitializeNodeWithArgs(std::vector* argv, HandleEnvOptions(per_process::cli_options->per_isolate->per_env); #if !defined(NODE_WITHOUT_NODE_OPTIONS) - std::string node_options; + if (!(flags & ProcessFlags::kDisableNodeOptionsEnv)) { + std::string node_options; - if (credentials::SafeGetenv("NODE_OPTIONS", &node_options)) { - std::vector env_argv = - ParseNodeOptionsEnvVar(node_options, errors); + if (credentials::SafeGetenv("NODE_OPTIONS", &node_options)) { + std::vector env_argv = + ParseNodeOptionsEnvVar(node_options, errors); - if (!errors->empty()) return 9; + if (!errors->empty()) return 9; - // [0] is expected to be the program name, fill it in from the real argv. - env_argv.insert(env_argv.begin(), argv->at(0)); + // [0] is expected to be the program name, fill it in from the real argv. + env_argv.insert(env_argv.begin(), argv->at(0)); - const int exit_code = ProcessGlobalArgs(&env_argv, - nullptr, - errors, - kAllowedInEnvironment); - if (exit_code != 0) return exit_code; + const int exit_code = ProcessGlobalArgs(&env_argv, + nullptr, + errors, + kAllowedInEnvironment); + if (exit_code != 0) return exit_code; + } } #endif - const int exit_code = ProcessGlobalArgs(argv, - exec_argv, - errors, - kDisallowedInEnvironment); - if (exit_code != 0) return exit_code; + if (!(flags & ProcessFlags::kDisableCLIOptions)) { + const int exit_code = ProcessGlobalArgs(argv, + exec_argv, + errors, + kDisallowedInEnvironment); + if (exit_code != 0) return exit_code; + } // Set the process.title immediately after processing argv if --title is set. if (!per_process::cli_options->title.empty()) uv_set_process_title(per_process::cli_options->title.c_str()); #if defined(NODE_HAVE_I18N_SUPPORT) - // If the parameter isn't given, use the env variable. - if (per_process::cli_options->icu_data_dir.empty()) - credentials::SafeGetenv("NODE_ICU_DATA", - &per_process::cli_options->icu_data_dir); + if (!(flags & ProcessFlags::kNoICU)) { + // If the parameter isn't given, use the env variable. + if (per_process::cli_options->icu_data_dir.empty()) + credentials::SafeGetenv("NODE_ICU_DATA", + &per_process::cli_options->icu_data_dir); #ifdef NODE_ICU_DEFAULT_DATA_DIR - // If neither the CLI option nor the environment variable was specified, - // fall back to the configured default - if (per_process::cli_options->icu_data_dir.empty()) { - // Check whether the NODE_ICU_DEFAULT_DATA_DIR contains the right data - // file and can be read. - static const char full_path[] = - NODE_ICU_DEFAULT_DATA_DIR "/" U_ICUDATA_NAME ".dat"; - - FILE* f = fopen(full_path, "rb"); - - if (f != nullptr) { - fclose(f); - per_process::cli_options->icu_data_dir = NODE_ICU_DEFAULT_DATA_DIR; + // If neither the CLI option nor the environment variable was specified, + // fall back to the configured default + if (per_process::cli_options->icu_data_dir.empty()) { + // Check whether the NODE_ICU_DEFAULT_DATA_DIR contains the right data + // file and can be read. + static const char full_path[] = + NODE_ICU_DEFAULT_DATA_DIR "/" U_ICUDATA_NAME ".dat"; + + FILE* f = fopen(full_path, "rb"); + + if (f != nullptr) { + fclose(f); + per_process::cli_options->icu_data_dir = NODE_ICU_DEFAULT_DATA_DIR; + } } - } #endif // NODE_ICU_DEFAULT_DATA_DIR - // Initialize ICU. - // If icu_data_dir is empty here, it will load the 'minimal' data. - if (!i18n::InitializeICUDirectory(per_process::cli_options->icu_data_dir)) { - errors->push_back("could not initialize ICU " - "(check NODE_ICU_DATA or --icu-data-dir parameters)\n"); - return 9; + // Initialize ICU. + // If icu_data_dir is empty here, it will load the 'minimal' data. + if (!i18n::InitializeICUDirectory(per_process::cli_options->icu_data_dir)) { + errors->push_back("could not initialize ICU " + "(check NODE_ICU_DATA or --icu-data-dir parameters)\n"); + return 9; + } + per_process::metadata.versions.InitializeIntlVersions(); } - per_process::metadata.versions.InitializeIntlVersions(); # ifndef __POSIX__ std::string tz; @@ -956,7 +971,8 @@ InitializationResult InitializeOncePerProcess(int argc, char** argv) { InitializationResult InitializeOncePerProcess( int argc, char** argv, - InitializationSettingsFlags flags) { + InitializationSettingsFlags flags, + ProcessFlags::Flags process_flags) { uint64_t init_flags = flags; if (init_flags & kDefaultInitialization) { init_flags = init_flags | kInitializeV8 | kInitOpenSSL | kRunPlatformInit; @@ -982,8 +998,8 @@ InitializationResult InitializeOncePerProcess( // This needs to run *before* V8::Initialize(). { - result.exit_code = - InitializeNodeWithArgs(&(result.args), &(result.exec_args), &errors); + result.exit_code = InitializeNodeWithArgs( + &(result.args), &(result.exec_args), &errors, process_flags); for (const std::string& error : errors) fprintf(stderr, "%s: %s\n", result.args.at(0).c_str(), error.c_str()); if (result.exit_code != 0) { diff --git a/src/node.h b/src/node.h index f34ed3939704bc..b80ca80aff66a1 100644 --- a/src/node.h +++ b/src/node.h @@ -214,6 +214,23 @@ namespace node { class IsolateData; class Environment; +namespace ProcessFlags { +enum Flags : uint64_t { + kNoFlags = 0, + // Use the default behaviour for Node.js instances. + kDefaultFlags = 1 << 0, + // Disable stdio inheritance. + // This is set when using kDefaultFlags. + kDisableStdioInheritance = 1 << 1, + // Disable reading the NODE_OPTIONS environment variable. + kDisableNodeOptionsEnv = 1 << 2, + // Do not parse CLI options. + kDisableCLIOptions = 1 << 3, + // Do not initialize ICU. + kNoICU = 1 << 4, +}; +} // namespace ProcessFlags + // TODO(addaleax): Officially deprecate this and replace it with something // better suited for a public embedder API. NODE_EXTERN int Start(int argc, char* argv[]); @@ -226,9 +243,11 @@ NODE_EXTERN int Stop(Environment* env); // from argv, fill exec_argv, and possibly add errors resulting from parsing // the arguments to `errors`. The return value is a suggested exit code for the // program; If it is 0, then initializing Node.js succeeded. -NODE_EXTERN int InitializeNodeWithArgs(std::vector* argv, - std::vector* exec_argv, - std::vector* errors); +NODE_EXTERN int InitializeNodeWithArgs( + std::vector* argv, + std::vector* exec_argv, + std::vector* errors, + ProcessFlags::Flags flags = ProcessFlags::kDefaultFlags); enum OptionEnvvarSettings { kAllowedInEnvironment, diff --git a/src/node_internals.h b/src/node_internals.h index c996723db5700c..0caffa254dd254 100644 --- a/src/node_internals.h +++ b/src/node_internals.h @@ -324,7 +324,8 @@ InitializationResult InitializeOncePerProcess(int argc, char** argv); InitializationResult InitializeOncePerProcess( int argc, char** argv, - InitializationSettingsFlags flags); + InitializationSettingsFlags flags, + ProcessFlags::Flags process_flags = ProcessFlags::kDefaultFlags); void TearDownOncePerProcess(); void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s); void SetIsolateMiscHandlers(v8::Isolate* isolate, const IsolateSettings& s);