admin管理员组文章数量:1310273
POSIX systems expose family of exec
functions, that allow one to load something maybe different into current process, keeping open file descriptors, process identifier and so on.
This can be done for variety of reasons, and in my case this is bootstrapping — I want to change mand line options of my own process, and then reload it over existing process, so there would be no child process.
Unfortunately, to much of my surprise, I could not find the way to call any of exec*
functions in Node.js. So, what is the correct way to replace currently running Node.js process with other image?
POSIX systems expose family of exec
functions, that allow one to load something maybe different into current process, keeping open file descriptors, process identifier and so on.
This can be done for variety of reasons, and in my case this is bootstrapping — I want to change mand line options of my own process, and then reload it over existing process, so there would be no child process.
Unfortunately, to much of my surprise, I could not find the way to call any of exec*
functions in Node.js. So, what is the correct way to replace currently running Node.js process with other image?
- Consider this question: stackoverflow./questions/4018154/… – clay Commented Dec 15, 2015 at 14:57
- Consider this nodejs/api/child_process.html – mkinawy Commented Dec 15, 2015 at 15:54
- @mkinawy child_process does not overwrite existing process. It spawns a new one, and it will have new PID. – toriningen Commented Dec 15, 2015 at 16:56
- @clay I don't see how is it related. – toriningen Commented Dec 15, 2015 at 16:57
- 1 @OleksiiRudenko please make this into an answer, I will accept it. – toriningen Commented Jun 29, 2017 at 19:51
4 Answers
Reset to default 5I have created a module to invoke execvp function from NodeJS: https://github./OrKoN/native-exec
It works like this:
var exec = require('native-exec');
exec('ls', {
newEnvKey: newEnvValue,
}, '-lsa'); // => the process is replaced with ls, which runs and exits
Since it's a native node addon it requires a C++ piler installed. Works fine in Docker, on Mac OS and Linux. Probably, does not work on Windows. Tested with node 6, 7 and 8.
Here is an example using node-ffi that works with node v10. (alas, not v12)
#!/usr/bin/node
"use strict";
const ffi = require('ffi');
const ref = require('ref');
const ArrayType = require('ref-array');
const stringAry = ArrayType('string');
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('Login: ', (username) => {
username = username.replace(/[^a-z0-9_]/g, "");
rl.close();
execvp("/usr/bin/ssh", "-e", "none", username+'@localhost');
});
function execvp() {
var current = ffi.Library(null,
{ execvp: ['int', ['string',
stringAry]],
dup2: ['int', ['int', 'int']]});
current.dup2(process.stdin._handle.fd, 0);
current.dup2(process.stdout._handle.fd, 1);
current.dup2(process.stderr._handle.fd, 2);
var ret = current.execvp(arguments[0], Array.prototype.slice.call(arguments).concat([ref.NULL]));
}
I ended up using ffi
module, and exported execvp
from libc
.
Here is another example using ffi-napi
, which works on Node 20:
https://gist.github./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);
}
本文标签:
版权声明:本文标题:javascript - A way to call execl, execle, execlp, execv, execvP or execvp from Node.js - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741842607a2400591.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论