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