@shitiandmw/node-pty 1.1.0-agent.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +69 -0
- package/README.md +170 -0
- package/binding.gyp +111 -0
- package/deps/.editorconfig +2 -0
- package/deps/winpty/.drone.yml +17 -0
- package/deps/winpty/.gitattributes +19 -0
- package/deps/winpty/LICENSE +21 -0
- package/deps/winpty/Makefile +166 -0
- package/deps/winpty/README.md +151 -0
- package/deps/winpty/RELEASES.md +280 -0
- package/deps/winpty/VERSION.txt +1 -0
- package/deps/winpty/configure +167 -0
- package/deps/winpty/misc/BufferResizeTests.cc +90 -0
- package/deps/winpty/misc/ChangeScreenBuffer.cc +53 -0
- package/deps/winpty/misc/ClearConsole.cc +72 -0
- package/deps/winpty/misc/ConinMode.cc +117 -0
- package/deps/winpty/misc/ConinMode.ps1 +116 -0
- package/deps/winpty/misc/ConoutMode.cc +113 -0
- package/deps/winpty/misc/DebugClient.py +42 -0
- package/deps/winpty/misc/DebugServer.py +63 -0
- package/deps/winpty/misc/DumpLines.py +5 -0
- package/deps/winpty/misc/EnableExtendedFlags.txt +46 -0
- package/deps/winpty/misc/Font-Report-June2016/CP437-Consolas.txt +528 -0
- package/deps/winpty/misc/Font-Report-June2016/CP437-Lucida.txt +633 -0
- package/deps/winpty/misc/Font-Report-June2016/CP932.txt +630 -0
- package/deps/winpty/misc/Font-Report-June2016/CP936.txt +630 -0
- package/deps/winpty/misc/Font-Report-June2016/CP949.txt +630 -0
- package/deps/winpty/misc/Font-Report-June2016/CP950.txt +630 -0
- package/deps/winpty/misc/Font-Report-June2016/MinimumWindowWidths.txt +16 -0
- package/deps/winpty/misc/Font-Report-June2016/Results.txt +4 -0
- package/deps/winpty/misc/Font-Report-June2016/Windows10SetFontBugginess.txt +144 -0
- package/deps/winpty/misc/FontSurvey.cc +100 -0
- package/deps/winpty/misc/FormatChar.h +21 -0
- package/deps/winpty/misc/FreezePerfTest.cc +62 -0
- package/deps/winpty/misc/GetCh.cc +20 -0
- package/deps/winpty/misc/GetConsolePos.cc +41 -0
- package/deps/winpty/misc/GetFont.cc +261 -0
- package/deps/winpty/misc/IdentifyConsoleWindow.ps1 +51 -0
- package/deps/winpty/misc/IsNewConsole.cc +87 -0
- package/deps/winpty/misc/MouseInputNotes.txt +90 -0
- package/deps/winpty/misc/MoveConsoleWindow.cc +34 -0
- package/deps/winpty/misc/Notes.txt +219 -0
- package/deps/winpty/misc/OSVersion.cc +27 -0
- package/deps/winpty/misc/ScreenBufferFreezeInactive.cc +101 -0
- package/deps/winpty/misc/ScreenBufferTest.cc +671 -0
- package/deps/winpty/misc/ScreenBufferTest2.cc +151 -0
- package/deps/winpty/misc/SelectAllTest.cc +45 -0
- package/deps/winpty/misc/SetBufferSize.cc +32 -0
- package/deps/winpty/misc/SetCursorPos.cc +10 -0
- package/deps/winpty/misc/SetFont.cc +145 -0
- package/deps/winpty/misc/SetWindowRect.cc +36 -0
- package/deps/winpty/misc/ShowArgv.cc +12 -0
- package/deps/winpty/misc/ShowConsoleInput.cc +40 -0
- package/deps/winpty/misc/Spew.py +5 -0
- package/deps/winpty/misc/TestUtil.cc +172 -0
- package/deps/winpty/misc/UnicodeDoubleWidthTest.cc +102 -0
- package/deps/winpty/misc/UnicodeWideTest1.cc +246 -0
- package/deps/winpty/misc/UnicodeWideTest2.cc +130 -0
- package/deps/winpty/misc/UnixEcho.cc +89 -0
- package/deps/winpty/misc/Utf16Echo.cc +46 -0
- package/deps/winpty/misc/VeryLargeRead.cc +122 -0
- package/deps/winpty/misc/VkEscapeTest.cc +56 -0
- package/deps/winpty/misc/Win10ResizeWhileFrozen.cc +52 -0
- package/deps/winpty/misc/Win10WrapTest1.cc +57 -0
- package/deps/winpty/misc/Win10WrapTest2.cc +30 -0
- package/deps/winpty/misc/Win32Echo1.cc +26 -0
- package/deps/winpty/misc/Win32Echo2.cc +19 -0
- package/deps/winpty/misc/Win32Test1.cc +46 -0
- package/deps/winpty/misc/Win32Test2.cc +70 -0
- package/deps/winpty/misc/Win32Test3.cc +78 -0
- package/deps/winpty/misc/Win32Write1.cc +44 -0
- package/deps/winpty/misc/WindowsBugCrashReader.cc +27 -0
- package/deps/winpty/misc/WriteConsole.cc +106 -0
- package/deps/winpty/misc/build32.sh +9 -0
- package/deps/winpty/misc/build64.sh +9 -0
- package/deps/winpty/misc/color-test.sh +212 -0
- package/deps/winpty/misc/font-notes.txt +300 -0
- package/deps/winpty/misc/winbug-15048.cc +201 -0
- package/deps/winpty/ship/build-pty4j-libpty.bat +36 -0
- package/deps/winpty/ship/common_ship.py +53 -0
- package/deps/winpty/ship/make_msvc_package.py +165 -0
- package/deps/winpty/ship/ship.py +108 -0
- package/deps/winpty/src/agent/Agent.cc +613 -0
- package/deps/winpty/src/agent/Agent.h +103 -0
- package/deps/winpty/src/agent/AgentCreateDesktop.cc +84 -0
- package/deps/winpty/src/agent/AgentCreateDesktop.h +28 -0
- package/deps/winpty/src/agent/ConsoleFont.cc +632 -0
- package/deps/winpty/src/agent/ConsoleFont.h +28 -0
- package/deps/winpty/src/agent/ConsoleInput.cc +852 -0
- package/deps/winpty/src/agent/ConsoleInput.h +109 -0
- package/deps/winpty/src/agent/ConsoleInputReencoding.cc +121 -0
- package/deps/winpty/src/agent/ConsoleInputReencoding.h +36 -0
- package/deps/winpty/src/agent/ConsoleLine.cc +152 -0
- package/deps/winpty/src/agent/ConsoleLine.h +41 -0
- package/deps/winpty/src/agent/Coord.h +87 -0
- package/deps/winpty/src/agent/DebugShowInput.cc +239 -0
- package/deps/winpty/src/agent/DebugShowInput.h +32 -0
- package/deps/winpty/src/agent/DefaultInputMap.cc +422 -0
- package/deps/winpty/src/agent/DefaultInputMap.h +28 -0
- package/deps/winpty/src/agent/DsrSender.h +30 -0
- package/deps/winpty/src/agent/EventLoop.cc +99 -0
- package/deps/winpty/src/agent/EventLoop.h +47 -0
- package/deps/winpty/src/agent/InputMap.cc +246 -0
- package/deps/winpty/src/agent/InputMap.h +114 -0
- package/deps/winpty/src/agent/LargeConsoleRead.cc +71 -0
- package/deps/winpty/src/agent/LargeConsoleRead.h +68 -0
- package/deps/winpty/src/agent/NamedPipe.cc +378 -0
- package/deps/winpty/src/agent/NamedPipe.h +125 -0
- package/deps/winpty/src/agent/Scraper.cc +699 -0
- package/deps/winpty/src/agent/Scraper.h +103 -0
- package/deps/winpty/src/agent/SimplePool.h +75 -0
- package/deps/winpty/src/agent/SmallRect.h +143 -0
- package/deps/winpty/src/agent/Terminal.cc +535 -0
- package/deps/winpty/src/agent/Terminal.h +69 -0
- package/deps/winpty/src/agent/UnicodeEncoding.h +157 -0
- package/deps/winpty/src/agent/UnicodeEncodingTest.cc +189 -0
- package/deps/winpty/src/agent/Win32Console.cc +107 -0
- package/deps/winpty/src/agent/Win32Console.h +67 -0
- package/deps/winpty/src/agent/Win32ConsoleBuffer.cc +193 -0
- package/deps/winpty/src/agent/Win32ConsoleBuffer.h +99 -0
- package/deps/winpty/src/agent/main.cc +114 -0
- package/deps/winpty/src/agent/subdir.mk +61 -0
- package/deps/winpty/src/configurations.gypi +60 -0
- package/deps/winpty/src/debugserver/DebugServer.cc +117 -0
- package/deps/winpty/src/debugserver/subdir.mk +41 -0
- package/deps/winpty/src/include/winpty.h +242 -0
- package/deps/winpty/src/include/winpty_constants.h +131 -0
- package/deps/winpty/src/libwinpty/AgentLocation.cc +75 -0
- package/deps/winpty/src/libwinpty/AgentLocation.h +28 -0
- package/deps/winpty/src/libwinpty/LibWinptyException.h +54 -0
- package/deps/winpty/src/libwinpty/WinptyInternal.h +72 -0
- package/deps/winpty/src/libwinpty/subdir.mk +46 -0
- package/deps/winpty/src/libwinpty/winpty.cc +970 -0
- package/deps/winpty/src/shared/AgentMsg.h +38 -0
- package/deps/winpty/src/shared/BackgroundDesktop.cc +122 -0
- package/deps/winpty/src/shared/BackgroundDesktop.h +73 -0
- package/deps/winpty/src/shared/Buffer.cc +103 -0
- package/deps/winpty/src/shared/Buffer.h +102 -0
- package/deps/winpty/src/shared/DebugClient.cc +187 -0
- package/deps/winpty/src/shared/DebugClient.h +38 -0
- package/deps/winpty/src/shared/GenRandom.cc +138 -0
- package/deps/winpty/src/shared/GenRandom.h +55 -0
- package/deps/winpty/src/shared/GetCommitHash.bat +13 -0
- package/deps/winpty/src/shared/Mutex.h +54 -0
- package/deps/winpty/src/shared/OsModule.h +63 -0
- package/deps/winpty/src/shared/OwnedHandle.cc +36 -0
- package/deps/winpty/src/shared/OwnedHandle.h +45 -0
- package/deps/winpty/src/shared/PrecompiledHeader.h +43 -0
- package/deps/winpty/src/shared/StringBuilder.h +227 -0
- package/deps/winpty/src/shared/StringBuilderTest.cc +114 -0
- package/deps/winpty/src/shared/StringUtil.cc +55 -0
- package/deps/winpty/src/shared/StringUtil.h +80 -0
- package/deps/winpty/src/shared/TimeMeasurement.h +63 -0
- package/deps/winpty/src/shared/UnixCtrlChars.h +45 -0
- package/deps/winpty/src/shared/UpdateGenVersion.bat +20 -0
- package/deps/winpty/src/shared/WindowsSecurity.cc +460 -0
- package/deps/winpty/src/shared/WindowsSecurity.h +104 -0
- package/deps/winpty/src/shared/WindowsVersion.cc +252 -0
- package/deps/winpty/src/shared/WindowsVersion.h +29 -0
- package/deps/winpty/src/shared/WinptyAssert.cc +55 -0
- package/deps/winpty/src/shared/WinptyAssert.h +64 -0
- package/deps/winpty/src/shared/WinptyException.cc +57 -0
- package/deps/winpty/src/shared/WinptyException.h +43 -0
- package/deps/winpty/src/shared/WinptyVersion.cc +42 -0
- package/deps/winpty/src/shared/WinptyVersion.h +27 -0
- package/deps/winpty/src/shared/winpty_snprintf.h +99 -0
- package/deps/winpty/src/subdir.mk +5 -0
- package/deps/winpty/src/tests/subdir.mk +28 -0
- package/deps/winpty/src/tests/trivial_test.cc +158 -0
- package/deps/winpty/src/unix-adapter/InputHandler.cc +114 -0
- package/deps/winpty/src/unix-adapter/InputHandler.h +56 -0
- package/deps/winpty/src/unix-adapter/OutputHandler.cc +80 -0
- package/deps/winpty/src/unix-adapter/OutputHandler.h +53 -0
- package/deps/winpty/src/unix-adapter/Util.cc +86 -0
- package/deps/winpty/src/unix-adapter/Util.h +31 -0
- package/deps/winpty/src/unix-adapter/WakeupFd.cc +70 -0
- package/deps/winpty/src/unix-adapter/WakeupFd.h +42 -0
- package/deps/winpty/src/unix-adapter/main.cc +729 -0
- package/deps/winpty/src/unix-adapter/subdir.mk +41 -0
- package/deps/winpty/src/winpty.gyp +234 -0
- package/deps/winpty/vcbuild.bat +83 -0
- package/lib/conpty_console_list_agent.js +16 -0
- package/lib/conpty_console_list_agent.js.map +1 -0
- package/lib/eventEmitter2.js +47 -0
- package/lib/eventEmitter2.js.map +1 -0
- package/lib/eventEmitter2.test.js +30 -0
- package/lib/eventEmitter2.test.js.map +1 -0
- package/lib/index.js +52 -0
- package/lib/index.js.map +1 -0
- package/lib/interfaces.js +7 -0
- package/lib/interfaces.js.map +1 -0
- package/lib/shared/conout.js +11 -0
- package/lib/shared/conout.js.map +1 -0
- package/lib/terminal.js +190 -0
- package/lib/terminal.js.map +1 -0
- package/lib/terminal.test.js +139 -0
- package/lib/terminal.test.js.map +1 -0
- package/lib/testUtils.test.js +28 -0
- package/lib/testUtils.test.js.map +1 -0
- package/lib/types.js +7 -0
- package/lib/types.js.map +1 -0
- package/lib/unixTerminal.js +346 -0
- package/lib/unixTerminal.js.map +1 -0
- package/lib/unixTerminal.test.js +351 -0
- package/lib/unixTerminal.test.js.map +1 -0
- package/lib/utils.js +39 -0
- package/lib/utils.js.map +1 -0
- package/lib/windowsConoutConnection.js +125 -0
- package/lib/windowsConoutConnection.js.map +1 -0
- package/lib/windowsPtyAgent.js +320 -0
- package/lib/windowsPtyAgent.js.map +1 -0
- package/lib/windowsPtyAgent.test.js +90 -0
- package/lib/windowsPtyAgent.test.js.map +1 -0
- package/lib/windowsTerminal.js +199 -0
- package/lib/windowsTerminal.js.map +1 -0
- package/lib/windowsTerminal.test.js +219 -0
- package/lib/windowsTerminal.test.js.map +1 -0
- package/lib/worker/conoutSocketWorker.js +22 -0
- package/lib/worker/conoutSocketWorker.js.map +1 -0
- package/package.json +68 -0
- package/prebuilds/darwin-arm64/pty.node +0 -0
- package/prebuilds/darwin-arm64/spawn-helper +0 -0
- package/prebuilds/darwin-x64/pty.node +0 -0
- package/prebuilds/darwin-x64/spawn-helper +0 -0
- package/prebuilds/win32-arm64/conpty/OpenConsole.exe +0 -0
- package/prebuilds/win32-arm64/conpty/conpty.dll +0 -0
- package/prebuilds/win32-arm64/conpty.node +0 -0
- package/prebuilds/win32-arm64/conpty.pdb +0 -0
- package/prebuilds/win32-arm64/conpty_console_list.node +0 -0
- package/prebuilds/win32-arm64/conpty_console_list.pdb +0 -0
- package/prebuilds/win32-arm64/pty.node +0 -0
- package/prebuilds/win32-arm64/pty.pdb +0 -0
- package/prebuilds/win32-arm64/winpty-agent.exe +0 -0
- package/prebuilds/win32-arm64/winpty-agent.pdb +0 -0
- package/prebuilds/win32-arm64/winpty.dll +0 -0
- package/prebuilds/win32-arm64/winpty.pdb +0 -0
- package/prebuilds/win32-x64/conpty/OpenConsole.exe +0 -0
- package/prebuilds/win32-x64/conpty/conpty.dll +0 -0
- package/prebuilds/win32-x64/conpty.node +0 -0
- package/prebuilds/win32-x64/conpty.pdb +0 -0
- package/prebuilds/win32-x64/conpty_console_list.node +0 -0
- package/prebuilds/win32-x64/conpty_console_list.pdb +0 -0
- package/prebuilds/win32-x64/pty.node +0 -0
- package/prebuilds/win32-x64/pty.pdb +0 -0
- package/prebuilds/win32-x64/winpty-agent.exe +0 -0
- package/prebuilds/win32-x64/winpty-agent.pdb +0 -0
- package/prebuilds/win32-x64/winpty.dll +0 -0
- package/prebuilds/win32-x64/winpty.pdb +0 -0
- package/scripts/gen-compile-commands.js +8 -0
- package/scripts/increment-version.js +54 -0
- package/scripts/post-install.js +99 -0
- package/scripts/prebuild.js +39 -0
- package/scripts/sync-prebuild.js +31 -0
- package/scripts/verify-darwin-fd-leak.js +63 -0
- package/src/conpty_console_list_agent.ts +15 -0
- package/src/eventEmitter2.test.ts +30 -0
- package/src/eventEmitter2.ts +48 -0
- package/src/index.ts +52 -0
- package/src/interfaces.ts +130 -0
- package/src/native.d.ts +54 -0
- package/src/shared/conout.ts +15 -0
- package/src/terminal.test.ts +119 -0
- package/src/terminal.ts +211 -0
- package/src/testUtils.test.ts +23 -0
- package/src/tsconfig.json +22 -0
- package/src/types.ts +15 -0
- package/src/unix/pty.cc +808 -0
- package/src/unix/spawn-helper.cc +23 -0
- package/src/unixTerminal.test.ts +367 -0
- package/src/unixTerminal.ts +388 -0
- package/src/utils.ts +29 -0
- package/src/win/conpty.cc +583 -0
- package/src/win/conpty.h +41 -0
- package/src/win/conpty_console_list.cc +44 -0
- package/src/win/path_util.cc +95 -0
- package/src/win/path_util.h +26 -0
- package/src/win/winpty.cc +333 -0
- package/src/windowsConoutConnection.ts +82 -0
- package/src/windowsPtyAgent.test.ts +94 -0
- package/src/windowsPtyAgent.ts +321 -0
- package/src/windowsTerminal.test.ts +229 -0
- package/src/windowsTerminal.ts +203 -0
- package/src/worker/conoutSocketWorker.ts +22 -0
- package/third_party/conpty/1.23.251008001/win10-arm64/OpenConsole.exe +0 -0
- package/third_party/conpty/1.23.251008001/win10-arm64/conpty.dll +0 -0
- package/third_party/conpty/1.23.251008001/win10-x64/OpenConsole.exe +0 -0
- package/third_party/conpty/1.23.251008001/win10-x64/conpty.dll +0 -0
- package/typings/node-pty.d.ts +211 -0
package/src/unix/pty.cc
ADDED
|
@@ -0,0 +1,808 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2012-2015, Christopher Jeffrey (MIT License)
|
|
3
|
+
* Copyright (c) 2017, Daniel Imms (MIT License)
|
|
4
|
+
*
|
|
5
|
+
* pty.cc:
|
|
6
|
+
* This file is responsible for starting processes
|
|
7
|
+
* with pseudo-terminal file descriptors.
|
|
8
|
+
*
|
|
9
|
+
* See:
|
|
10
|
+
* man pty
|
|
11
|
+
* man tty_ioctl
|
|
12
|
+
* man termios
|
|
13
|
+
* man forkpty
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Includes
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
#define NODE_ADDON_API_DISABLE_DEPRECATED
|
|
21
|
+
#include <napi.h>
|
|
22
|
+
#include <assert.h>
|
|
23
|
+
#include <errno.h>
|
|
24
|
+
#include <string.h>
|
|
25
|
+
#include <stdlib.h>
|
|
26
|
+
#include <unistd.h>
|
|
27
|
+
#include <thread>
|
|
28
|
+
|
|
29
|
+
#include <sys/types.h>
|
|
30
|
+
#include <sys/stat.h>
|
|
31
|
+
#include <sys/ioctl.h>
|
|
32
|
+
#include <sys/wait.h>
|
|
33
|
+
#include <fcntl.h>
|
|
34
|
+
#include <signal.h>
|
|
35
|
+
|
|
36
|
+
/* forkpty */
|
|
37
|
+
/* http://www.gnu.org/software/gnulib/manual/html_node/forkpty.html */
|
|
38
|
+
#if defined(__linux__)
|
|
39
|
+
#include <pty.h>
|
|
40
|
+
#elif defined(__APPLE__)
|
|
41
|
+
#include <util.h>
|
|
42
|
+
#elif defined(__FreeBSD__)
|
|
43
|
+
#include <libutil.h>
|
|
44
|
+
#include <termios.h>
|
|
45
|
+
#elif defined(__OpenBSD__)
|
|
46
|
+
#include <util.h>
|
|
47
|
+
#include <termios.h>
|
|
48
|
+
#endif
|
|
49
|
+
|
|
50
|
+
/* Some platforms name VWERASE and VDISCARD differently */
|
|
51
|
+
#if !defined(VWERASE) && defined(VWERSE)
|
|
52
|
+
#define VWERASE VWERSE
|
|
53
|
+
#endif
|
|
54
|
+
#if !defined(VDISCARD) && defined(VDISCRD)
|
|
55
|
+
#define VDISCARD VDISCRD
|
|
56
|
+
#endif
|
|
57
|
+
|
|
58
|
+
/* for pty_getproc */
|
|
59
|
+
#if defined(__linux__)
|
|
60
|
+
#include <stdio.h>
|
|
61
|
+
#include <stdint.h>
|
|
62
|
+
#elif defined(__APPLE__)
|
|
63
|
+
#include <libproc.h>
|
|
64
|
+
#include <os/availability.h>
|
|
65
|
+
#include <paths.h>
|
|
66
|
+
#include <spawn.h>
|
|
67
|
+
#include <sys/event.h>
|
|
68
|
+
#include <sys/sysctl.h>
|
|
69
|
+
#include <termios.h>
|
|
70
|
+
#endif
|
|
71
|
+
|
|
72
|
+
/* NSIG - macro for highest signal + 1, should be defined */
|
|
73
|
+
#ifndef NSIG
|
|
74
|
+
#define NSIG 32
|
|
75
|
+
#endif
|
|
76
|
+
|
|
77
|
+
/* macOS 10.14 back does not define this constant */
|
|
78
|
+
#ifndef POSIX_SPAWN_SETSID
|
|
79
|
+
#define POSIX_SPAWN_SETSID 1024
|
|
80
|
+
#endif
|
|
81
|
+
|
|
82
|
+
/* environ for execvpe */
|
|
83
|
+
/* node/src/node_child_process.cc */
|
|
84
|
+
#if !defined(__APPLE__)
|
|
85
|
+
extern char **environ;
|
|
86
|
+
#endif
|
|
87
|
+
|
|
88
|
+
#if defined(__APPLE__)
|
|
89
|
+
extern "C" {
|
|
90
|
+
// Changes the current thread's directory to a path or directory file
|
|
91
|
+
// descriptor. libpthread only exposes a syscall wrapper starting in
|
|
92
|
+
// macOS 10.12, but the system call dates back to macOS 10.5. On older OSes,
|
|
93
|
+
// the syscall is issued directly.
|
|
94
|
+
int pthread_chdir_np(const char* dir) API_AVAILABLE(macosx(10.12));
|
|
95
|
+
int pthread_fchdir_np(int fd) API_AVAILABLE(macosx(10.12));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
#define HANDLE_EINTR(x) ({ \
|
|
99
|
+
int eintr_wrapper_counter = 0; \
|
|
100
|
+
decltype(x) eintr_wrapper_result; \
|
|
101
|
+
do { \
|
|
102
|
+
eintr_wrapper_result = (x); \
|
|
103
|
+
} while (eintr_wrapper_result == -1 && errno == EINTR && \
|
|
104
|
+
eintr_wrapper_counter++ < 100); \
|
|
105
|
+
eintr_wrapper_result; \
|
|
106
|
+
})
|
|
107
|
+
#endif
|
|
108
|
+
|
|
109
|
+
struct ExitEvent {
|
|
110
|
+
int exit_code = 0, signal_code = 0;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
void SetupExitCallback(Napi::Env env, Napi::Function cb, pid_t pid) {
|
|
114
|
+
std::thread *th = new std::thread;
|
|
115
|
+
// Don't use Napi::AsyncWorker which is limited by UV_THREADPOOL_SIZE.
|
|
116
|
+
auto tsfn = Napi::ThreadSafeFunction::New(
|
|
117
|
+
env,
|
|
118
|
+
cb, // JavaScript function called asynchronously
|
|
119
|
+
"SetupExitCallback_resource", // Name
|
|
120
|
+
0, // Unlimited queue
|
|
121
|
+
1, // Only one thread will use this initially
|
|
122
|
+
[th](Napi::Env) { // Finalizer used to clean threads up
|
|
123
|
+
th->join();
|
|
124
|
+
delete th;
|
|
125
|
+
});
|
|
126
|
+
*th = std::thread([tsfn = std::move(tsfn), pid] {
|
|
127
|
+
auto callback = [](Napi::Env env, Napi::Function cb, ExitEvent *exit_event) {
|
|
128
|
+
cb.Call({Napi::Number::New(env, exit_event->exit_code),
|
|
129
|
+
Napi::Number::New(env, exit_event->signal_code)});
|
|
130
|
+
delete exit_event;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
int ret;
|
|
134
|
+
int stat_loc;
|
|
135
|
+
#if defined(__APPLE__)
|
|
136
|
+
// Based on
|
|
137
|
+
// https://source.chromium.org/chromium/chromium/src/+/main:base/process/kill_mac.cc;l=35-69?
|
|
138
|
+
int kq = HANDLE_EINTR(kqueue());
|
|
139
|
+
struct kevent change = {0};
|
|
140
|
+
EV_SET(&change, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
|
|
141
|
+
ret = HANDLE_EINTR(kevent(kq, &change, 1, NULL, 0, NULL));
|
|
142
|
+
if (ret == -1) {
|
|
143
|
+
if (errno == ESRCH) {
|
|
144
|
+
// At this point, one of the following has occurred:
|
|
145
|
+
// 1. The process has died but has not yet been reaped.
|
|
146
|
+
// 2. The process has died and has already been reaped.
|
|
147
|
+
// 3. The process is in the process of dying. It's no longer
|
|
148
|
+
// kqueueable, but it may not be waitable yet either. Mark calls
|
|
149
|
+
// this case the "zombie death race".
|
|
150
|
+
ret = HANDLE_EINTR(waitpid(pid, &stat_loc, WNOHANG));
|
|
151
|
+
if (ret == 0) {
|
|
152
|
+
ret = kill(pid, SIGKILL);
|
|
153
|
+
if (ret != -1) {
|
|
154
|
+
HANDLE_EINTR(waitpid(pid, &stat_loc, 0));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
} else {
|
|
159
|
+
struct kevent event = {0};
|
|
160
|
+
ret = HANDLE_EINTR(kevent(kq, NULL, 0, &event, 1, NULL));
|
|
161
|
+
if (ret == 1) {
|
|
162
|
+
if ((event.fflags & NOTE_EXIT) &&
|
|
163
|
+
(event.ident == static_cast<uintptr_t>(pid))) {
|
|
164
|
+
// The process is dead or dying. This won't block for long, if at
|
|
165
|
+
// all.
|
|
166
|
+
HANDLE_EINTR(waitpid(pid, &stat_loc, 0));
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (kq != -1) {
|
|
171
|
+
close(kq);
|
|
172
|
+
}
|
|
173
|
+
#else
|
|
174
|
+
while (true) {
|
|
175
|
+
errno = 0;
|
|
176
|
+
if ((ret = waitpid(pid, &stat_loc, 0)) != pid) {
|
|
177
|
+
if (ret == -1 && errno == EINTR) {
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
if (ret == -1 && errno == ECHILD) {
|
|
181
|
+
// XXX node v0.8.x seems to have this problem.
|
|
182
|
+
// waitpid is already handled elsewhere.
|
|
183
|
+
;
|
|
184
|
+
} else {
|
|
185
|
+
assert(false);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
#endif
|
|
191
|
+
ExitEvent *exit_event = new ExitEvent;
|
|
192
|
+
if (WIFEXITED(stat_loc)) {
|
|
193
|
+
exit_event->exit_code = WEXITSTATUS(stat_loc); // errno?
|
|
194
|
+
}
|
|
195
|
+
if (WIFSIGNALED(stat_loc)) {
|
|
196
|
+
exit_event->signal_code = WTERMSIG(stat_loc);
|
|
197
|
+
}
|
|
198
|
+
auto status = tsfn.BlockingCall(exit_event, callback); // In main thread
|
|
199
|
+
switch (status) {
|
|
200
|
+
case napi_closing:
|
|
201
|
+
break;
|
|
202
|
+
|
|
203
|
+
case napi_queue_full:
|
|
204
|
+
Napi::Error::Fatal("SetupExitCallback", "Queue was full");
|
|
205
|
+
|
|
206
|
+
case napi_ok:
|
|
207
|
+
if (tsfn.Release() != napi_ok) {
|
|
208
|
+
Napi::Error::Fatal("SetupExitCallback", "ThreadSafeFunction.Release() failed");
|
|
209
|
+
}
|
|
210
|
+
break;
|
|
211
|
+
|
|
212
|
+
default:
|
|
213
|
+
Napi::Error::Fatal("SetupExitCallback", "ThreadSafeFunction.BlockingCall() failed");
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Methods
|
|
220
|
+
*/
|
|
221
|
+
|
|
222
|
+
Napi::Value PtyFork(const Napi::CallbackInfo& info);
|
|
223
|
+
Napi::Value PtyOpen(const Napi::CallbackInfo& info);
|
|
224
|
+
Napi::Value PtyResize(const Napi::CallbackInfo& info);
|
|
225
|
+
Napi::Value PtyGetProc(const Napi::CallbackInfo& info);
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Functions
|
|
229
|
+
*/
|
|
230
|
+
|
|
231
|
+
static int
|
|
232
|
+
pty_nonblock(int);
|
|
233
|
+
|
|
234
|
+
#if defined(__APPLE__)
|
|
235
|
+
static char *
|
|
236
|
+
pty_getproc(int);
|
|
237
|
+
#else
|
|
238
|
+
static char *
|
|
239
|
+
pty_getproc(int, char *);
|
|
240
|
+
#endif
|
|
241
|
+
|
|
242
|
+
#if defined(__APPLE__) || defined(__OpenBSD__)
|
|
243
|
+
static void
|
|
244
|
+
pty_posix_spawn(char** argv, char** env,
|
|
245
|
+
const struct termios *termp,
|
|
246
|
+
const struct winsize *winp,
|
|
247
|
+
int* master,
|
|
248
|
+
pid_t* pid,
|
|
249
|
+
int* err);
|
|
250
|
+
#endif
|
|
251
|
+
|
|
252
|
+
struct DelBuf {
|
|
253
|
+
int len;
|
|
254
|
+
DelBuf(int len) : len(len) {}
|
|
255
|
+
void operator()(char **p) {
|
|
256
|
+
if (p == nullptr)
|
|
257
|
+
return;
|
|
258
|
+
for (int i = 0; i < len; i++)
|
|
259
|
+
free(p[i]);
|
|
260
|
+
delete[] p;
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
Napi::Value PtyFork(const Napi::CallbackInfo& info) {
|
|
265
|
+
Napi::Env napiEnv(info.Env());
|
|
266
|
+
Napi::HandleScope scope(napiEnv);
|
|
267
|
+
|
|
268
|
+
if (info.Length() != 11 ||
|
|
269
|
+
!info[0].IsString() ||
|
|
270
|
+
!info[1].IsArray() ||
|
|
271
|
+
!info[2].IsArray() ||
|
|
272
|
+
!info[3].IsString() ||
|
|
273
|
+
!info[4].IsNumber() ||
|
|
274
|
+
!info[5].IsNumber() ||
|
|
275
|
+
!info[6].IsNumber() ||
|
|
276
|
+
!info[7].IsNumber() ||
|
|
277
|
+
!info[8].IsBoolean() ||
|
|
278
|
+
!info[9].IsString() ||
|
|
279
|
+
!info[10].IsFunction()) {
|
|
280
|
+
throw Napi::Error::New(napiEnv, "Usage: pty.fork(file, args, env, cwd, cols, rows, uid, gid, utf8, helperPath, onexit)");
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// file
|
|
284
|
+
std::string file = info[0].As<Napi::String>();
|
|
285
|
+
|
|
286
|
+
// args
|
|
287
|
+
Napi::Array argv_ = info[1].As<Napi::Array>();
|
|
288
|
+
|
|
289
|
+
// env
|
|
290
|
+
Napi::Array env_ = info[2].As<Napi::Array>();
|
|
291
|
+
int envc = env_.Length();
|
|
292
|
+
std::unique_ptr<char *, DelBuf> env_unique_ptr(new char *[envc + 1], DelBuf(envc + 1));
|
|
293
|
+
char **env = env_unique_ptr.get();
|
|
294
|
+
env[envc] = NULL;
|
|
295
|
+
for (int i = 0; i < envc; i++) {
|
|
296
|
+
std::string pair = env_.Get(i).As<Napi::String>();
|
|
297
|
+
env[i] = strdup(pair.c_str());
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// cwd
|
|
301
|
+
std::string cwd_ = info[3].As<Napi::String>();
|
|
302
|
+
|
|
303
|
+
// size
|
|
304
|
+
struct winsize winp;
|
|
305
|
+
winp.ws_col = info[4].As<Napi::Number>().Int32Value();
|
|
306
|
+
winp.ws_row = info[5].As<Napi::Number>().Int32Value();
|
|
307
|
+
winp.ws_xpixel = 0;
|
|
308
|
+
winp.ws_ypixel = 0;
|
|
309
|
+
|
|
310
|
+
#if !defined(__APPLE__)
|
|
311
|
+
// uid / gid
|
|
312
|
+
int uid = info[6].As<Napi::Number>().Int32Value();
|
|
313
|
+
int gid = info[7].As<Napi::Number>().Int32Value();
|
|
314
|
+
#endif
|
|
315
|
+
|
|
316
|
+
// termios
|
|
317
|
+
struct termios t = termios();
|
|
318
|
+
struct termios *term = &t;
|
|
319
|
+
term->c_iflag = ICRNL | IXON | IXANY | IMAXBEL | BRKINT;
|
|
320
|
+
if (info[8].As<Napi::Boolean>().Value()) {
|
|
321
|
+
#if defined(IUTF8)
|
|
322
|
+
term->c_iflag |= IUTF8;
|
|
323
|
+
#endif
|
|
324
|
+
}
|
|
325
|
+
term->c_oflag = OPOST | ONLCR;
|
|
326
|
+
term->c_cflag = CREAD | CS8 | HUPCL;
|
|
327
|
+
term->c_lflag = ICANON | ISIG | IEXTEN | ECHO | ECHOE | ECHOK | ECHOKE | ECHOCTL;
|
|
328
|
+
|
|
329
|
+
term->c_cc[VEOF] = 4;
|
|
330
|
+
term->c_cc[VEOL] = -1;
|
|
331
|
+
term->c_cc[VEOL2] = -1;
|
|
332
|
+
term->c_cc[VERASE] = 0x7f;
|
|
333
|
+
term->c_cc[VWERASE] = 23;
|
|
334
|
+
term->c_cc[VKILL] = 21;
|
|
335
|
+
term->c_cc[VREPRINT] = 18;
|
|
336
|
+
term->c_cc[VINTR] = 3;
|
|
337
|
+
term->c_cc[VQUIT] = 0x1c;
|
|
338
|
+
term->c_cc[VSUSP] = 26;
|
|
339
|
+
term->c_cc[VSTART] = 17;
|
|
340
|
+
term->c_cc[VSTOP] = 19;
|
|
341
|
+
term->c_cc[VLNEXT] = 22;
|
|
342
|
+
term->c_cc[VDISCARD] = 15;
|
|
343
|
+
term->c_cc[VMIN] = 1;
|
|
344
|
+
term->c_cc[VTIME] = 0;
|
|
345
|
+
|
|
346
|
+
#if (__APPLE__)
|
|
347
|
+
term->c_cc[VDSUSP] = 25;
|
|
348
|
+
term->c_cc[VSTATUS] = 20;
|
|
349
|
+
#endif
|
|
350
|
+
|
|
351
|
+
cfsetispeed(term, B38400);
|
|
352
|
+
cfsetospeed(term, B38400);
|
|
353
|
+
|
|
354
|
+
// helperPath
|
|
355
|
+
std::string helper_path = info[9].As<Napi::String>();
|
|
356
|
+
|
|
357
|
+
pid_t pid;
|
|
358
|
+
int master;
|
|
359
|
+
#if defined(__APPLE__)
|
|
360
|
+
int argc = argv_.Length();
|
|
361
|
+
int argl = argc + 4;
|
|
362
|
+
std::unique_ptr<char *, DelBuf> argv_unique_ptr(new char *[argl], DelBuf(argl));
|
|
363
|
+
char **argv = argv_unique_ptr.get();
|
|
364
|
+
argv[0] = strdup(helper_path.c_str());
|
|
365
|
+
argv[1] = strdup(cwd_.c_str());
|
|
366
|
+
argv[2] = strdup(file.c_str());
|
|
367
|
+
argv[argl - 1] = NULL;
|
|
368
|
+
for (int i = 0; i < argc; i++) {
|
|
369
|
+
std::string arg = argv_.Get(i).As<Napi::String>();
|
|
370
|
+
argv[i + 3] = strdup(arg.c_str());
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
int err = -1;
|
|
374
|
+
pty_posix_spawn(argv, env, term, &winp, &master, &pid, &err);
|
|
375
|
+
if (err != 0) {
|
|
376
|
+
throw Napi::Error::New(napiEnv, "posix_spawnp failed.");
|
|
377
|
+
}
|
|
378
|
+
if (pty_nonblock(master) == -1) {
|
|
379
|
+
throw Napi::Error::New(napiEnv, "Could not set master fd to nonblocking.");
|
|
380
|
+
}
|
|
381
|
+
#else
|
|
382
|
+
int argc = argv_.Length();
|
|
383
|
+
int argl = argc + 2;
|
|
384
|
+
std::unique_ptr<char *, DelBuf> argv_unique_ptr(new char *[argl], DelBuf(argl));
|
|
385
|
+
char** argv = argv_unique_ptr.get();
|
|
386
|
+
argv[0] = strdup(file.c_str());
|
|
387
|
+
argv[argl - 1] = NULL;
|
|
388
|
+
for (int i = 0; i < argc; i++) {
|
|
389
|
+
std::string arg = argv_.Get(i).As<Napi::String>();
|
|
390
|
+
argv[i + 1] = strdup(arg.c_str());
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
sigset_t newmask, oldmask;
|
|
394
|
+
struct sigaction sig_action;
|
|
395
|
+
// temporarily block all signals
|
|
396
|
+
// this is needed due to a race condition in openpty
|
|
397
|
+
// and to avoid running signal handlers in the child
|
|
398
|
+
// before exec* happened
|
|
399
|
+
sigfillset(&newmask);
|
|
400
|
+
pthread_sigmask(SIG_SETMASK, &newmask, &oldmask);
|
|
401
|
+
|
|
402
|
+
pid = forkpty(&master, nullptr, static_cast<termios*>(term), static_cast<winsize*>(&winp));
|
|
403
|
+
|
|
404
|
+
if (!pid) {
|
|
405
|
+
// remove all signal handler from child
|
|
406
|
+
sig_action.sa_handler = SIG_DFL;
|
|
407
|
+
sig_action.sa_flags = 0;
|
|
408
|
+
sigemptyset(&sig_action.sa_mask);
|
|
409
|
+
for (int i = 0 ; i < NSIG ; i++) { // NSIG is a macro for all signals + 1
|
|
410
|
+
sigaction(i, &sig_action, NULL);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// reenable signals
|
|
415
|
+
pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
|
|
416
|
+
|
|
417
|
+
switch (pid) {
|
|
418
|
+
case -1:
|
|
419
|
+
throw Napi::Error::New(napiEnv, "forkpty(3) failed.");
|
|
420
|
+
case 0:
|
|
421
|
+
if (strlen(cwd_.c_str())) {
|
|
422
|
+
if (chdir(cwd_.c_str()) == -1) {
|
|
423
|
+
perror("chdir(2) failed.");
|
|
424
|
+
_exit(1);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
if (uid != -1 && gid != -1) {
|
|
429
|
+
if (setgid(gid) == -1) {
|
|
430
|
+
perror("setgid(2) failed.");
|
|
431
|
+
_exit(1);
|
|
432
|
+
}
|
|
433
|
+
if (setuid(uid) == -1) {
|
|
434
|
+
perror("setuid(2) failed.");
|
|
435
|
+
_exit(1);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
{
|
|
440
|
+
char **old = environ;
|
|
441
|
+
environ = env;
|
|
442
|
+
execvp(argv[0], argv);
|
|
443
|
+
environ = old;
|
|
444
|
+
perror("execvp(3) failed.");
|
|
445
|
+
_exit(1);
|
|
446
|
+
}
|
|
447
|
+
default:
|
|
448
|
+
if (pty_nonblock(master) == -1) {
|
|
449
|
+
throw Napi::Error::New(napiEnv, "Could not set master fd to nonblocking.");
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
#endif
|
|
453
|
+
|
|
454
|
+
Napi::Object obj = Napi::Object::New(napiEnv);
|
|
455
|
+
obj.Set("fd", Napi::Number::New(napiEnv, master));
|
|
456
|
+
obj.Set("pid", Napi::Number::New(napiEnv, pid));
|
|
457
|
+
obj.Set("pty", Napi::String::New(napiEnv, ptsname(master)));
|
|
458
|
+
|
|
459
|
+
// Set up process exit callback.
|
|
460
|
+
Napi::Function cb = info[10].As<Napi::Function>();
|
|
461
|
+
SetupExitCallback(napiEnv, cb, pid);
|
|
462
|
+
return obj;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
Napi::Value PtyOpen(const Napi::CallbackInfo& info) {
|
|
466
|
+
Napi::Env env(info.Env());
|
|
467
|
+
Napi::HandleScope scope(env);
|
|
468
|
+
|
|
469
|
+
if (info.Length() != 2 ||
|
|
470
|
+
!info[0].IsNumber() ||
|
|
471
|
+
!info[1].IsNumber()) {
|
|
472
|
+
throw Napi::Error::New(env, "Usage: pty.open(cols, rows)");
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// size
|
|
476
|
+
struct winsize winp;
|
|
477
|
+
winp.ws_col = info[0].As<Napi::Number>().Int32Value();
|
|
478
|
+
winp.ws_row = info[1].As<Napi::Number>().Int32Value();
|
|
479
|
+
winp.ws_xpixel = 0;
|
|
480
|
+
winp.ws_ypixel = 0;
|
|
481
|
+
|
|
482
|
+
// pty
|
|
483
|
+
int master, slave;
|
|
484
|
+
int ret = openpty(&master, &slave, nullptr, NULL, static_cast<winsize*>(&winp));
|
|
485
|
+
|
|
486
|
+
if (ret == -1) {
|
|
487
|
+
throw Napi::Error::New(env, "openpty(3) failed.");
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
if (pty_nonblock(master) == -1) {
|
|
491
|
+
throw Napi::Error::New(env, "Could not set master fd to nonblocking.");
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
if (pty_nonblock(slave) == -1) {
|
|
495
|
+
throw Napi::Error::New(env, "Could not set slave fd to nonblocking.");
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
Napi::Object obj = Napi::Object::New(env);
|
|
499
|
+
obj.Set("master", Napi::Number::New(env, master));
|
|
500
|
+
obj.Set("slave", Napi::Number::New(env, slave));
|
|
501
|
+
obj.Set("pty", Napi::String::New(env, ptsname(master)));
|
|
502
|
+
|
|
503
|
+
return obj;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
Napi::Value PtyResize(const Napi::CallbackInfo& info) {
|
|
507
|
+
Napi::Env env(info.Env());
|
|
508
|
+
Napi::HandleScope scope(env);
|
|
509
|
+
|
|
510
|
+
if (info.Length() != 3 ||
|
|
511
|
+
!info[0].IsNumber() ||
|
|
512
|
+
!info[1].IsNumber() ||
|
|
513
|
+
!info[2].IsNumber()) {
|
|
514
|
+
throw Napi::Error::New(env, "Usage: pty.resize(fd, cols, rows)");
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
int fd = info[0].As<Napi::Number>().Int32Value();
|
|
518
|
+
|
|
519
|
+
struct winsize winp;
|
|
520
|
+
winp.ws_col = info[1].As<Napi::Number>().Int32Value();
|
|
521
|
+
winp.ws_row = info[2].As<Napi::Number>().Int32Value();
|
|
522
|
+
winp.ws_xpixel = 0;
|
|
523
|
+
winp.ws_ypixel = 0;
|
|
524
|
+
|
|
525
|
+
if (ioctl(fd, TIOCSWINSZ, &winp) == -1) {
|
|
526
|
+
switch (errno) {
|
|
527
|
+
case EBADF:
|
|
528
|
+
throw Napi::Error::New(env, "ioctl(2) failed, EBADF");
|
|
529
|
+
case EFAULT:
|
|
530
|
+
throw Napi::Error::New(env, "ioctl(2) failed, EFAULT");
|
|
531
|
+
case EINVAL:
|
|
532
|
+
throw Napi::Error::New(env, "ioctl(2) failed, EINVAL");
|
|
533
|
+
case ENOTTY:
|
|
534
|
+
throw Napi::Error::New(env, "ioctl(2) failed, ENOTTY");
|
|
535
|
+
}
|
|
536
|
+
throw Napi::Error::New(env, "ioctl(2) failed");
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
return env.Undefined();
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Foreground Process Name
|
|
544
|
+
*/
|
|
545
|
+
Napi::Value PtyGetProc(const Napi::CallbackInfo& info) {
|
|
546
|
+
Napi::Env env(info.Env());
|
|
547
|
+
Napi::HandleScope scope(env);
|
|
548
|
+
|
|
549
|
+
#if defined(__APPLE__)
|
|
550
|
+
if (info.Length() != 1 ||
|
|
551
|
+
!info[0].IsNumber()) {
|
|
552
|
+
throw Napi::Error::New(env, "Usage: pty.process(pid)");
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
int fd = info[0].As<Napi::Number>().Int32Value();
|
|
556
|
+
char *name = pty_getproc(fd);
|
|
557
|
+
#else
|
|
558
|
+
if (info.Length() != 2 ||
|
|
559
|
+
!info[0].IsNumber() ||
|
|
560
|
+
!info[1].IsString()) {
|
|
561
|
+
throw Napi::Error::New(env, "Usage: pty.process(fd, tty)");
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
int fd = info[0].As<Napi::Number>().Int32Value();
|
|
565
|
+
|
|
566
|
+
std::string tty_ = info[1].As<Napi::String>();
|
|
567
|
+
char *tty = strdup(tty_.c_str());
|
|
568
|
+
char *name = pty_getproc(fd, tty);
|
|
569
|
+
free(tty);
|
|
570
|
+
#endif
|
|
571
|
+
|
|
572
|
+
if (name == NULL) {
|
|
573
|
+
return env.Undefined();
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
Napi::String name_ = Napi::String::New(env, name);
|
|
577
|
+
free(name);
|
|
578
|
+
return name_;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* Nonblocking FD
|
|
583
|
+
*/
|
|
584
|
+
|
|
585
|
+
static int
|
|
586
|
+
pty_nonblock(int fd) {
|
|
587
|
+
int flags = fcntl(fd, F_GETFL, 0);
|
|
588
|
+
if (flags == -1) return -1;
|
|
589
|
+
return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* pty_getproc
|
|
594
|
+
* Taken from tmux.
|
|
595
|
+
*/
|
|
596
|
+
|
|
597
|
+
// Taken from: tmux (http://tmux.sourceforge.net/)
|
|
598
|
+
// Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
|
599
|
+
// Copyright (c) 2009 Joshua Elsasser <josh@elsasser.org>
|
|
600
|
+
// Copyright (c) 2009 Todd Carson <toc@daybefore.net>
|
|
601
|
+
//
|
|
602
|
+
// Permission to use, copy, modify, and distribute this software for any
|
|
603
|
+
// purpose with or without fee is hereby granted, provided that the above
|
|
604
|
+
// copyright notice and this permission notice appear in all copies.
|
|
605
|
+
//
|
|
606
|
+
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
607
|
+
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
608
|
+
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
609
|
+
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
610
|
+
// WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
|
611
|
+
// IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
|
612
|
+
// OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
613
|
+
|
|
614
|
+
#if defined(__linux__)
|
|
615
|
+
|
|
616
|
+
static char *
|
|
617
|
+
pty_getproc(int fd, char *tty) {
|
|
618
|
+
FILE *f;
|
|
619
|
+
char *path, *buf;
|
|
620
|
+
size_t len;
|
|
621
|
+
int ch;
|
|
622
|
+
pid_t pgrp;
|
|
623
|
+
int r;
|
|
624
|
+
|
|
625
|
+
if ((pgrp = tcgetpgrp(fd)) == -1) {
|
|
626
|
+
return NULL;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
r = asprintf(&path, "/proc/%lld/cmdline", (long long)pgrp);
|
|
630
|
+
if (r == -1 || path == NULL) return NULL;
|
|
631
|
+
|
|
632
|
+
if ((f = fopen(path, "r")) == NULL) {
|
|
633
|
+
free(path);
|
|
634
|
+
return NULL;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
free(path);
|
|
638
|
+
|
|
639
|
+
len = 0;
|
|
640
|
+
buf = NULL;
|
|
641
|
+
while ((ch = fgetc(f)) != EOF) {
|
|
642
|
+
if (ch == '\0') break;
|
|
643
|
+
buf = (char *)realloc(buf, len + 2);
|
|
644
|
+
if (buf == NULL) return NULL;
|
|
645
|
+
buf[len++] = ch;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
if (buf != NULL) {
|
|
649
|
+
buf[len] = '\0';
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
fclose(f);
|
|
653
|
+
return buf;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
#elif defined(__APPLE__)
|
|
657
|
+
|
|
658
|
+
static char *
|
|
659
|
+
pty_getproc(int fd) {
|
|
660
|
+
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, 0 };
|
|
661
|
+
size_t size;
|
|
662
|
+
struct kinfo_proc kp;
|
|
663
|
+
|
|
664
|
+
if ((mib[3] = tcgetpgrp(fd)) == -1) {
|
|
665
|
+
return NULL;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
size = sizeof kp;
|
|
669
|
+
if (sysctl(mib, 4, &kp, &size, NULL, 0) == -1) {
|
|
670
|
+
return NULL;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
if (size != (sizeof kp) || *kp.kp_proc.p_comm == '\0') {
|
|
674
|
+
return NULL;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
return strdup(kp.kp_proc.p_comm);
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
#else
|
|
681
|
+
|
|
682
|
+
static char *
|
|
683
|
+
pty_getproc(int fd, char *tty) {
|
|
684
|
+
return NULL;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
#endif
|
|
688
|
+
|
|
689
|
+
#if defined(__APPLE__)
|
|
690
|
+
static void
|
|
691
|
+
pty_posix_spawn(char** argv, char** env,
|
|
692
|
+
const struct termios *termp,
|
|
693
|
+
const struct winsize *winp,
|
|
694
|
+
int* master,
|
|
695
|
+
pid_t* pid,
|
|
696
|
+
int* err) {
|
|
697
|
+
int low_fds[3];
|
|
698
|
+
size_t low_fd_count = 0;
|
|
699
|
+
|
|
700
|
+
for (; low_fd_count < 3; low_fd_count++) {
|
|
701
|
+
low_fds[low_fd_count] = posix_openpt(O_RDWR);
|
|
702
|
+
if (low_fds[low_fd_count] >= STDERR_FILENO) {
|
|
703
|
+
low_fd_count++;
|
|
704
|
+
break;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
int flags = POSIX_SPAWN_CLOEXEC_DEFAULT |
|
|
709
|
+
POSIX_SPAWN_SETSIGDEF |
|
|
710
|
+
POSIX_SPAWN_SETSIGMASK |
|
|
711
|
+
POSIX_SPAWN_SETSID;
|
|
712
|
+
*master = posix_openpt(O_RDWR);
|
|
713
|
+
if (*master == -1) {
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
int res = grantpt(*master) || unlockpt(*master);
|
|
718
|
+
if (res == -1) {
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
// Use TIOCPTYGNAME instead of ptsname() to avoid threading problems.
|
|
723
|
+
int slave = -1;
|
|
724
|
+
char slave_pty_name[128];
|
|
725
|
+
res = ioctl(*master, TIOCPTYGNAME, slave_pty_name);
|
|
726
|
+
if (res == -1) {
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
slave = open(slave_pty_name, O_RDWR | O_NOCTTY);
|
|
731
|
+
if (slave == -1) {
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
if (termp) {
|
|
736
|
+
res = tcsetattr(slave, TCSANOW, termp);
|
|
737
|
+
if (res == -1) {
|
|
738
|
+
return;
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
if (winp) {
|
|
743
|
+
res = ioctl(slave, TIOCSWINSZ, winp);
|
|
744
|
+
if (res == -1) {
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
posix_spawn_file_actions_t acts;
|
|
750
|
+
posix_spawn_file_actions_init(&acts);
|
|
751
|
+
posix_spawn_file_actions_adddup2(&acts, slave, STDIN_FILENO);
|
|
752
|
+
posix_spawn_file_actions_adddup2(&acts, slave, STDOUT_FILENO);
|
|
753
|
+
posix_spawn_file_actions_adddup2(&acts, slave, STDERR_FILENO);
|
|
754
|
+
posix_spawn_file_actions_addclose(&acts, slave);
|
|
755
|
+
posix_spawn_file_actions_addclose(&acts, *master);
|
|
756
|
+
|
|
757
|
+
posix_spawnattr_t attrs;
|
|
758
|
+
posix_spawnattr_init(&attrs);
|
|
759
|
+
*err = posix_spawnattr_setflags(&attrs, flags);
|
|
760
|
+
if (*err != 0) {
|
|
761
|
+
goto done;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
sigset_t signal_set;
|
|
765
|
+
/* Reset all signal the child to their default behavior */
|
|
766
|
+
sigfillset(&signal_set);
|
|
767
|
+
*err = posix_spawnattr_setsigdefault(&attrs, &signal_set);
|
|
768
|
+
if (*err != 0) {
|
|
769
|
+
goto done;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
/* Reset the signal mask for all signals */
|
|
773
|
+
sigemptyset(&signal_set);
|
|
774
|
+
*err = posix_spawnattr_setsigmask(&attrs, &signal_set);
|
|
775
|
+
if (*err != 0) {
|
|
776
|
+
goto done;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
do
|
|
780
|
+
*err = posix_spawn(pid, argv[0], &acts, &attrs, argv, env);
|
|
781
|
+
while (*err == EINTR);
|
|
782
|
+
done:
|
|
783
|
+
posix_spawn_file_actions_destroy(&acts);
|
|
784
|
+
posix_spawnattr_destroy(&attrs);
|
|
785
|
+
if (slave != -1) {
|
|
786
|
+
close(slave);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
while (low_fd_count > 0) {
|
|
790
|
+
low_fd_count--;
|
|
791
|
+
close(low_fds[low_fd_count]);
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
#endif
|
|
795
|
+
|
|
796
|
+
/**
|
|
797
|
+
* Init
|
|
798
|
+
*/
|
|
799
|
+
|
|
800
|
+
Napi::Object init(Napi::Env env, Napi::Object exports) {
|
|
801
|
+
exports.Set("fork", Napi::Function::New(env, PtyFork));
|
|
802
|
+
exports.Set("open", Napi::Function::New(env, PtyOpen));
|
|
803
|
+
exports.Set("resize", Napi::Function::New(env, PtyResize));
|
|
804
|
+
exports.Set("process", Napi::Function::New(env, PtyGetProc));
|
|
805
|
+
return exports;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
NODE_API_MODULE(NODE_GYP_MODULE_NAME, init)
|