1'use strict'; 2 3const { ObjectDefineProperty } = primordials; 4const rawMethods = internalBinding('process_methods'); 5const { 6 namespace: { 7 addSerializeCallback, 8 isBuildingSnapshot, 9 }, 10} = require('internal/v8/startup_snapshot'); 11// TODO(joyeecheung): deprecate and remove these underscore methods 12process._debugProcess = rawMethods._debugProcess; 13process._debugEnd = rawMethods._debugEnd; 14 15// See the discussion in https://github.com/nodejs/node/issues/19009 and 16// https://github.com/nodejs/node/pull/34010 for why these are no-ops. 17// Five word summary: they were broken beyond repair. 18process._startProfilerIdleNotifier = () => {}; 19process._stopProfilerIdleNotifier = () => {}; 20 21function defineStream(name, getter) { 22 ObjectDefineProperty(process, name, { 23 __proto__: null, 24 configurable: true, 25 enumerable: true, 26 get: getter, 27 }); 28} 29 30defineStream('stdout', getStdout); 31defineStream('stdin', getStdin); 32defineStream('stderr', getStderr); 33 34// Worker threads don't receive signals. 35const { 36 startListeningIfSignal, 37 stopListeningIfSignal, 38} = require('internal/process/signal'); 39process.on('newListener', startListeningIfSignal); 40process.on('removeListener', stopListeningIfSignal); 41 42// ---- keep the attachment of the wrappers above so that it's easier to ---- 43// ---- compare the setups side-by-side ----- 44 45const { guessHandleType } = internalBinding('util'); 46 47function createWritableStdioStream(fd) { 48 let stream; 49 // Note stream._type is used for test-module-load-list.js 50 switch (guessHandleType(fd)) { 51 case 'TTY': { 52 const tty = require('tty'); 53 stream = new tty.WriteStream(fd); 54 stream._type = 'tty'; 55 break; 56 } 57 58 case 'FILE': { 59 const SyncWriteStream = require('internal/fs/sync_write_stream'); 60 stream = new SyncWriteStream(fd, { autoClose: false }); 61 stream._type = 'fs'; 62 break; 63 } 64 65 case 'PIPE': 66 case 'TCP': { 67 const net = require('net'); 68 69 // If fd is already being used for the IPC channel, libuv will return 70 // an error when trying to use it again. In that case, create the socket 71 // using the existing handle instead of the fd. 72 if (process.channel && process.channel.fd === fd) { 73 const { kChannelHandle } = require('internal/child_process'); 74 stream = new net.Socket({ 75 handle: process[kChannelHandle], 76 readable: false, 77 writable: true, 78 }); 79 } else { 80 stream = new net.Socket({ 81 fd, 82 readable: false, 83 writable: true, 84 }); 85 } 86 87 stream._type = 'pipe'; 88 break; 89 } 90 91 default: { 92 // Provide a dummy black-hole output for e.g. non-console 93 // Windows applications. 94 const { Writable } = require('stream'); 95 stream = new Writable({ 96 write(buf, enc, cb) { 97 cb(); 98 }, 99 }); 100 } 101 } 102 103 // For supporting legacy API we put the FD here. 104 stream.fd = fd; 105 106 stream._isStdio = true; 107 108 return stream; 109} 110 111function dummyDestroy(err, cb) { 112 cb(err); 113 this._undestroy(); 114 115 // We need to emit 'close' anyway so that the closing 116 // of the stream is observable. We just make sure we 117 // are not going to do it twice. 118 // The 'close' event is needed so that finished and 119 // pipeline work correctly. 120 if (!this._writableState.emitClose) { 121 process.nextTick(() => { 122 this.emit('close'); 123 }); 124 } 125} 126 127let stdin; 128let stdout; 129let stderr; 130 131let stdoutDestroy; 132let stderrDestroy; 133 134function refreshStdoutOnSigWinch() { 135 stdout._refreshSize(); 136} 137 138function refreshStderrOnSigWinch() { 139 stderr._refreshSize(); 140} 141 142function addCleanup(fn) { 143 if (isBuildingSnapshot()) { 144 addSerializeCallback(fn); 145 } 146} 147 148function getStdout() { 149 if (stdout) return stdout; 150 stdout = createWritableStdioStream(1); 151 stdout.destroySoon = stdout.destroy; 152 // Override _destroy so that the fd is never actually closed. 153 stdoutDestroy = stdout._destroy; 154 stdout._destroy = dummyDestroy; 155 if (stdout.isTTY) { 156 process.on('SIGWINCH', refreshStdoutOnSigWinch); 157 } 158 159 addCleanup(function cleanupStdout() { 160 stdout._destroy = stdoutDestroy; 161 stdout.destroy(); 162 process.removeListener('SIGWINCH', refreshStdoutOnSigWinch); 163 stdout = undefined; 164 }); 165 // No need to add deserialize callback because stdout = undefined above 166 // causes the stream to be lazily initialized again later. 167 return stdout; 168} 169 170function getStderr() { 171 if (stderr) return stderr; 172 stderr = createWritableStdioStream(2); 173 stderr.destroySoon = stderr.destroy; 174 stderrDestroy = stderr._destroy; 175 // Override _destroy so that the fd is never actually closed. 176 stderr._destroy = dummyDestroy; 177 if (stderr.isTTY) { 178 process.on('SIGWINCH', refreshStderrOnSigWinch); 179 } 180 addCleanup(function cleanupStderr() { 181 stderr._destroy = stderrDestroy; 182 stderr.destroy(); 183 process.removeListener('SIGWINCH', refreshStderrOnSigWinch); 184 stderr = undefined; 185 }); 186 // No need to add deserialize callback because stderr = undefined above 187 // causes the stream to be lazily initialized again later. 188 return stderr; 189} 190 191function getStdin() { 192 if (stdin) return stdin; 193 const fd = 0; 194 195 switch (guessHandleType(fd)) { 196 case 'TTY': { 197 const tty = require('tty'); 198 stdin = new tty.ReadStream(fd); 199 break; 200 } 201 202 case 'FILE': { 203 const fs = require('fs'); 204 stdin = new fs.ReadStream(null, { fd: fd, autoClose: false }); 205 break; 206 } 207 208 case 'PIPE': 209 case 'TCP': { 210 const net = require('net'); 211 212 // It could be that process has been started with an IPC channel 213 // sitting on fd=0, in such case the pipe for this fd is already 214 // present and creating a new one will lead to the assertion failure 215 // in libuv. 216 if (process.channel && process.channel.fd === fd) { 217 stdin = new net.Socket({ 218 handle: process.channel, 219 readable: true, 220 writable: false, 221 manualStart: true, 222 }); 223 } else { 224 stdin = new net.Socket({ 225 fd: fd, 226 readable: true, 227 writable: false, 228 manualStart: true, 229 }); 230 } 231 // Make sure the stdin can't be `.end()`-ed 232 stdin._writableState.ended = true; 233 break; 234 } 235 236 default: { 237 // Provide a dummy contentless input for e.g. non-console 238 // Windows applications. 239 const { Readable } = require('stream'); 240 stdin = new Readable({ read() {} }); 241 stdin.push(null); 242 } 243 } 244 245 // For supporting legacy API we put the FD here. 246 stdin.fd = fd; 247 248 // `stdin` starts out life in a paused state, but node doesn't 249 // know yet. Explicitly to readStop() it to put it in the 250 // not-reading state. 251 if (stdin._handle && stdin._handle.readStop) { 252 stdin._handle.reading = false; 253 stdin._readableState.reading = false; 254 stdin._handle.readStop(); 255 } 256 257 // If the user calls stdin.pause(), then we need to stop reading 258 // once the stream implementation does so (one nextTick later), 259 // so that the process can close down. 260 stdin.on('pause', () => { 261 process.nextTick(onpause); 262 }); 263 264 function onpause() { 265 if (!stdin._handle) 266 return; 267 if (stdin._handle.reading && !stdin.readableFlowing) { 268 stdin._readableState.reading = false; 269 stdin._handle.reading = false; 270 stdin._handle.readStop(); 271 } 272 } 273 274 addCleanup(function cleanupStdin() { 275 stdin.destroy(); 276 stdin = undefined; 277 }); 278 // No need to add deserialize callback because stdin = undefined above 279 // causes the stream to be lazily initialized again later. 280 return stdin; 281} 282 283// Used by internal tests. 284rawMethods.resetStdioForTesting = function() { 285 stdin = undefined; 286 stdout = undefined; 287 stderr = undefined; 288}; 289 290// Needed by the module loader and generally needed everywhere. 291require('fs'); 292require('util'); 293require('url'); 294 295require('internal/modules/cjs/loader'); 296require('internal/modules/esm/utils'); 297require('internal/vm/module'); 298// Needed to refresh the time origin. 299require('internal/perf/utils'); 300// Needed to register the async hooks. 301if (internalBinding('config').hasInspector) { 302 require('internal/inspector_async_hook'); 303} 304// Needed to set the wasm web API callbacks. 305internalBinding('wasm_web_api'); 306// Needed to detect whether it's on main thread. 307internalBinding('worker'); 308// Needed by most execution modes. 309require('internal/modules/run_main'); 310// Needed to refresh DNS configurations. 311require('internal/dns/utils'); 312// Needed by almost all execution modes. It's fine to 313// load them into the snapshot as long as we don't run 314// any of the initialization. 315require('internal/process/pre_execution'); 316