/* Copyright 2006 - 2018 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #include "ILibDuktape_ChildProcess.h" #include "ILibDuktapeModSearch.h" #include "../microstack/ILibParsers.h" #include "../microstack/ILibProcessPipe.h" #include "ILibDuktape_Helpers.h" #include "ILibDuktape_ReadableStream.h" #include "ILibDuktape_WritableStream.h" #include "ILibDuktape_EventEmitter.h" #include "ILibDuktape_ScriptContainer.h" #define ILibDuktape_ChildProcess_Process "\xFF_ChildProcess_Process" #define ILibDuktape_ChildProcess_MemBuf "\xFF_ChildProcess_MemBuf" typedef struct ILibDuktape_ChildProcess_SubProcess { duk_context *ctx; void *subProcess; void *chain; ILibProcessPipe_Process childProcess; #ifdef WIN32 int dispatchFlags; #endif ILibDuktape_readableStream *stdOut; ILibDuktape_readableStream *stdErr; ILibDuktape_WritableStream *stdIn; int exitCode; }ILibDuktape_ChildProcess_SubProcess; void ILibDuktape_ChildProcess_SubProcess_StdOut_OnPause(ILibDuktape_readableStream *sender, void *user) { ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)user; if (ILibMemory_CanaryOK(p->childProcess)) { ILibProcessPipe_Pipe_Pause(ILibProcessPipe_Process_GetStdOut(p->childProcess)); } } void ILibDuktape_ChildProcess_SubProcess_StdOut_OnResume(ILibDuktape_readableStream *sender, void *user) { ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)user; if (ILibMemory_CanaryOK(p->childProcess)) { ILibProcessPipe_Pipe_Resume(ILibProcessPipe_Process_GetStdOut(p->childProcess)); } } void ILibDuktape_ChildProcess_SubProcess_StdErr_OnPause(ILibDuktape_readableStream *sender, void *user) { ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)user; if (ILibMemory_CanaryOK(p->childProcess)) { ILibProcessPipe_Pipe_Pause(ILibProcessPipe_Process_GetStdErr(p->childProcess)); } } void ILibDuktape_ChildProcess_SubProcess_StdErr_OnResume(ILibDuktape_readableStream *sender, void *user) { ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)user; if (ILibMemory_CanaryOK(p->childProcess)) { ILibProcessPipe_Pipe_Resume(ILibProcessPipe_Process_GetStdErr(p->childProcess)); } } ILibTransport_DoneState ILibDuktape_ChildProcess_SubProcess_StdIn_WriteHandler(ILibDuktape_WritableStream *stream, char *buffer, int bufferLen, void *user) { ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)user; if (ILibMemory_CanaryOK(p->childProcess)) { return(ILibProcessPipe_Process_WriteStdIn(p->childProcess, buffer, bufferLen, ILibTransport_MemoryOwnership_USER)); } else { return(ILibTransport_DoneState_ERROR); } } void ILibDuktape_ChildProcess_SubProcess_StdIn_EndHandler(ILibDuktape_WritableStream *sender, void *user) { ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)user; if (ILibMemory_CanaryOK(p->childProcess)) { ILibProcessPipe_Process_CloseStdIn(p->childProcess); } } void ILibDuktape_ChildProcess_SubProcess_ExitHandler(ILibProcessPipe_Process sender, int exitCode, void* user); void ILibDuktape_ChildProcess_SubProcess_ExitHandler_sink1(void *chain, void *user) { ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)user; if (!ILibMemory_CanaryOK(p)) { return; } ILibDuktape_ChildProcess_SubProcess_ExitHandler(NULL, p->exitCode, p); } void ILibDuktape_ChildProcess_SubProcess_ExitHandler(ILibProcessPipe_Process sender, int exitCode, void* user) { ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)user; if (!ILibMemory_CanaryOK(p)) { return; } p->exitCode = exitCode; p->childProcess = NULL; duk_push_heapptr(p->ctx, p->subProcess); // [childProcess] #ifdef _POSIX if (duk_has_prop_string(p->ctx, -1, "_sigsink")) { ILibDuktape_EventEmitter_SetupRemoveListener(p->ctx, ILibDuktape_GetProcessObject(p->ctx), "SIGCHLD"); //......][remove][process][SIGCHLD] duk_get_prop_string(p->ctx, -4, "_sigsink"); // [childProcess][remove][process][SIGCHLD][func] duk_pcall_method(p->ctx, 2); duk_pop(p->ctx); // [childProcess] } #endif if (Duktape_GetIntPropertyValue(p->ctx, -1, "\xFF_WaitExit", 0) != 0) { ILibChain_EndContinue(Duktape_GetChain(p->ctx)); } duk_get_prop_string(p->ctx, -1, "emit"); // [childProcess][emit] duk_swap_top(p->ctx, -2); // [emit][this] duk_push_string(p->ctx, "exit"); // [emit][this][exit] duk_push_int(p->ctx, p->exitCode); // [emit][this][exit][exitCode] duk_push_null(p->ctx); // [emit][this][exit][exitCode][sig] if (duk_pcall_method(p->ctx, 3) != 0) { ILibDuktape_Process_UncaughtExceptionEx(p->ctx, "child_process.subProcess.exit(): "); } duk_pop(p->ctx); } void ILibDuktape_ChildProcess_SubProcess_StdOutHandler(ILibProcessPipe_Process sender, char *buffer, int bufferLen, int* bytesConsumed, void* user) { ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)user; if (!ILibMemory_CanaryOK(p)) { return; } ILibDuktape_readableStream_WriteData(p->stdOut, buffer, bufferLen); *bytesConsumed = bufferLen; } void ILibDuktape_ChildProcess_SubProcess_StdErrHandler(ILibProcessPipe_Process sender, char *buffer, int bufferLen, int* bytesConsumed, void* user) { ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)user; if (!ILibMemory_CanaryOK(p)) { return; } ILibDuktape_readableStream_WriteData(p->stdErr, buffer, bufferLen); *bytesConsumed = bufferLen; } void ILibDuktape_ChildProcess_SubProcess_SendOK(ILibProcessPipe_Process sender, void* user) { ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)user; if (!ILibMemory_CanaryOK(p)) { return; } ILibDuktape_WritableStream_Ready(p->stdIn); } duk_ret_t ILibDuktape_ChildProcess_Kill(duk_context *ctx) { duk_push_this(ctx); ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)Duktape_GetBufferProperty(ctx, -1, ILibDuktape_ChildProcess_MemBuf); if (p != NULL) { ILibProcessPipe_Process_SoftKill(p->childProcess); } return(0); } duk_ret_t ILibDuktape_ChildProcess_waitExit(duk_context *ctx) { int timeout = duk_is_number(ctx, 0) ? duk_require_int(ctx, 0) : -1; void *chain = Duktape_GetChain(ctx); if (ILibIsChainBeingDestroyed(chain)) { return(ILibDuktape_Error(ctx, "Cannot waitExit() because current thread is exiting")); } duk_push_this(ctx); // [spawnedProcess] //char *_target = Duktape_GetStringPropertyValue(ctx, -1, "_target", NULL); if (!ILibChain_IsLinkAlive(Duktape_GetPointerProperty(ctx, -1, ILibDuktape_ChildProcess_Manager))) { return(ILibDuktape_Error(ctx, "Cannot waitExit() because JS Engine is exiting")); } duk_push_int(ctx, 1); // [spawnedProcess][flag] duk_put_prop_string(ctx, -2, "\xFF_WaitExit"); // [spawnedProcess] void *mods[] = { ILibGetBaseTimer(Duktape_GetChain(ctx)), Duktape_GetPointerProperty(ctx, -1, ILibDuktape_ChildProcess_Manager), ILibDuktape_Process_GetSignalListener(ctx) }; #ifdef WIN32 HANDLE handles[] = { NULL, NULL, NULL, NULL, NULL }; ILibProcessPipe_Process p = Duktape_GetPointerProperty(ctx, -1, ILibDuktape_ChildProcess_Process); ILibProcessPipe_Process_GetWaitHandles(p, &(handles[0]), &(handles[1]), &(handles[2]), &(handles[3])); ILibChain_Continue(chain, (ILibChain_Link**)mods, 2, timeout, (HANDLE**)handles); #else ILibChain_Continue(chain, (ILibChain_Link**)mods, 3, timeout); #endif return(0); } duk_ret_t ILibDuktape_ChildProcess_SpawnedProcess_Finalizer(duk_context *ctx) { #ifdef WIN32 ILibDuktape_ChildProcess_SubProcess *retVal = (ILibDuktape_ChildProcess_SubProcess*)Duktape_GetBufferProperty(ctx, 0, ILibDuktape_ChildProcess_MemBuf); ILibProcessPipe_Process_RemoveHandlers(retVal->childProcess); #endif duk_get_prop_string(ctx, 0, "kill"); // [kill] duk_dup(ctx, 0); // [kill][this] duk_call_method(ctx, 0); return(0); } #ifndef WIN32 duk_ret_t ILibDuktape_ChildProcess_tcsetsize(duk_context *ctx) { duk_push_this(ctx); int fd = (int)Duktape_GetIntPropertyValue(ctx, -1, "pty", 0); struct winsize ws; ws.ws_row = (int)duk_require_int(ctx, 0); ws.ws_col = (int)duk_require_int(ctx, 1); if (ioctl(fd, TIOCSWINSZ, &ws) == -1) { return(ILibDuktape_Error(ctx, "Error making TIOCSWINSZ/IOCTL")); } return(0); } #endif duk_ret_t ILibDuktape_SpawnedProcess_descriptorSetter(duk_context *ctx) { duk_push_this(ctx); ILibDuktape_ChildProcess_SubProcess *retVal = (ILibDuktape_ChildProcess_SubProcess*)Duktape_GetBufferProperty(ctx, -1, ILibDuktape_ChildProcess_MemBuf); if (retVal != NULL) { duk_push_string(ctx, ILibProcessPipe_Process_GetMetadata(retVal->childProcess)); // [string] duk_get_prop_string(ctx, -1, "split"); // [string][split] duk_swap_top(ctx, -2); // [split][this] duk_push_string(ctx, " [EXIT]"); // [split][this][delim] duk_call_method(ctx, 1); // [array] duk_get_prop_string(ctx, -1, "shift"); // [array][shift] duk_swap_top(ctx, -2); // [shift][this] duk_call_method(ctx, 0); // [string] duk_push_sprintf(ctx, "%s, %s", duk_get_string(ctx, -1), duk_require_string(ctx, 0)); // [string][newVal] ILibProcessPipe_Process_ResetMetadata(retVal->childProcess, (char*)duk_get_string(ctx, -1)); } return(0); } #ifdef _POSIX extern void ILibProcessPipe_Process_Destroy(void *p); duk_ret_t ILibDuktape_SpawnedProcess_SIGCHLD_sink(duk_context *ctx) { int statusCode = duk_require_int(ctx, 1); int pid = duk_require_int(ctx, 2); duk_push_current_function(ctx); // [func] duk_get_prop_string(ctx, -1, "_child"); // [func][child] void *child = duk_get_heapptr(ctx, -1); if (Duktape_GetIntPropertyValue(ctx, -1, "pid", -1) == pid) { // This SIGCHLD is for us. Let's unhook from SIGCHLD ILibDuktape_EventEmitter_SetupRemoveListener(ctx, duk_get_heapptr(ctx, -1), "SIGCHLD"); // [remove][this][SIGCHLD] duk_push_current_function(ctx); // [remove][this][SIGCHLD][func] duk_pcall_method(ctx, 2); // If we got this far, this means the process died without breaking the pipes. // This will happen if the process was spawned as detached, otherwise this is // pretty rare, but can happen if you spawn a login shell, then sudo su, then kill the parent. ILibDuktape_EventEmitter_SetupEmit(ctx, child, "exit"); // [child][emit][this][exit] duk_push_int(ctx, statusCode); // [child][emit][this][exit][code] duk_push_null(ctx); // [child][emit][this][exit][code][null] duk_call_method(ctx, 3); duk_pop(ctx); // ... duk_push_heapptr(ctx, child); // [child] void *mProcess = Duktape_GetPointerProperty(ctx, -1, ILibDuktape_ChildProcess_Process); if (mProcess != NULL) { duk_del_prop_string(ctx, -1, ILibDuktape_ChildProcess_Process); duk_del_prop_string(ctx, -1, ILibDuktape_ChildProcess_MemBuf); ILibProcessPipe_Process_Destroy(mProcess); } } return(0); } #endif ILibDuktape_ChildProcess_SubProcess* ILibDuktape_ChildProcess_SpawnedProcess_PUSH(duk_context *ctx, ILibProcessPipe_Process mProcess, void *callback) { duk_push_object(ctx); // [ChildProcess] ILibDuktape_WriteID(ctx, "childProcess.subProcess"); duk_push_pointer(ctx, mProcess); // [ChildProcess][ptr] duk_put_prop_string(ctx, -2, ILibDuktape_ChildProcess_Process); // [ChildProcess] ILibDuktape_ChildProcess_SubProcess *retVal = (ILibDuktape_ChildProcess_SubProcess*)Duktape_PushBuffer(ctx, sizeof(ILibDuktape_ChildProcess_SubProcess)); duk_put_prop_string(ctx, -2, ILibDuktape_ChildProcess_MemBuf); // [ChildProcess] retVal->ctx = ctx; retVal->subProcess = duk_get_heapptr(ctx, -1); retVal->childProcess = mProcess; retVal->chain = Duktape_GetChain(ctx); ILibDuktape_CreateReadonlyProperty_int(ctx, "pid", ILibProcessPipe_Process_GetPID(mProcess)); ILibDuktape_EventEmitter *emitter = ILibDuktape_EventEmitter_Create(ctx); ILibDuktape_EventEmitter_CreateEventEx(emitter, "exit"); ILibDuktape_EventEmitter_CreateEventEx(emitter, "error"); ILibDuktape_CreateInstanceMethod(ctx, "kill", ILibDuktape_ChildProcess_Kill, 0); ILibDuktape_CreateInstanceMethod(ctx, "waitExit", ILibDuktape_ChildProcess_waitExit, DUK_VARARGS); if (ILibProcessPipe_Process_IsDetached(mProcess) == 0) { ILibDuktape_EventEmitter_PrependOnce(ctx, -1, "~", ILibDuktape_ChildProcess_SpawnedProcess_Finalizer); // Kill child if object is collected while process is alive duk_push_object(ctx); ILibDuktape_WriteID(ctx, "childProcess.subProcess.stdout"); duk_dup(ctx, -2); ILibDuktape_CreateReadonlyProperty(ctx, "parent"); retVal->stdOut = ILibDuktape_ReadableStream_Init(ctx, ILibDuktape_ChildProcess_SubProcess_StdOut_OnPause, ILibDuktape_ChildProcess_SubProcess_StdOut_OnResume, retVal); ILibDuktape_CreateReadonlyProperty(ctx, "stdout"); duk_push_object(ctx); ILibDuktape_WriteID(ctx, "childProcess.subProcess.stderr"); duk_dup(ctx, -2); ILibDuktape_CreateReadonlyProperty(ctx, "parent"); retVal->stdErr = ILibDuktape_ReadableStream_Init(ctx, ILibDuktape_ChildProcess_SubProcess_StdErr_OnPause, ILibDuktape_ChildProcess_SubProcess_StdErr_OnResume, retVal); ILibDuktape_CreateReadonlyProperty(ctx, "stderr"); duk_push_object(ctx); ILibDuktape_WriteID(ctx, "childProcess.subProcess.stdin"); duk_dup(ctx, -2); ILibDuktape_CreateReadonlyProperty(ctx, "parent"); retVal->stdIn = ILibDuktape_WritableStream_Init(ctx, ILibDuktape_ChildProcess_SubProcess_StdIn_WriteHandler, ILibDuktape_ChildProcess_SubProcess_StdIn_EndHandler, retVal); ILibDuktape_CreateReadonlyProperty(ctx, "stdin"); #ifndef WIN32 if (ILibProcessPipe_Process_GetPTY(mProcess) != 0) { duk_push_int(ctx, ILibProcessPipe_Process_GetPTY(mProcess)); ILibDuktape_CreateReadonlyProperty(ctx, "pty"); ILibDuktape_CreateInstanceMethod(ctx, "tcsetsize", ILibDuktape_ChildProcess_tcsetsize, 2); } #endif if (callback != NULL) { ILibDuktape_EventEmitter_AddOnce(emitter, "exit", callback); } char tmp[255]; sprintf_s(tmp, sizeof(tmp), "childProcess (pid=%d)", ILibProcessPipe_Process_GetPID(mProcess)); ILibProcessPipe_Process_ResetMetadata(mProcess, tmp); ILibProcessPipe_Process_AddHandlers(mProcess, 4096, ILibDuktape_ChildProcess_SubProcess_ExitHandler, ILibDuktape_ChildProcess_SubProcess_StdOutHandler, ILibDuktape_ChildProcess_SubProcess_StdErrHandler, ILibDuktape_ChildProcess_SubProcess_SendOK, retVal); } else { if (callback != NULL) { ILibDuktape_EventEmitter_AddOnce(emitter, "exit", callback); } } #ifdef _POSIX ILibDuktape_EventEmitter_SetupOn(ctx, ILibDuktape_GetProcessObject(ctx), "SIGCHLD"); // [child][on][process][SIGCHLD] duk_push_c_function(ctx, ILibDuktape_SpawnedProcess_SIGCHLD_sink, DUK_VARARGS); // [child][on][process][SIGCHLD][func] duk_dup(ctx, -5); // [child][on][process][SIGCHLD][func][child] duk_put_prop_string(ctx, -2, "_child"); // [child][on][process][SIGCHLD][func] duk_dup(ctx, -1); // [child][on][process][SIGCHLD][func][func] duk_put_prop_string(ctx, -6, "_sigsink"); // [child][on][process][SIGCHLD][func] duk_pcall_method(ctx, 2); duk_pop(ctx); // [child] #endif ILibDuktape_CreateEventWithSetterEx(ctx, "descriptorMetadata", ILibDuktape_SpawnedProcess_descriptorSetter); return(retVal); } duk_ret_t ILibDuktape_ChildProcess_Manager_Finalizer(duk_context *ctx) { duk_get_prop_string(ctx, 0, ILibDuktape_ChildProcess_Manager); ILibProcessPipe_Manager manager = (ILibProcessPipe_Manager)duk_get_pointer(ctx, -1); ILibChain_SafeRemove(((ILibChain_Link*)manager)->ParentChain, manager); return(0); } duk_ret_t ILibDuktape_ChildProcess_execFile(duk_context *ctx) { int nargs = duk_get_top(ctx); duk_push_this(ctx); duk_get_prop_string(ctx, -1, ILibDuktape_ChildProcess_Manager); ILibProcessPipe_Manager manager = (ILibProcessPipe_Manager)duk_get_pointer(ctx, -1); duk_size_t targetLen; char *target = (char*)duk_get_lstring(ctx, 0, &targetLen); char **args = NULL; int i, x; void *callback = NULL; ILibProcessPipe_Process p = NULL; ILibProcessPipe_SpawnTypes spawnType = ILibProcessPipe_SpawnTypes_DEFAULT; int uid = -1; char **envargs = NULL; for (i = 0; i < nargs; ++i) { if (duk_is_array(ctx, i) != 0) { int arrLen = (int)duk_get_length(ctx, i); #ifdef WIN32 args = (char**)_alloca((arrLen + 1) * sizeof(char*)); #else args = (char**)alloca((arrLen + 1) * sizeof(char*)); #endif for (x = 0; x < arrLen; ++x) { duk_get_prop_index(ctx, i, x); args[x] = (char*)duk_get_string(ctx, -1); } args[x] = NULL; } else if (duk_is_function(ctx, i)) { callback = duk_get_heapptr(ctx, i); } else if (duk_is_object(ctx, i)) { // Options spawnType = (ILibProcessPipe_SpawnTypes)Duktape_GetIntPropertyValue(ctx, i, "type", (int)ILibProcessPipe_SpawnTypes_DEFAULT); uid = Duktape_GetIntPropertyValue(ctx, i, "uid", -1); #ifdef WIN32 if (uid >= 0 && spawnType == ILibProcessPipe_SpawnTypes_USER) { spawnType = ILibProcessPipe_SpawnTypes_SPECIFIED_USER; } #endif if (Duktape_GetBooleanProperty(ctx, i, "detached", 0) != 0) { spawnType |= ILibProcessPipe_SpawnTypes_POSIX_DETACHED; } if (duk_has_prop_string(ctx, i, "env")) { int ecount = 0; duk_get_prop_string(ctx, i, "env"); // [env] duk_enum(ctx, -1, DUK_ENUM_OWN_PROPERTIES_ONLY); // [env][enum] while (duk_next(ctx, -1, 0)) { ++ecount; duk_pop(ctx); // [env][enum] } if (ecount > 0) { duk_pop(ctx); // [env] duk_enum(ctx, -1, DUK_ENUM_OWN_PROPERTIES_ONLY); // [env][enum] envargs = (char**)duk_push_fixed_buffer(ctx, (ecount+1) * 2*sizeof(void*)); // [env][enum][buf] memset(envargs, 0, (ecount + 1) * 2*sizeof(void*)); duk_insert(ctx, -3); // [buf][env][enum] ecount = 0; while (duk_next(ctx, -1, 1)) // [buf][env][enum][key][val] { envargs[ecount] = (char*)duk_get_string(ctx, -2); envargs[ecount + 1] = (char*)duk_to_string(ctx, -1); ecount += 2; duk_pop_2(ctx); // [buf][env][enum] } } } } } #ifdef WIN32 if (target[0] == '%') { size_t evsize; int pctx = ILibString_IndexOf(target + 1, (int)targetLen - 1, "%", 1); if (pctx > 0) { memcpy_s(ILibScratchPad, sizeof(ILibScratchPad), target + 1, pctx); ILibScratchPad[pctx] = 0; getenv_s(&evsize, ILibScratchPad2, sizeof(ILibScratchPad2), ILibScratchPad); if (evsize > 0) { strncpy_s(ILibScratchPad2 + evsize - 1, sizeof(ILibScratchPad2) - evsize, target + pctx + 2, targetLen - pctx - 2); target = ILibScratchPad2; } } } #endif #ifdef WIN32 p = ILibProcessPipe_Manager_SpawnProcessEx3(manager, target, args, spawnType, (void*)(ILibPtrCAST)(uint64_t)(uid < 0 ? 0 : uid), 0); #else p = ILibProcessPipe_Manager_SpawnProcessEx4(manager, target, args, spawnType, (void*)(ILibPtrCAST)(uint64_t)uid, envargs, 0); #endif if (p == NULL) { return(ILibDuktape_Error(ctx, "child_process.execFile(): Could not exec [%s]", target)); } ILibDuktape_ChildProcess_SpawnedProcess_PUSH(ctx, p, callback); duk_push_string(ctx, target); duk_put_prop_string(ctx, -2, "_target"); duk_push_pointer(ctx, manager); duk_put_prop_string(ctx, -2, ILibDuktape_ChildProcess_Manager); return(1); } void ILibDuktape_ChildProcess_PUSH(duk_context *ctx, void *chain) { duk_push_object(ctx); ILibDuktape_WriteID(ctx, "childProcess"); duk_push_pointer(ctx, (void*)ILibProcessPipe_Manager_Create(chain)); duk_put_prop_string(ctx, -2, ILibDuktape_ChildProcess_Manager); ILibDuktape_CreateFinalizer(ctx, ILibDuktape_ChildProcess_Manager_Finalizer); ILibDuktape_CreateInstanceMethod(ctx, "execFile", ILibDuktape_ChildProcess_execFile, DUK_VARARGS); duk_push_object(ctx); duk_push_int(ctx, 0); duk_put_prop_string(ctx, -2, "DEFAULT"); duk_push_int(ctx, 1); duk_put_prop_string(ctx, -2, "USER"); duk_push_int(ctx, 2); duk_put_prop_string(ctx, -2, "WINLOGON"); duk_push_int(ctx, 3); duk_put_prop_string(ctx, -2, "TERM"); duk_push_int(ctx, 4); duk_put_prop_string(ctx, -2, "DETACHED"); duk_put_prop_string(ctx, -2, "SpawnTypes"); char flags[] = "exports.c_iflags = {'IGNBRK': 01, 'BRKINT': 02, 'IGNPAR': 04, 'PARMRK': 010,'INPCK': 020, 'ISTRIP': 040, 'INLCR': 0100, 'IGNCR': 0200, 'ICRNL': 0400, 'IUCLC': 01000, 'IXON': 02000, 'IXANY': 04000, 'IXOFF': 010000, 'IMAXBEL': 020000};\ exports.c_oflags = {'OPOST': 001, 'OLCUC': 002, 'ONLCR': 004, 'OCRNL': 010, 'ONOCR': 020, 'ONLRET': 040, 'OFILL': 0100, 'OFDEL': 0200};\ exports.c_lflags = {'ISIG': 001, 'ICANON': 002, 'ECHO': 010, 'ECHOE': 020, 'ECHOK': 040, 'ECHONL': 0100, 'NOFLSH': 0200, 'IEXTEN': 0400, 'TOSTOP': 0100000, 'ITOSTOP': 0100000}\ "; ILibDuktape_ModSearch_AddHandler_AlsoIncludeJS(ctx, flags, sizeof(flags) - 1); } void ILibDuktape_ChildProcess_Init(duk_context *ctx) { ILibDuktape_ModSearch_AddHandler(ctx, "child_process", ILibDuktape_ChildProcess_PUSH); } #ifdef __DOXY__ /*! \implements EventEmitter \brief The child_process module provides the ability to spawn child processes. Note: To use, must require('child_process') */ class ChildProcess { public: /*! \brief The specified file is spawned as a child process \param file \ Required. The name or path of the executable file to run \param args \ Optional. List of string arguments \param options Optional. \n cwd \ Current working directory\n env Environment key-value pairs\n timeout Default: 0\n \returns \ */ static ChildProcess execFile(file[, args][, options][, callback]); /*! \brief Event emitted whenever process cannot be killed or spawned \param err The Error */ void error; /*! \brief Event emitted after the child process ends \param code Exit code \param signal \ Not used. */ void exit; /*! \brief Process ID of the child process */ Integer pid; /*! \brief Sends SIGTERM to child process */ void kill(); /*! \brief StdOut ReadableStream */ ReadableStream stdout; /*! \brief StdErr ReadableStream */ ReadableStream stderr; /*! \brief StdIn WritableStream */ WritableStream stdin; }; #endif