• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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