Skip to content

Instantly share code, notes, and snippets.

@oxc
Last active July 30, 2024 01:05
Show Gist options
  • Save oxc/b91f02b55f4973910e5274a26694238d to your computer and use it in GitHub Desktop.
Save oxc/b91f02b55f4973910e5274a26694238d to your computer and use it in GitHub Desktop.
Call execv (works similar for execvp, execve) on Node 20
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);
}
@oxc
Copy link
Author

oxc commented Jan 7, 2024

args must contain arg0.

Re-execing the current process might look like:

execv(process.execPath, [process.argv0, ...process.execArgv, ...process.argv.slice(1)])

@oxc
Copy link
Author

oxc commented Jan 7, 2024

This gist was inspired by the existing answers to this StackOverflow question by user1629060 (using ffi) and oleksii-rudenko (removing the "exit on close" flag from the streams).

I have also posted it as an answer here: https://stackoverflow.com/a/77774287/1479482

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment