Security News
tea.xyz Spam Plagues npm and RubyGems Package Registries
Tea.xyz, a crypto project aimed at rewarding open source contributions, is once again facing backlash due to an influx of spam packages flooding public package registries.
forkexec
Advanced tools
Readme
This library provides somewhat saner interfaces to Node's child_process module. It's still growing, and most of the interfaces there don't have analogs here yet.
The interfaces in this library conform to Joyent's Best Practices for Error Handling in Node.js. Most notably:
The only interfaces currently provided are:
(args, callback)
: like
child_process.execFile
, but all operational errors are emitted
asynchronously, errors are more descriptive, and there's a crisper summary of
exactly what happened.(args)
:
lower-level function for taking the result of one of Node's child_process
functions and producing a normalized summary of what happened.One of the biggest challenges in using Node's child_process interfaces is properly interpreting the result. When you kick off a child process (as with fork/exec), there are basically four possible outcomes:
error
is non-null, status
is null, and signal
is null)error
is non-null, status
is null, and signal
is non-null)error
is non-null, status
is a non-zero integer, and signal
is null).error
is null, status
is 0, and signal
is null.)Most code doesn't handle (1) at all, since it usually results in the child_process function throwing an exception rather than calling your callback. Most use-cases want to treat (1), (2), and (3) as failure cases and generate a descriptive error for them, but the built-in Errors are not very descriptive.
The interfaces here attempt to make the common case very easy (providing a
descriptive, non-null Error in cases (1) through (3), but not (4)), while still
allowing more complex callers to easily determine exactly what happened. These
interfaces do this by taking the result of the underlying Node API function and
producing an info
object with properties:
Like the built-in child_process.execFile
, this function forks a child process,
exec's the requested command, waits for it to exit, and captures the full stdout
and stderr. The file should be an executable on the caller's PATH. It is
not passed through bash -c
as would happen with child_process.exec
.
forkExecWait(args, callback)
The main argument is:
[ 'ls', '-l' ]
.The following arguments have the same semantics as for Node's built-in
child_process.execFile
except where otherwise noted:
stderr
will be trimmed and included in the error message.
Defaults to false
.The return value is the same as child_process.execFile
except when that
function would throw an exception, in which case this function will return
null
and the error that would have been thrown is instead emitted to the
callback (as you'd probably have expected Node to do).
The callback is invoked as callback(err, info)
, where info
always has
properties:
info.error
is the same as the err
argument.As described above, the interface throws on programmer errors, and these should not be handled. Operational errors are emitted asynchronously. See the four possible outcomes described above for what those are.
Normal command:
forkExecWait({
'argv': [ 'echo', 'hello', 'world' ]
}, function (err, info) {
console.log(info);
});
{ error: null,
status: 0,
signal: null,
stdout: 'hello world\n',
stderr: '' }
Successful fork/exec, command fails:
forkExecWait({
'argv': [ 'grep', 'foobar' '/nonexistent_file' ]
}, function (err, info) {
console.log(info);
});
{ error:
{ [VError: exec "grep foobar /nonexistent_file": exited with status 2]
jse_shortmsg: 'exec "grep foobar /nonexistent_file"',
jse_summary: 'exec "grep foobar /nonexistent_file": exited with status 2',
jse_cause:
{ [VError: exited with status 2]
jse_shortmsg: 'exited with status 2',
jse_summary: 'exited with status 2',
message: 'exited with status 2' },
message: 'exec "grep foobar /nonexistent_file": exited with status 2' },
status: 2,
signal: null,
stdout: '',
stderr: 'grep: /nonexistent_file: No such file or directory\n' }
Failed fork/exec: command not found:
forkExecWait({
'argv': [ 'nonexistent', 'command' ]
}, function (err, info) {
console.log(info);
});
{ error:
{ [VError: exec "nonexistent command": spawn nonexistent ENOENT]
jse_shortmsg: 'exec "nonexistent command"',
jse_summary: 'exec "nonexistent command": spawn nonexistent ENOENT',
jse_cause:
{ [Error: spawn nonexistent ENOENT]
code: 'ENOENT',
errno: 'ENOENT',
syscall: 'spawn nonexistent',
path: 'nonexistent',
cmd: 'nonexistent command' },
message: 'exec "nonexistent command": spawn nonexistent ENOENT' },
status: null,
signal: null,
stdout: '',
stderr: '' }
Failed fork/exec: command is not executable (note: Node throws on this, while this library emits an error asynchronously, since this is an operational error):
forkExecWait({
'argv': [ '/dev/null' ]
}, function (err, info) {
console.log(info);
});
{ error:
{ [VError: exec "/dev/null": spawn EACCES]
jse_shortmsg: 'exec "/dev/null"',
jse_summary: 'exec "/dev/null": spawn EACCES',
jse_cause: { [Error: spawn EACCES] code: 'EACCES', errno: 'EACCES', syscall: 'spawn' },
message: 'exec "/dev/null": spawn EACCES' },
status: null,
signal: null,
stdout: '',
stderr: '' }
Command times out (killed by our SIGKILL after 3 seconds):
forkExecWait({
'argv': [ 'sleep', '4' ],
'timeout': 3000,
}, function (err, info) {
console.log(info);
});
{ error:
{ [VError: exec "sleep 2": unexpectedly terminated by signal SIGKILL]
jse_shortmsg: 'exec "sleep 2"',
jse_summary: 'exec "sleep 2": unexpectedly terminated by signal SIGKILL',
jse_cause:
{ [VError: unexpectedly terminated by signal SIGKILL]
jse_shortmsg: 'unexpectedly terminated by signal SIGKILL',
jse_summary: 'unexpectedly terminated by signal SIGKILL',
message: 'unexpectedly terminated by signal SIGKILL' },
message: 'exec "sleep 2": unexpectedly terminated by signal SIGKILL' },
status: null,
signal: 'SIGKILL',
stdout: '',
stderr: '' }
This lower-level function takes the results of one of the child_process
functions and produces the info
object described above, including a more
descriptive Error (if there was one).
interpretChildProcessResult(args)
Named arguments are:
null
or
an instance of Error.The return value is an info
object with the error
, status
, and signal
properties described above.
As described above, the interface throws on programmer errors, and these should not be handled. There are no operational errors for this interface.
Contributions welcome. Code should be "make prepush" clean. To run "make prepush", you'll need these tools:
If you're changing something non-trivial or user-facing, you may want to submit an issue first.
FAQs
sane child process library
The npm package forkexec receives a total of 20 weekly downloads. As such, forkexec popularity was classified as not popular.
We found that forkexec demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 14 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Tea.xyz, a crypto project aimed at rewarding open source contributions, is once again facing backlash due to an influx of spam packages flooding public package registries.
Security News
As cyber threats become more autonomous, AI-powered defenses are crucial for businesses to stay ahead of attackers who can exploit software vulnerabilities at scale.
Security News
UnitedHealth Group disclosed that the ransomware attack on Change Healthcare compromised protected health information for millions in the U.S., with estimated costs to the company expected to reach $1 billion.