• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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'use strict';
23
24const {
25  ArrayPrototypePush,
26  Float64Array,
27  NumberParseInt,
28  ObjectDefineProperties,
29  StringPrototypeEndsWith,
30  StringPrototypeSlice,
31  SymbolToPrimitive,
32} = primordials;
33
34const { safeGetenv } = internalBinding('credentials');
35const constants = internalBinding('constants').os;
36const isWindows = process.platform === 'win32';
37
38const {
39  codes: {
40    ERR_SYSTEM_ERROR,
41  },
42  hideStackFrames,
43} = require('internal/errors');
44const { validateInt32 } = require('internal/validators');
45
46const {
47  getAvailableParallelism,
48  getCPUs,
49  getFreeMem,
50  getHomeDirectory: _getHomeDirectory,
51  getHostname: _getHostname,
52  getInterfaceAddresses: _getInterfaceAddresses,
53  getLoadAvg,
54  getPriority: _getPriority,
55  getOSInformation: _getOSInformation,
56  getTotalMem,
57  getUserInfo,
58  getUptime: _getUptime,
59  isBigEndian,
60  setPriority: _setPriority,
61} = internalBinding('os');
62
63function getCheckedFunction(fn) {
64  return hideStackFrames(function checkError(...args) {
65    const ctx = {};
66    const ret = fn(...args, ctx);
67    if (ret === undefined) {
68      throw new ERR_SYSTEM_ERROR(ctx);
69    }
70    return ret;
71  });
72}
73
74const {
75  0: type,
76  1: version,
77  2: release,
78  3: machine,
79} = _getOSInformation();
80
81const getHomeDirectory = getCheckedFunction(_getHomeDirectory);
82const getHostname = getCheckedFunction(_getHostname);
83const getInterfaceAddresses = getCheckedFunction(_getInterfaceAddresses);
84const getUptime = getCheckedFunction(_getUptime);
85
86/**
87 * @returns {string}
88 */
89const getOSRelease = () => release;
90/**
91 * @returns {string}
92 */
93const getOSType = () => type;
94/**
95 * @returns {string}
96 */
97const getOSVersion = () => version;
98/**
99 * @returns {string}
100 */
101const getMachine = () => machine;
102
103getAvailableParallelism[SymbolToPrimitive] = () => getAvailableParallelism();
104getFreeMem[SymbolToPrimitive] = () => getFreeMem();
105getHostname[SymbolToPrimitive] = () => getHostname();
106getOSVersion[SymbolToPrimitive] = () => getOSVersion();
107getOSType[SymbolToPrimitive] = () => getOSType();
108getOSRelease[SymbolToPrimitive] = () => getOSRelease();
109getMachine[SymbolToPrimitive] = () => getMachine();
110getHomeDirectory[SymbolToPrimitive] = () => getHomeDirectory();
111getTotalMem[SymbolToPrimitive] = () => getTotalMem();
112getUptime[SymbolToPrimitive] = () => getUptime();
113
114const kEndianness = isBigEndian ? 'BE' : 'LE';
115
116const avgValues = new Float64Array(3);
117
118/**
119 * @returns {[number, number, number]}
120 */
121function loadavg() {
122  getLoadAvg(avgValues);
123  return [avgValues[0], avgValues[1], avgValues[2]];
124}
125
126/**
127 * Returns an array of objects containing information about each
128 * logical CPU core.
129 * @returns {Array<{
130 *  model: string,
131 *  speed: number,
132 *  times: {
133 *    user: number,
134 *    nice: number,
135 *    sys: number,
136 *    idle: number,
137 *    irq: number,
138 *  },
139 * }>}
140 */
141function cpus() {
142  // [] is a bugfix for a regression introduced in 51cea61
143  const data = getCPUs() || [];
144  const result = [];
145  let i = 0;
146  while (i < data.length) {
147    ArrayPrototypePush(result, {
148      model: data[i++],
149      speed: data[i++],
150      times: {
151        user: data[i++],
152        nice: data[i++],
153        sys: data[i++],
154        idle: data[i++],
155        irq: data[i++],
156      },
157    });
158  }
159  return result;
160}
161
162/**
163 * @returns {string}
164 */
165function arch() {
166  return process.arch;
167}
168arch[SymbolToPrimitive] = () => process.arch;
169
170/**
171 * @returns {string}
172 */
173function platform() {
174  return process.platform;
175}
176platform[SymbolToPrimitive] = () => process.platform;
177
178/**
179 * @returns {string}
180 */
181function tmpdir() {
182  let path;
183  if (isWindows) {
184    path = process.env.TEMP ||
185           process.env.TMP ||
186           (process.env.SystemRoot || process.env.windir) + '\\temp';
187    if (path.length > 1 && StringPrototypeEndsWith(path, '\\') &&
188        !StringPrototypeEndsWith(path, ':\\'))
189      path = StringPrototypeSlice(path, 0, -1);
190  } else {
191    path = safeGetenv('TMPDIR') ||
192           safeGetenv('TMP') ||
193           safeGetenv('TEMP') ||
194           '/tmp';
195    if (path.length > 1 && StringPrototypeEndsWith(path, '/'))
196      path = StringPrototypeSlice(path, 0, -1);
197  }
198
199  return path;
200}
201tmpdir[SymbolToPrimitive] = () => tmpdir();
202
203/**
204 * @returns {'BE' | 'LE'}
205 */
206function endianness() {
207  return kEndianness;
208}
209endianness[SymbolToPrimitive] = () => kEndianness;
210
211// Returns the number of ones in the binary representation of the decimal
212// number.
213function countBinaryOnes(n) {
214  // Count the number of bits set in parallel, which is faster than looping
215  n = n - ((n >>> 1) & 0x55555555);
216  n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);
217  return ((n + (n >>> 4) & 0xF0F0F0F) * 0x1010101) >>> 24;
218}
219
220function getCIDR(address, netmask, family) {
221  let ones = 0;
222  let split = '.';
223  let range = 10;
224  let groupLength = 8;
225  let hasZeros = false;
226  let lastPos = 0;
227
228  if (family === 'IPv6') {
229    split = ':';
230    range = 16;
231    groupLength = 16;
232  }
233
234  for (let i = 0; i < netmask.length; i++) {
235    if (netmask[i] !== split) {
236      if (i + 1 < netmask.length) {
237        continue;
238      }
239      i++;
240    }
241    const part = StringPrototypeSlice(netmask, lastPos, i);
242    lastPos = i + 1;
243    if (part !== '') {
244      if (hasZeros) {
245        if (part !== '0') {
246          return null;
247        }
248      } else {
249        const binary = NumberParseInt(part, range);
250        const binaryOnes = countBinaryOnes(binary);
251        ones += binaryOnes;
252        if (binaryOnes !== groupLength) {
253          if ((binary & 1) !== 0) {
254            return null;
255          }
256          hasZeros = true;
257        }
258      }
259    }
260  }
261
262  return `${address}/${ones}`;
263}
264
265/**
266 * @returns {Record<string, Array<{
267 *  address: string,
268 *  netmask: string,
269 *  family: 'IPv4' | 'IPv6',
270 *  mac: string,
271 *  internal: boolean,
272 *  scopeid: number,
273 *  cidr: string | null,
274 * }>>}
275 */
276function networkInterfaces() {
277  const data = getInterfaceAddresses();
278  const result = {};
279
280  if (data === undefined)
281    return result;
282  for (let i = 0; i < data.length; i += 7) {
283    const name = data[i];
284    const entry = {
285      address: data[i + 1],
286      netmask: data[i + 2],
287      family: data[i + 3],
288      mac: data[i + 4],
289      internal: data[i + 5],
290      cidr: getCIDR(data[i + 1], data[i + 2], data[i + 3]),
291    };
292    const scopeid = data[i + 6];
293    if (scopeid !== -1)
294      entry.scopeid = scopeid;
295
296    const existing = result[name];
297    if (existing !== undefined)
298      ArrayPrototypePush(existing, entry);
299    else
300      result[name] = [entry];
301  }
302
303  return result;
304}
305
306/**
307 * @param {number} [pid=0]
308 * @param {number} priority
309 * @returns {void}
310 */
311function setPriority(pid, priority) {
312  if (priority === undefined) {
313    priority = pid;
314    pid = 0;
315  }
316
317  validateInt32(pid, 'pid');
318  validateInt32(priority, 'priority', -20, 19);
319
320  const ctx = {};
321
322  if (_setPriority(pid, priority, ctx) !== 0)
323    throw new ERR_SYSTEM_ERROR(ctx);
324}
325
326/**
327 * @param {number} [pid=0]
328 * @returns {number}
329 */
330function getPriority(pid) {
331  if (pid === undefined)
332    pid = 0;
333  else
334    validateInt32(pid, 'pid');
335
336  const ctx = {};
337  const priority = _getPriority(pid, ctx);
338
339  if (priority === undefined)
340    throw new ERR_SYSTEM_ERROR(ctx);
341
342  return priority;
343}
344
345/**
346 * @param {{ encoding?: string }} [options=utf8] If `encoding` is set to
347 * `'buffer'`, the `username`, `shell`, and `homedir` values will
348 * be `Buffer` instances.
349 * @returns {{
350 *   uid: number,
351 *   gid: number,
352 *   username: string,
353 *   homedir: string,
354 *   shell: string | null,
355 * }}
356 */
357function userInfo(options) {
358  if (typeof options !== 'object')
359    options = null;
360
361  const ctx = {};
362  const user = getUserInfo(options, ctx);
363
364  if (user === undefined)
365    throw new ERR_SYSTEM_ERROR(ctx);
366
367  if (isWindows) {
368    user.uid |= 0;
369    user.gid |= 0;
370  }
371
372  return user;
373}
374
375module.exports = {
376  arch,
377  availableParallelism: getAvailableParallelism,
378  cpus,
379  endianness,
380  freemem: getFreeMem,
381  getPriority,
382  homedir: getHomeDirectory,
383  hostname: getHostname,
384  loadavg,
385  networkInterfaces,
386  platform,
387  release: getOSRelease,
388  setPriority,
389  tmpdir,
390  totalmem: getTotalMem,
391  type: getOSType,
392  userInfo,
393  uptime: getUptime,
394  version: getOSVersion,
395  machine: getMachine,
396};
397
398ObjectDefineProperties(module.exports, {
399  constants: {
400    __proto__: null,
401    configurable: false,
402    enumerable: true,
403    value: constants,
404  },
405
406  EOL: {
407    __proto__: null,
408    configurable: true,
409    enumerable: true,
410    writable: false,
411    value: isWindows ? '\r\n' : '\n',
412  },
413
414  devNull: {
415    __proto__: null,
416    configurable: true,
417    enumerable: true,
418    writable: false,
419    value: isWindows ? '\\\\.\\nul' : '/dev/null',
420  },
421});
422