1 // Copyright Joyent, Inc. and other Node contributors. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a 4 // copy of this software and associated documentation files (the 5 // "Software"), to deal in the Software without restriction, including 6 // without limitation the rights to use, copy, modify, merge, publish, 7 // distribute, sublicense, and/or sell copies of the Software, and to permit 8 // persons to whom the Software is furnished to do so, subject to the 9 // following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included 12 // in all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22 #ifndef SRC_SPAWN_SYNC_H_ 23 #define SRC_SPAWN_SYNC_H_ 24 25 #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 26 27 #include "node_buffer.h" 28 #include "uv.h" 29 #include "v8.h" 30 31 namespace node { 32 33 34 35 class SyncProcessOutputBuffer; 36 class SyncProcessStdioPipe; 37 class SyncProcessRunner; 38 39 40 class SyncProcessOutputBuffer { 41 static const unsigned int kBufferSize = 65536; 42 43 public: 44 inline SyncProcessOutputBuffer() = default; 45 46 inline void OnAlloc(size_t suggested_size, uv_buf_t* buf) const; 47 inline void OnRead(const uv_buf_t* buf, size_t nread); 48 49 inline size_t Copy(char* dest) const; 50 51 inline unsigned int available() const; 52 inline unsigned int used() const; 53 54 inline SyncProcessOutputBuffer* next() const; 55 inline void set_next(SyncProcessOutputBuffer* next); 56 57 private: 58 // Use unsigned int because that's what `uv_buf_init` takes. 59 mutable char data_[kBufferSize]; 60 unsigned int used_ = 0; 61 62 SyncProcessOutputBuffer* next_ = nullptr; 63 }; 64 65 66 class SyncProcessStdioPipe { 67 enum Lifecycle { 68 kUninitialized = 0, 69 kInitialized, 70 kStarted, 71 kClosing, 72 kClosed 73 }; 74 75 public: 76 SyncProcessStdioPipe(SyncProcessRunner* process_handler, 77 bool readable, 78 bool writable, 79 uv_buf_t input_buffer); 80 ~SyncProcessStdioPipe(); 81 82 int Initialize(uv_loop_t* loop); 83 int Start(); 84 void Close(); 85 86 v8::Local<v8::Object> GetOutputAsBuffer(Environment* env) const; 87 88 inline bool readable() const; 89 inline bool writable() const; 90 inline uv_stdio_flags uv_flags() const; 91 92 inline uv_pipe_t* uv_pipe() const; 93 inline uv_stream_t* uv_stream() const; 94 inline uv_handle_t* uv_handle() const; 95 96 private: 97 inline size_t OutputLength() const; 98 inline void CopyOutput(char* dest) const; 99 100 inline void OnAlloc(size_t suggested_size, uv_buf_t* buf); 101 inline void OnRead(const uv_buf_t* buf, ssize_t nread); 102 inline void OnWriteDone(int result); 103 inline void OnShutdownDone(int result); 104 inline void OnClose(); 105 106 inline void SetError(int error); 107 108 static void AllocCallback(uv_handle_t* handle, 109 size_t suggested_size, 110 uv_buf_t* buf); 111 static void ReadCallback(uv_stream_t* stream, 112 ssize_t nread, 113 const uv_buf_t* buf); 114 static void WriteCallback(uv_write_t* req, int result); 115 static void ShutdownCallback(uv_shutdown_t* req, int result); 116 static void CloseCallback(uv_handle_t* handle); 117 118 SyncProcessRunner* process_handler_; 119 120 bool readable_; 121 bool writable_; 122 uv_buf_t input_buffer_; 123 124 SyncProcessOutputBuffer* first_output_buffer_; 125 SyncProcessOutputBuffer* last_output_buffer_; 126 127 mutable uv_pipe_t uv_pipe_; 128 uv_write_t write_req_; 129 uv_shutdown_t shutdown_req_; 130 131 Lifecycle lifecycle_; 132 }; 133 134 135 class SyncProcessRunner { 136 enum Lifecycle { 137 kUninitialized = 0, 138 kInitialized, 139 kHandlesClosed 140 }; 141 142 public: 143 static void Initialize(v8::Local<v8::Object> target, 144 v8::Local<v8::Value> unused, 145 v8::Local<v8::Context> context, 146 void* priv); 147 static void Spawn(const v8::FunctionCallbackInfo<v8::Value>& args); 148 149 private: 150 friend class SyncProcessStdioPipe; 151 152 explicit SyncProcessRunner(Environment* env_); 153 ~SyncProcessRunner(); 154 155 inline Environment* env() const; 156 157 v8::MaybeLocal<v8::Object> Run(v8::Local<v8::Value> options); 158 v8::Maybe<bool> TryInitializeAndRunLoop(v8::Local<v8::Value> options); 159 void CloseHandlesAndDeleteLoop(); 160 161 void CloseStdioPipes(); 162 void CloseKillTimer(); 163 164 void Kill(); 165 void IncrementBufferSizeAndCheckOverflow(ssize_t length); 166 167 void OnExit(int64_t exit_status, int term_signal); 168 void OnKillTimerTimeout(); 169 170 int GetError(); 171 void SetError(int error); 172 void SetPipeError(int pipe_error); 173 174 v8::Local<v8::Object> BuildResultObject(); 175 v8::Local<v8::Array> BuildOutputArray(); 176 177 v8::Maybe<int> ParseOptions(v8::Local<v8::Value> js_value); 178 int ParseStdioOptions(v8::Local<v8::Value> js_value); 179 int ParseStdioOption(int child_fd, v8::Local<v8::Object> js_stdio_option); 180 181 inline int AddStdioIgnore(uint32_t child_fd); 182 inline int AddStdioPipe(uint32_t child_fd, 183 bool readable, 184 bool writable, 185 uv_buf_t input_buffer); 186 inline int AddStdioInheritFD(uint32_t child_fd, int inherit_fd); 187 188 static bool IsSet(v8::Local<v8::Value> value); 189 v8::Maybe<int> CopyJsString(v8::Local<v8::Value> js_value, 190 const char** target); 191 v8::Maybe<int> CopyJsStringArray(v8::Local<v8::Value> js_value, 192 char** target); 193 194 static void ExitCallback(uv_process_t* handle, 195 int64_t exit_status, 196 int term_signal); 197 static void KillTimerCallback(uv_timer_t* handle); 198 static void KillTimerCloseCallback(uv_handle_t* handle); 199 200 double max_buffer_; 201 uint64_t timeout_; 202 int kill_signal_; 203 204 uv_loop_t* uv_loop_; 205 206 uint32_t stdio_count_; 207 uv_stdio_container_t* uv_stdio_containers_; 208 std::vector<std::unique_ptr<SyncProcessStdioPipe>> stdio_pipes_; 209 bool stdio_pipes_initialized_; 210 211 uv_process_options_t uv_process_options_; 212 const char* file_buffer_; 213 char* args_buffer_; 214 char* env_buffer_; 215 const char* cwd_buffer_; 216 217 uv_process_t uv_process_; 218 bool killed_; 219 220 size_t buffered_output_size_; 221 int64_t exit_status_; 222 int term_signal_; 223 224 uv_timer_t uv_timer_; 225 bool kill_timer_initialized_; 226 227 // Errors that happen in one of the pipe handlers are stored in the 228 // `pipe_error` field. They are treated as "low-priority", only to be 229 // reported if no more serious errors happened. 230 int error_; 231 int pipe_error_; 232 233 Lifecycle lifecycle_; 234 235 Environment* env_; 236 }; 237 238 } // namespace node 239 240 #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 241 242 #endif // SRC_SPAWN_SYNC_H_ 243