Skip to content

(v6.x backport) src: allow CLI args in env with NODE_OPTIONS #12677

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
8 changes: 8 additions & 0 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,11 @@ parser.add_option('--without-ssl',
dest='without_ssl',
help='build without SSL (disables crypto, https, inspector, etc.)')

parser.add_option('--without-node-options',
action='store_true',
dest='without_node_options',
help='build without NODE_OPTIONS support')

parser.add_option('--xcode',
action='store_true',
dest='use_xcode',
Expand Down Expand Up @@ -975,6 +980,9 @@ def configure_openssl(o):
o['variables']['openssl_no_asm'] = 1 if options.openssl_no_asm else 0
if options.use_openssl_ca_store:
o['defines'] += ['NODE_OPENSSL_CERT_STORE']
o['variables']['node_without_node_options'] = b(options.without_node_options)
if options.without_node_options:
o['defines'] += ['NODE_WITHOUT_NODE_OPTIONS']
if options.openssl_fips:
o['variables']['openssl_fips'] = options.openssl_fips
fips_dir = os.path.join(root_dir, 'deps', 'openssl', 'fips')
Expand Down
60 changes: 60 additions & 0 deletions doc/api/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,16 @@ added: v6.0.0

Print stack traces for process warnings (including deprecations).

### `--redirect-warnings=file`
<!-- YAML
added: REPLACEME
-->

Write process warnings to the given file instead of printing to stderr. The
file will be created if it does not exist, and will be appended to if it does.
If an error occurs while attempting to write the warning to the file, the
warning will be written to stderr instead.

### `--trace-sync-io`
<!-- YAML
added: v2.1.0
Expand Down Expand Up @@ -322,6 +332,45 @@ added: v6.11.0

When set to `1`, process warnings are silenced.

### `NODE_OPTIONS=options...`
<!-- YAML
added: REPLACEME
-->

`options...` are interpreted as if they had been specified on the command line
before the actual command line (so they can be overriden). Node will exit with
an error if an option that is not allowed in the environment is used, such as
`-p` or a script file.

Node options that are allowed are:
- `--enable-fips`
- `--force-fips`
- `--icu-data-dir`
- `--debug-brk`
- `--debug-port`
- `--debug`
- `--napi-modules`
- `--no-deprecation`
- `--no-warnings`
- `--openssl-config`
- `--redirect-warnings`
- `--require`, `-r`
- `--throw-deprecation`
- `--tls-cipher-list`
- `--trace-deprecation`
- `--trace-sync-io`
- `--trace-warnings`
- `--track-heap-objects`
- `--use-bundled-ca`
- `--use-openssl-ca`
- `--v8-pool-size`
- `--zero-fill-buffers`

V8 options that are allowed are:
- `--abort-on-uncaught-exception`
- `--max_old_space_size`


### `NODE_REPL_HISTORY=file`
<!-- YAML
added: v3.0.0
Expand Down Expand Up @@ -383,6 +432,17 @@ Note: Be aware that unless the child environment is explicitly set, this
evironment variable will be inherited by any child processes, and if they use
OpenSSL, it may cause them to trust the same CAs as node.

### `NODE_REDIRECT_WARNINGS=file`
<!-- YAML
added: REPLACEME
-->

When set, process warnings will be emitted to the given file instead of
printing to stderr. The file will be created if it does not exist, and will be
appended to if it does. If an error occurs while attempting to write the
warning to the file, the warning will be written to stderr instead. This is
equivalent to using the `--redirect-warnings=file` command-line flag.

[emit_warning]: process.html#process_process_emitwarning_warning_name_ctor
[Buffer]: buffer.html#buffer_buffer
[debugger]: debugger.html
Expand Down
17 changes: 17 additions & 0 deletions doc/node.1
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ Silence all process warnings (including deprecations).
.BR \-\-trace\-warnings
Print stack traces for process warnings (including deprecations).

.TP
.BR \-\-redirect\-warnings=\fIfile\fR
Write process warnings to the given file instead of printing to stderr.

.TP
.BR \-\-trace\-sync\-io
Print a stack trace whenever synchronous I/O is detected after the first turn
Expand Down Expand Up @@ -222,6 +226,13 @@ with small\-icu support.
.BR NODE_NO_WARNINGS =\fI1\fR
When set to \fI1\fR, process warnings are silenced.

.TP
.BR NODE_OPTIONS =\fIoptions...\fR
\fBoptions...\fR are interpreted as if they had been specified on the command
line before the actual command line (so they can be overriden). Node will exit
with an error if an option that is not allowed in the environment is used, such
as \fB-p\fR or a script file.

.TP
.BR NODE_REPL_HISTORY =\fIfile\fR
Path to the file used to store the persistent REPL history. The default path
Expand Down Expand Up @@ -255,6 +266,12 @@ containing trusted certificates.
If \fB\-\-use\-openssl\-ca\fR is enabled, this overrides and sets OpenSSL's
file containing trusted certificates.

.TP
.BR NODE_REDIRECT_WARNINGS=\fIfile\fR
Write process warnings to the given file instead of printing to stderr.
(equivalent to using the \-\-redirect\-warnings=\fIfile\fR command-line
argument).

.SH BUGS
Bugs are tracked in GitHub Issues:
.ur https://github.com/nodejs/node/issues
Expand Down
75 changes: 73 additions & 2 deletions lib/internal/process/warning.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,81 @@ const traceWarnings = process.traceProcessWarnings;
const noDeprecation = process.noDeprecation;
const traceDeprecation = process.traceDeprecation;
const throwDeprecation = process.throwDeprecation;
const config = process.binding('config');
const prefix = `(${process.release.name}:${process.pid}) `;

exports.setup = setupProcessWarnings;

var fs;
var cachedFd;
var acquiringFd = false;
function nop() {}

function lazyFs() {
if (!fs)
fs = require('fs');
return fs;
}

function writeOut(message) {
if (console && typeof console.error === 'function')
return console.error(message);
process._rawDebug(message);
}

function onClose(fd) {
return function() {
lazyFs().close(fd, nop);
};
}

function onOpen(cb) {
return function(err, fd) {
acquiringFd = false;
if (fd !== undefined) {
cachedFd = fd;
process.on('exit', onClose(fd));
}
cb(err, fd);
process.emit('_node_warning_fd_acquired', err, fd);
};
}

function onAcquired(message) {
// make a best effort attempt at writing the message
// to the fd. Errors are ignored at this point.
return function(err, fd) {
if (err)
return writeOut(message);
lazyFs().appendFile(fd, `${message}\n`, nop);
};
}

function acquireFd(cb) {
if (cachedFd === undefined && !acquiringFd) {
acquiringFd = true;
lazyFs().open(config.warningFile, 'a', onOpen(cb));
} else if (cachedFd !== undefined && !acquiringFd) {
cb(null, cachedFd);
} else {
process.once('_node_warning_fd_acquired', cb);
}
}

function output(message) {
if (typeof config.warningFile === 'string') {
acquireFd(onAcquired(message));
return;
}
writeOut(message);
}

function doEmitWarning(warning) {
return function() {
process.emit('warning', warning);
};
}

function setupProcessWarnings() {
if (!process.noProcessWarnings && process.env.NODE_NO_WARNINGS !== '1') {
process.on('warning', (warning) => {
Expand All @@ -21,7 +92,7 @@ function setupProcessWarnings() {
var toString = warning.toString;
if (typeof toString !== 'function')
toString = Error.prototype.toString;
console.error(`${prefix}${toString.apply(warning)}`);
output(`${prefix}${toString.apply(warning)}`);
}
});
}
Expand All @@ -44,6 +115,6 @@ function setupProcessWarnings() {
if (throwDeprecation && warning.name === 'DeprecationWarning')
throw warning;
else
process.nextTick(() => process.emit('warning', warning));
process.nextTick(doEmitWarning(warning));
};
}
Loading