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