• 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 
24 const {
25   ArrayPrototypePush,
26   Float64Array,
27   NumberParseInt,
28   ObjectDefineProperties,
29   StringPrototypeEndsWith,
30   StringPrototypeSlice,
31   StringPrototypeSplit,
32   SymbolToPrimitive,
33 } = primordials;
34 
35 const { safeGetenv } = internalBinding('credentials');
36 const constants = internalBinding('constants').os;
37 const isWindows = process.platform === 'win32';
38 
39 const {
40   codes: {
41     ERR_SYSTEM_ERROR
42   },
43   hideStackFrames
44 } = require('internal/errors');
45 const { validateInt32 } = require('internal/validators');
46 
47 const {
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 
63 function 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 
74 const {
75   0: type,
76   1: version,
77   2: release,
78 } = _getOSInformation();
79 
80 const getHomeDirectory = getCheckedFunction(_getHomeDirectory);
81 const getHostname = getCheckedFunction(_getHostname);
82 const getInterfaceAddresses = getCheckedFunction(_getInterfaceAddresses);
83 /**
84  * @returns {string}
85  */
86 const getOSRelease = () => release;
87 /**
88  * @returns {string}
89  */
90 const getOSType = () => type;
91 /**
92  * @returns {string}
93  */
94 const getOSVersion = () => version;
95 
96 getFreeMem[SymbolToPrimitive] = () => getFreeMem();
97 getHostname[SymbolToPrimitive] = () => getHostname();
98 getOSVersion[SymbolToPrimitive] = () => getOSVersion();
99 getOSType[SymbolToPrimitive] = () => getOSType();
100 getOSRelease[SymbolToPrimitive] = () => getOSRelease();
101 getHomeDirectory[SymbolToPrimitive] = () => getHomeDirectory();
102 getTotalMem[SymbolToPrimitive] = () => getTotalMem();
103 getUptime[SymbolToPrimitive] = () => getUptime();
104 
105 const kEndianness = isBigEndian ? 'BE' : 'LE';
106 
107 const avgValues = new Float64Array(3);
108 
109 /**
110  * @returns {[number, number, number]}
111  */
112 function 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  */
133 function 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  */
157 function arch() {
158   return process.arch;
159 }
160 arch[SymbolToPrimitive] = () => process.arch;
161 
162 /**
163  * @returns {string}
164  */
165 function platform() {
166   return process.platform;
167 }
168 platform[SymbolToPrimitive] = () => process.platform;
169 
170 /**
171  * @returns {string}
172  */
173 function 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 }
193 tmpdir[SymbolToPrimitive] = () => tmpdir();
194 
195 /**
196  * @returns {'BE' | 'LE'}
197  */
198 function endianness() {
199   return kEndianness;
200 }
201 endianness[SymbolToPrimitive] = () => kEndianness;
202 
203 // Returns the number of ones in the binary representation of the decimal
204 // number.
205 function 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 
212 function 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  */
258 function 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  */
293 function 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  */
312 function 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  */
339 function 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 
352 module.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 
373 ObjectDefineProperties(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