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