Skip to content

Commit

Permalink
src: add flags for controlling process behavior
Browse files Browse the repository at this point in the history
PR-URL: #40339
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Michael Dawson <midawson@redhat.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Shelley Vohr <shelley.vohr@gmail.com>
Reviewed-By: Minwoo Jung <nodecorelab@gmail.com>
  • Loading branch information
zcbenz authored and danielleadams committed Jan 29, 2022
1 parent ab28dc5 commit a9826b0
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 50 deletions.
108 changes: 62 additions & 46 deletions src/node.cc
Expand Up @@ -843,6 +843,14 @@ static std::atomic_bool init_called{false};
int InitializeNodeWithArgs(std::vector<std::string>* argv,
std::vector<std::string>* exec_argv,
std::vector<std::string>* errors) {
return InitializeNodeWithArgs(argv, exec_argv, errors,
ProcessFlags::kNoFlags);
}

int InitializeNodeWithArgs(std::vector<std::string>* argv,
std::vector<std::string>* exec_argv,
std::vector<std::string>* errors,
ProcessFlags::Flags flags) {
// Make sure InitializeNodeWithArgs() is called only once.
CHECK(!init_called.exchange(true));

Expand All @@ -853,7 +861,8 @@ int InitializeNodeWithArgs(std::vector<std::string>* 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.
Expand All @@ -869,67 +878,73 @@ int InitializeNodeWithArgs(std::vector<std::string>* 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<std::string> env_argv =
ParseNodeOptionsEnvVar(node_options, errors);
if (credentials::SafeGetenv("NODE_OPTIONS", &node_options)) {
std::vector<std::string> 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;
Expand All @@ -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;
Expand All @@ -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) {
Expand Down
27 changes: 24 additions & 3 deletions src/node.h
Expand Up @@ -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[]);
Expand All @@ -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<std::string>* argv,
std::vector<std::string>* exec_argv,
std::vector<std::string>* errors);
NODE_EXTERN int InitializeNodeWithArgs(
std::vector<std::string>* argv,
std::vector<std::string>* exec_argv,
std::vector<std::string>* errors);
// TODO(zcbenz): Turn above overloaded version into below's default argument.
NODE_EXTERN int InitializeNodeWithArgs(
std::vector<std::string>* argv,
std::vector<std::string>* exec_argv,
std::vector<std::string>* errors,
ProcessFlags::Flags flags);

enum OptionEnvvarSettings {
kAllowedInEnvironment,
Expand Down
3 changes: 2 additions & 1 deletion src/node_internals.h
Expand Up @@ -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);
Expand Down

0 comments on commit a9826b0

Please sign in to comment.