1'use strict'; 2 3const { ObjectDefineProperty } = primordials; 4const rawMethods = internalBinding('process_methods'); 5 6// TODO(joyeecheung): deprecate and remove these underscore methods 7process._debugProcess = rawMethods._debugProcess; 8process._debugEnd = rawMethods._debugEnd; 9 10// See the discussion in https://github.com/nodejs/node/issues/19009 and 11// https://github.com/nodejs/node/pull/34010 for why these are no-ops. 12// Five word summary: they were broken beyond repair. 13process._startProfilerIdleNotifier = () => {}; 14process._stopProfilerIdleNotifier = () => {}; 15 16function defineStream(name, getter) { 17 ObjectDefineProperty(process, name, { 18 configurable: true, 19 enumerable: true, 20 get: getter 21 }); 22} 23 24defineStream('stdout', getStdout); 25defineStream('stdin', getStdin); 26defineStream('stderr', getStderr); 27 28// Worker threads don't receive signals. 29const { 30 startListeningIfSignal, 31 stopListeningIfSignal 32} = require('internal/process/signal'); 33process.on('newListener', startListeningIfSignal); 34process.on('removeListener', stopListeningIfSignal); 35 36// ---- keep the attachment of the wrappers above so that it's easier to ---- 37// ---- compare the setups side-by-side ----- 38 39const { guessHandleType } = internalBinding('util'); 40 41function createWritableStdioStream(fd) { 42 let stream; 43 // Note stream._type is used for test-module-load-list.js 44 switch (guessHandleType(fd)) { 45 case 'TTY': 46 const tty = require('tty'); 47 stream = new tty.WriteStream(fd); 48 stream._type = 'tty'; 49 break; 50 51 case 'FILE': 52 const SyncWriteStream = require('internal/fs/sync_write_stream'); 53 stream = new SyncWriteStream(fd, { autoClose: false }); 54 stream._type = 'fs'; 55 break; 56 57 case 'PIPE': 58 case 'TCP': 59 const net = require('net'); 60 61 // If fd is already being used for the IPC channel, libuv will return 62 // an error when trying to use it again. In that case, create the socket 63 // using the existing handle instead of the fd. 64 if (process.channel && process.channel.fd === fd) { 65 const { kChannelHandle } = require('internal/child_process'); 66 stream = new net.Socket({ 67 handle: process[kChannelHandle], 68 readable: false, 69 writable: true 70 }); 71 } else { 72 stream = new net.Socket({ 73 fd, 74 readable: false, 75 writable: true 76 }); 77 } 78 79 stream._type = 'pipe'; 80 break; 81 82 default: 83 // Provide a dummy black-hole output for e.g. non-console 84 // Windows applications. 85 const { Writable } = require('stream'); 86 stream = new Writable({ 87 write(buf, enc, cb) { 88 cb(); 89 } 90 }); 91 } 92 93 // For supporting legacy API we put the FD here. 94 stream.fd = fd; 95 96 stream._isStdio = true; 97 98 return stream; 99} 100 101function dummyDestroy(err, cb) { 102 cb(err); 103 104 // We need to emit 'close' anyway so that the closing 105 // of the stream is observable. We just make sure we 106 // are not going to do it twice. 107 // The 'close' event is needed so that finished and 108 // pipeline work correctly. 109 if (!this._writableState.emitClose) { 110 process.nextTick(() => { 111 this.emit('close'); 112 }); 113 } 114} 115 116let stdin; 117let stdout; 118let stderr; 119 120function getStdout() { 121 if (stdout) return stdout; 122 stdout = createWritableStdioStream(1); 123 stdout.destroySoon = stdout.destroy; 124 // Override _destroy so that the fd is never actually closed. 125 stdout._destroy = dummyDestroy; 126 if (stdout.isTTY) { 127 process.on('SIGWINCH', () => stdout._refreshSize()); 128 } 129 return stdout; 130} 131 132function getStderr() { 133 if (stderr) return stderr; 134 stderr = createWritableStdioStream(2); 135 stderr.destroySoon = stderr.destroy; 136 // Override _destroy so that the fd is never actually closed. 137 stderr._destroy = dummyDestroy; 138 if (stderr.isTTY) { 139 process.on('SIGWINCH', () => stderr._refreshSize()); 140 } 141 return stderr; 142} 143 144function getStdin() { 145 if (stdin) return stdin; 146 const fd = 0; 147 148 switch (guessHandleType(fd)) { 149 case 'TTY': 150 const tty = require('tty'); 151 stdin = new tty.ReadStream(fd, { 152 highWaterMark: 0, 153 readable: true, 154 writable: false 155 }); 156 break; 157 158 case 'FILE': 159 const fs = require('fs'); 160 stdin = new fs.ReadStream(null, { fd: fd, autoClose: false }); 161 break; 162 163 case 'PIPE': 164 case 'TCP': 165 const net = require('net'); 166 167 // It could be that process has been started with an IPC channel 168 // sitting on fd=0, in such case the pipe for this fd is already 169 // present and creating a new one will lead to the assertion failure 170 // in libuv. 171 if (process.channel && process.channel.fd === fd) { 172 stdin = new net.Socket({ 173 handle: process.channel, 174 readable: true, 175 writable: false, 176 manualStart: true 177 }); 178 } else { 179 stdin = new net.Socket({ 180 fd: fd, 181 readable: true, 182 writable: false, 183 manualStart: true 184 }); 185 } 186 // Make sure the stdin can't be `.end()`-ed 187 stdin._writableState.ended = true; 188 break; 189 190 default: 191 // Provide a dummy contentless input for e.g. non-console 192 // Windows applications. 193 const { Readable } = require('stream'); 194 stdin = new Readable({ read() {} }); 195 stdin.push(null); 196 } 197 198 // For supporting legacy API we put the FD here. 199 stdin.fd = fd; 200 201 // `stdin` starts out life in a paused state, but node doesn't 202 // know yet. Explicitly to readStop() it to put it in the 203 // not-reading state. 204 if (stdin._handle && stdin._handle.readStop) { 205 stdin._handle.reading = false; 206 stdin._readableState.reading = false; 207 stdin._handle.readStop(); 208 } 209 210 // If the user calls stdin.pause(), then we need to stop reading 211 // once the stream implementation does so (one nextTick later), 212 // so that the process can close down. 213 stdin.on('pause', () => { 214 process.nextTick(onpause); 215 }); 216 217 function onpause() { 218 if (!stdin._handle) 219 return; 220 if (stdin._handle.reading && !stdin.readableFlowing) { 221 stdin._readableState.reading = false; 222 stdin._handle.reading = false; 223 stdin._handle.readStop(); 224 } 225 } 226 227 return stdin; 228} 229 230// Used by internal tests. 231rawMethods.resetStdioForTesting = function() { 232 stdin = undefined; 233 stdout = undefined; 234 stderr = undefined; 235}; 236