Here is another example using ffi-napi
, which works on Node 20:
https://gist.github.com/oxc/b91f02b55f4973910e5274a26694238d
It was inspired by the existing answers to this question by user1629060 (using ffi) and oleksii-rudenko (removing the "exit on close" flag from the streams).
I only needed execv
, but implementing any of the other variants should work equivalently.
Note that args
is the full array and needs to include arg0 as first element. It does NOT copy path
as first element like in other examples here.
import ref from "ref-napi";
import ffi from "ffi-napi";
import ref_array_di from "ref-array-di";
const ArrayType = ref_array_di(ref);
const StringArray = ArrayType("string");
// from fcntl.h
const F_GETFD = 1; /* get close_on_exec */
const F_SETFD = 2; /* set/clear close_on_exec */
const FD_CLOEXEC = 1; /* actually anything with low bit set goes */
export function execv(path: string, args: string[]): number | never {
const current = ffi.Library(null, {
execv: ["int", ["string", StringArray]],
fcntl: ["int", ["int", "int", "int"]],
});
function dontCloseOnExit(fd: number) {
let flags = current.fcntl(fd, F_GETFD, 0);
if (flags < 0) return flags;
flags &= ~FD_CLOEXEC; //clear FD_CLOEXEC bit
return current.fcntl(fd, F_SETFD, flags);
}
const argsArray = new StringArray(args.length + 1);
for (let i = 0; i < args.length; i++) {
argsArray[i] = args[i];
}
argsArray[args.length] = null;
dontCloseOnExit(process.stdin.fd);
dontCloseOnExit(process.stdout.fd);
dontCloseOnExit(process.stderr.fd);
return current.execv(path, argsArray);
}
node
started with no options, I need to add options like--expose_gc_as=V8GC
or--harmony
, (b) or I just want to open some files and leave their descriptors for the next application that I am going to overload, (c) or I am going through daemonization step and want tofork()
(btw, there is no way to callfork()
either), (d) or anything else people useexec
for in other languages and platforms. – Frowzyffi
module, and exposedexecvp
to the process. Please keep in mindfork
won't work, because V8 has threads, andfork()
syscall only copies main thread, so forked interpreter crashes immediately. – Frowzyexecvp
. It's without ffi, compiled as a native node addon instead. – Lotson