'use strict'; // This file contains process bootstrappers that can only be // run in the main thread const { errnoException, codes: { ERR_INVALID_ARG_TYPE, ERR_UNKNOWN_CREDENTIAL } } = require('internal/errors'); const { validateMode, validateUint32 } = require('internal/validators'); const { setupProcessStdio, getMainThreadStdio } = require('internal/process/stdio'); const assert = require('assert').strict; function setupStdio() { setupProcessStdio(getMainThreadStdio()); } // Non-POSIX platforms like Windows don't have certain methods. // Workers also lack these methods since they change process-global state. function setupProcessMethods(_chdir, _umask, _initgroups, _setegid, _seteuid, _setgid, _setuid, _setgroups) { if (_setgid !== undefined) { setupPosixMethods(_initgroups, _setegid, _seteuid, _setgid, _setuid, _setgroups); } process.chdir = function chdir(directory) { if (typeof directory !== 'string') { throw new ERR_INVALID_ARG_TYPE('directory', 'string', directory); } return _chdir(directory); }; process.umask = function umask(mask) { if (mask === undefined) { // Get the mask return _umask(mask); } mask = validateMode(mask, 'mask'); return _umask(mask); }; } function setupPosixMethods(_initgroups, _setegid, _seteuid, _setgid, _setuid, _setgroups) { process.initgroups = function initgroups(user, extraGroup) { validateId(user, 'user'); validateId(extraGroup, 'extraGroup'); // Result is 0 on success, 1 if user is unknown, 2 if group is unknown. const result = _initgroups(user, extraGroup); if (result === 1) { throw new ERR_UNKNOWN_CREDENTIAL('User', user); } else if (result === 2) { throw new ERR_UNKNOWN_CREDENTIAL('Group', extraGroup); } }; process.setegid = function setegid(id) { return execId(id, 'Group', _setegid); }; process.seteuid = function seteuid(id) { return execId(id, 'User', _seteuid); }; process.setgid = function setgid(id) { return execId(id, 'Group', _setgid); }; process.setuid = function setuid(id) { return execId(id, 'User', _setuid); }; process.setgroups = function setgroups(groups) { if (!Array.isArray(groups)) { throw new ERR_INVALID_ARG_TYPE('groups', 'Array', groups); } for (var i = 0; i < groups.length; i++) { validateId(groups[i], `groups[${i}]`); } // Result is 0 on success. A positive integer indicates that the // corresponding group was not found. const result = _setgroups(groups); if (result > 0) { throw new ERR_UNKNOWN_CREDENTIAL('Group', groups[result - 1]); } }; function execId(id, type, method) { validateId(id, 'id'); // Result is 0 on success, 1 if credential is unknown. const result = method(id); if (result === 1) { throw new ERR_UNKNOWN_CREDENTIAL(type, id); } } function validateId(id, name) { if (typeof id === 'number') { validateUint32(id, name); } else if (typeof id !== 'string') { throw new ERR_INVALID_ARG_TYPE(name, ['number', 'string'], id); } } } // Worker threads don't receive signals. function setupSignalHandlers(internalBinding) { const constants = internalBinding('constants').os.signals; const signalWraps = Object.create(null); let Signal; function isSignal(event) { return typeof event === 'string' && constants[event] !== undefined; } // Detect presence of a listener for the special signal types process.on('newListener', function(type) { if (isSignal(type) && signalWraps[type] === undefined) { if (Signal === undefined) Signal = internalBinding('signal_wrap').Signal; const wrap = new Signal(); wrap.unref(); wrap.onsignal = process.emit.bind(process, type, type); const signum = constants[type]; const err = wrap.start(signum); if (err) { wrap.close(); throw errnoException(err, 'uv_signal_start'); } signalWraps[type] = wrap; } }); process.on('removeListener', function(type) { if (signalWraps[type] !== undefined && this.listenerCount(type) === 0) { signalWraps[type].close(); delete signalWraps[type]; } }); } function setupChildProcessIpcChannel() { // If we were spawned with env NODE_CHANNEL_FD then load that up and // start parsing data from that stream. if (process.env.NODE_CHANNEL_FD) { const fd = parseInt(process.env.NODE_CHANNEL_FD, 10); assert(fd >= 0); // Make sure it's not accidentally inherited by child processes. delete process.env.NODE_CHANNEL_FD; require('child_process')._forkChild(fd); assert(process.send); } } module.exports = { setupStdio, setupProcessMethods, setupSignalHandlers, setupChildProcessIpcChannel };