From a9826b09d46eeb3ec48e66177a803125607f9010 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 PR-URL: https://github.com/nodejs/node/pull/40339 Reviewed-By: Anna Henningsen Reviewed-By: Michael Dawson Reviewed-By: James M Snell Reviewed-By: Shelley Vohr Reviewed-By: Minwoo Jung --- src/node.cc | 108 +++++++++++++++++++++++++------------------ src/node.h | 27 +++++++++-- src/node_internals.h | 3 +- 3 files changed, 88 insertions(+), 50 deletions(-) diff --git a/src/node.cc b/src/node.cc index e942c108a15a3c..0fa51b269764f4 100644 --- a/src/node.cc +++ b/src/node.cc @@ -843,6 +843,14 @@ static std::atomic_bool init_called{false}; int InitializeNodeWithArgs(std::vector* argv, std::vector* exec_argv, std::vector* errors) { + return InitializeNodeWithArgs(argv, exec_argv, errors, + ProcessFlags::kNoFlags); +} + +int InitializeNodeWithArgs(std::vector* argv, + std::vector* exec_argv, + std::vector* errors, + ProcessFlags::Flags flags) { // 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::kEnableStdioInheritance)) + 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 1f9afa558d0c8b..5b1404ff8e290a 100644 --- a/src/node.h +++ b/src/node.h @@ -214,6 +214,20 @@ namespace node { class IsolateData; class Environment; +namespace ProcessFlags { +enum Flags : uint64_t { + kNoFlags = 0, + // Enable stdio inheritance, which is disabled by default. + kEnableStdioInheritance = 1 << 0, + // Disable reading the NODE_OPTIONS environment variable. + kDisableNodeOptionsEnv = 1 << 1, + // Do not parse CLI options. + kDisableCLIOptions = 1 << 2, + // Do not initialize ICU. + kNoICU = 1 << 3, +}; +} // 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 +240,16 @@ 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); +// TODO(zcbenz): Turn above overloaded version into below's default argument. +NODE_EXTERN int InitializeNodeWithArgs( + std::vector* argv, + std::vector* exec_argv, + std::vector* errors, + ProcessFlags::Flags flags); enum OptionEnvvarSettings { kAllowedInEnvironment, diff --git a/src/node_internals.h b/src/node_internals.h index dec024bd79f2cd..f21fe9001d9cd9 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::kNoFlags); void TearDownOncePerProcess(); void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s); void SetIsolateMiscHandlers(v8::Isolate* isolate, const IsolateSettings& s);