diff options
-rw-r--r-- | src/bun.js/node/node_os.zig | 174 | ||||
-rw-r--r-- | test/bun.js/os.test.js | 9 |
2 files changed, 83 insertions, 100 deletions
diff --git a/src/bun.js/node/node_os.zig b/src/bun.js/node/node_os.zig index 9bf1bbb86..8c59de8a2 100644 --- a/src/bun.js/node/node_os.zig +++ b/src/bun.js/node/node_os.zig @@ -67,8 +67,7 @@ pub const Os = struct { const fields = comptime std.meta.fieldNames(CPUTimes); const ret = JSC.JSValue.createEmptyObject(globalThis, fields.len); inline for (fields) |fieldName| { - ret.put(globalThis, JSC.ZigString.static(fieldName), - JSC.JSValue.jsNumberFromUint64(@field(self, fieldName))); + ret.put(globalThis, JSC.ZigString.static(fieldName), JSC.JSValue.jsNumberFromUint64(@field(self, fieldName))); } return ret; } @@ -78,27 +77,27 @@ pub const Os = struct { JSC.markBinding(@src()); return if (comptime Environment.isLinux) - cpusImplLinux(globalThis) catch { - const err = JSC.SystemError{ - .message = JSC.ZigString.init("Failed to get cpu information"), - .code = JSC.ZigString.init(@as(string, @tagName(JSC.Node.ErrorCode.ERR_SYSTEM_ERROR))), - }; - - globalThis.vm().throwError(globalThis, err.toErrorInstance(globalThis)); - return JSC.JSValue.jsUndefined(); - } - else if (comptime Environment.isMac) - cpusImplDarwin(globalThis) catch { - const err = JSC.SystemError{ - .message = JSC.ZigString.init("Failed to get cpu information"), - .code = JSC.ZigString.init(@as(string, @tagName(JSC.Node.ErrorCode.ERR_SYSTEM_ERROR))), - }; - - globalThis.vm().throwError(globalThis, err.toErrorInstance(globalThis)); - return JSC.JSValue.jsUndefined(); - } - else - JSC.JSValue.createEmptyArray(globalThis, 0); + cpusImplLinux(globalThis) catch { + const err = JSC.SystemError{ + .message = JSC.ZigString.init("Failed to get cpu information"), + .code = JSC.ZigString.init(@as(string, @tagName(JSC.Node.ErrorCode.ERR_SYSTEM_ERROR))), + }; + + globalThis.vm().throwError(globalThis, err.toErrorInstance(globalThis)); + return JSC.JSValue.jsUndefined(); + } + else if (comptime Environment.isMac) + cpusImplDarwin(globalThis) catch { + const err = JSC.SystemError{ + .message = JSC.ZigString.init("Failed to get cpu information"), + .code = JSC.ZigString.init(@as(string, @tagName(JSC.Node.ErrorCode.ERR_SYSTEM_ERROR))), + }; + + globalThis.vm().throwError(globalThis, err.toErrorInstance(globalThis)); + return JSC.JSValue.jsUndefined(); + } + else + JSC.JSValue.createEmptyArray(globalThis, 0); } fn cpusImplLinux(globalThis: *JSC.JSGlobalObject) !JSC.JSValue { @@ -107,7 +106,7 @@ pub const Os = struct { var num_cpus: u32 = 0; // Use a large line buffer because the /proc/stat file can have a very long list of interrupts - var line_buffer: [1024*8]u8 = undefined; + var line_buffer: [1024 * 8]u8 = undefined; // Read /proc/stat to get number of CPUs and times if (std.fs.openFileAbsolute("/proc/stat", .{})) |file| { @@ -131,10 +130,10 @@ pub const Os = struct { var times = CPUTimes{}; times.user = scale * try std.fmt.parseInt(u64, toks.next() orelse return error.eol, 10); times.nice = scale * try std.fmt.parseInt(u64, toks.next() orelse return error.eol, 10); - times.sys = scale * try std.fmt.parseInt(u64, toks.next() orelse return error.eol, 10); + times.sys = scale * try std.fmt.parseInt(u64, toks.next() orelse return error.eol, 10); times.idle = scale * try std.fmt.parseInt(u64, toks.next() orelse return error.eol, 10); _ = try (toks.next() orelse error.eol); // skip iowait - times.irq = scale * try std.fmt.parseInt(u64, toks.next() orelse return error.eol, 10); + times.irq = scale * try std.fmt.parseInt(u64, toks.next() orelse return error.eol, 10); // Actually create the JS object representing the CPU const cpu = JSC.JSValue.createEmptyObject(globalThis, 3); @@ -161,13 +160,11 @@ pub const Os = struct { const digits = std.mem.trim(u8, line[key_processor.len..], " \t\n"); cpu_index = try std.fmt.parseInt(u32, digits, 10); if (cpu_index >= num_cpus) return error.too_may_cpus; - } else if (std.mem.startsWith(u8, line, key_model_name)) { // If this is the model name, extract it and store on the current cpu const model_name = line[key_model_name.len..]; const cpu = JSC.JSObject.getIndex(values, globalThis, cpu_index); - cpu.put(globalThis, JSC.ZigString.static("model"), - JSC.ZigString.init(model_name).withEncoding().toValueGC(globalThis)); + cpu.put(globalThis, JSC.ZigString.static("model"), JSC.ZigString.init(model_name).withEncoding().toValueGC(globalThis)); } //TODO: special handling for ARM64 (no model name)? } @@ -175,8 +172,7 @@ pub const Os = struct { // Initialize model name to "unknown" var it = values.arrayIterator(globalThis); while (it.next()) |cpu| { - cpu.put(globalThis, JSC.ZigString.static("model"), - JSC.ZigString.static("unknown").withEncoding().toValue(globalThis)); + cpu.put(globalThis, JSC.ZigString.static("model"), JSC.ZigString.static("unknown").withEncoding().toValue(globalThis)); } } @@ -212,11 +208,7 @@ pub const Os = struct { var num_cpus: c.natural_t = 0; var info: [*]local_bindings.processor_cpu_load_info = undefined; var info_size: std.c.mach_msg_type_number_t = 0; - if (local_bindings.host_processor_info( - std.c.mach_host_self(), - local_bindings.PROCESSOR_CPU_LOAD_INFO, - &num_cpus, @ptrCast(*local_bindings.processor_info_array_t, &info), - &info_size) != .SUCCESS) { + if (local_bindings.host_processor_info(std.c.mach_host_self(), local_bindings.PROCESSOR_CPU_LOAD_INFO, &num_cpus, @ptrCast(*local_bindings.processor_info_array_t, &info), &info_size) != .SUCCESS) { return error.no_processor_info; } defer _ = std.c.vm_deallocate(std.c.mach_task_self(), @ptrToInt(info), info_size); @@ -226,13 +218,13 @@ pub const Os = struct { return error.broken_process_info; } - // Get CPU model name var model_name_buf: [512]u8 = undefined; var len: usize = model_name_buf.len; // Try brand_string first and if it fails try hw.model if (!(std.c.sysctlbyname("machdep.cpu.brand_string", &model_name_buf, &len, null, 0) == 0 or - std.c.sysctlbyname("hw.model", &model_name_buf, &len, null, 0) == 0)) { + std.c.sysctlbyname("hw.model", &model_name_buf, &len, null, 0) == 0)) + { return error.no_processor_info; } //NOTE: sysctlbyname doesn't update len if it was large enough, so we @@ -240,7 +232,6 @@ pub const Os = struct { // model name. const model_name = JSC.ZigString.init(std.mem.sliceTo(&model_name_buf, 0)).withEncoding().toValueGC(globalThis); - // Get CPU speed var speed: u64 = 0; len = @sizeOf(@TypeOf(speed)); @@ -252,9 +243,10 @@ pub const Os = struct { speed = 2_400_000_000; } - // Get the multiplier; this is the number of ms/tick - const unistd = @cImport({@cInclude("unistd.h");}); + const unistd = @cImport({ + @cInclude("unistd.h"); + }); const ticks: i64 = unistd.sysconf(unistd._SC_CLK_TCK); const multiplier = 1000 / @intCast(u64, ticks); @@ -265,9 +257,9 @@ pub const Os = struct { const times = CPUTimes{ .user = info[cpu_index].cpu_ticks[0] * multiplier, .nice = info[cpu_index].cpu_ticks[3] * multiplier, - .sys = info[cpu_index].cpu_ticks[1] * multiplier, + .sys = info[cpu_index].cpu_ticks[1] * multiplier, .idle = info[cpu_index].cpu_ticks[2] * multiplier, - .irq = 0, // not available + .irq = 0, // not available }; const cpu = JSC.JSValue.createEmptyObject(globalThis, 3); @@ -397,7 +389,6 @@ pub const Os = struct { } defer C.freeifaddrs(interface_start); - const helpers = struct { // We'll skip interfaces that aren't actually available pub fn skip(iface: *C.ifaddrs) bool { @@ -414,10 +405,11 @@ pub const Os = struct { pub fn isLinkLayer(iface: *C.ifaddrs) bool { if (iface.ifa_addr == null) return false; return if (comptime Environment.isLinux) - return iface.ifa_addr.*.sa_family == std.os.AF.PACKET - else if (comptime Environment.isMac) - return iface.ifa_addr.?.*.family == std.os.AF.LINK - else unreachable; + return iface.ifa_addr.*.sa_family == std.os.AF.PACKET + else if (comptime Environment.isMac) + return iface.ifa_addr.?.*.family == std.os.AF.LINK + else + unreachable; } pub fn isLoopback(iface: *C.ifaddrs) bool { @@ -425,7 +417,6 @@ pub const Os = struct { } }; - // The list currently contains entries for link-layer interfaces // and the IPv4, IPv6 interfaces. We only want to return the latter two // but need the link-layer entries to determine MAC address. @@ -459,7 +450,7 @@ pub const Os = struct { const maybe_suffix: ?u8 = switch (addr.any.family) { std.os.AF.INET => netmaskToCIDRSuffix(netmask.in.sa.addr), std.os.AF.INET6 => netmaskToCIDRSuffix(@bitCast(u128, netmask.in6.sa.addr)), - else => null + else => null, }; // Format the address and then, if valid, the CIDR suffix; both @@ -472,14 +463,13 @@ pub const Os = struct { //NOTE addr_str might not start at buf[0] due to slicing in formatAddress const start = @ptrToInt(addr_str.ptr) - @ptrToInt(&buf[0]); // Start writing the suffix immediately after the address - const suffix_str = std.fmt.bufPrint(buf[start + addr_str.len..], "/{}", .{ suffix }) catch unreachable; + const suffix_str = std.fmt.bufPrint(buf[start + addr_str.len ..], "/{}", .{suffix}) catch unreachable; // The full cidr value is the address + the suffix - const cidr_str = buf[start..start + addr_str.len + suffix_str.len]; + const cidr_str = buf[start .. start + addr_str.len + suffix_str.len]; cidr = JSC.ZigString.init(cidr_str).withEncoding().toValueGC(globalThis); } - interface.put(globalThis, JSC.ZigString.static("address"), - JSC.ZigString.init(addr_str).withEncoding().toValueGC(globalThis)); + interface.put(globalThis, JSC.ZigString.static("address"), JSC.ZigString.init(addr_str).withEncoding().toValueGC(globalThis)); interface.put(globalThis, JSC.ZigString.static("cidr"), cidr); } @@ -487,18 +477,15 @@ pub const Os = struct { { var buf: [64]u8 = undefined; const str = formatAddress(netmask, &buf) catch unreachable; - interface.put(globalThis, JSC.ZigString.static("netmask"), - JSC.ZigString.init(str).withEncoding().toValueGC(globalThis)); + interface.put(globalThis, JSC.ZigString.static("netmask"), JSC.ZigString.init(str).withEncoding().toValueGC(globalThis)); } // family <string> Either IPv4 or IPv6 - interface.put(globalThis, JSC.ZigString.static("family"), - (switch (addr.any.family) { - std.os.AF.INET => JSC.ZigString.static("IPv4"), - std.os.AF.INET6 => JSC.ZigString.static("IPv6"), - else => JSC.ZigString.static("unknown"), - }).toValue(globalThis) - ); + interface.put(globalThis, JSC.ZigString.static("family"), (switch (addr.any.family) { + std.os.AF.INET => JSC.ZigString.static("IPv4"), + std.os.AF.INET6 => JSC.ZigString.static("IPv6"), + else => JSC.ZigString.static("unknown"), + }).toValue(globalThis)); // mac <string> The MAC address of the network interface { @@ -524,32 +511,23 @@ pub const Os = struct { // Encode its link-layer address. We need 2*6 bytes for the // hex characters and 5 for the colon separators var mac_buf: [17]u8 = undefined; - var addr_data = if (comptime Environment.isLinux) ll_addr.addr - else if (comptime Environment.isMac) ll_addr.sdl_data[ll_addr.sdl_nlen..] - else unreachable; - const mac = std.fmt.bufPrint(&mac_buf, - "{x:0>2}:{x:0>2}:{x:0>2}:{x:0>2}:{x:0>2}:{x:0>2}", - .{ - addr_data[0], addr_data[1], addr_data[2], - addr_data[3], addr_data[4], addr_data[5], - } - ) catch unreachable; - interface.put(globalThis, JSC.ZigString.static("mac"), - JSC.ZigString.init(mac).withEncoding().toValueGC(globalThis)); + var addr_data = if (comptime Environment.isLinux) ll_addr.addr else if (comptime Environment.isMac) ll_addr.sdl_data[ll_addr.sdl_nlen..] else unreachable; + const mac = std.fmt.bufPrint(&mac_buf, "{x:0>2}:{x:0>2}:{x:0>2}:{x:0>2}:{x:0>2}:{x:0>2}", .{ + addr_data[0], addr_data[1], addr_data[2], + addr_data[3], addr_data[4], addr_data[5], + }) catch unreachable; + interface.put(globalThis, JSC.ZigString.static("mac"), JSC.ZigString.init(mac).withEncoding().toValueGC(globalThis)); } } // internal <boolean> true if the network interface is a loopback or similar interface that is not remotely accessible; otherwise false - interface.put(globalThis, JSC.ZigString.static("internal"), - JSC.JSValue.jsBoolean(helpers.isLoopback(iface))); + interface.put(globalThis, JSC.ZigString.static("internal"), JSC.JSValue.jsBoolean(helpers.isLoopback(iface))); // scopeid <number> The numeric IPv6 scope ID (only specified when family is IPv6) if (addr.any.family == std.os.AF.INET6) { - interface.put(globalThis, JSC.ZigString.static("scope_id"), - JSC.JSValue.jsNumber(addr.in6.sa.scope_id)); + interface.put(globalThis, JSC.ZigString.static("scope_id"), JSC.JSValue.jsNumber(addr.in6.sa.scope_id)); } - // Does this entry already exist? if (ret.get(globalThis, interface_name)) |array| { // Add this interface entry to the existing array @@ -567,7 +545,6 @@ pub const Os = struct { return ret; } - pub fn platform(globalThis: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) JSC.JSValue { JSC.markBinding(@src()); @@ -656,7 +633,8 @@ pub const Os = struct { break :brk systemdir_ ++ "\\temp"; } } else { - break :brk bun.asByteSlice(bun.getenvZ("TMPDIR") orelse bun.getenvZ("TMP") orelse bun.getenvZ("TEMP") orelse "/tmp"); + const dir = bun.asByteSlice(bun.getenvZ("TMPDIR") orelse bun.getenvZ("TMP") orelse bun.getenvZ("TEMP") orelse "/tmp"); + break :brk strings.withoutTrailingSlash(dir); } break :brk "unknown"; @@ -756,8 +734,8 @@ fn formatAddress(address: std.net.Address, into: []u8) ![]u8 { result = result[0..colon]; } // Strip brackets - if (result[0] == '[' and result[result.len-1] == ']') { - result = result[1..result.len-1]; + if (result[0] == '[' and result[result.len - 1] == ']') { + result = result[1 .. result.len - 1]; } return result; } @@ -782,20 +760,20 @@ test "netmaskToCIDRSuffix" { .{ "255.255.255.254", 31 }, .{ "255.255.255.252", 30 }, .{ "255.255.255.128", 25 }, - .{ "255.255.255.0", 24 }, - .{ "255.255.128.0", 17 }, - .{ "255.255.0.0", 16 }, - .{ "255.128.0.0", 9 }, - .{ "255.0.0.0", 8 }, - .{ "224.0.0.0", 3 }, - .{ "192.0.0.0", 2 }, - .{ "128.0.0.0", 1 }, - .{ "0.0.0.0", 0 }, + .{ "255.255.255.0", 24 }, + .{ "255.255.128.0", 17 }, + .{ "255.255.0.0", 16 }, + .{ "255.128.0.0", 9 }, + .{ "255.0.0.0", 8 }, + .{ "224.0.0.0", 3 }, + .{ "192.0.0.0", 2 }, + .{ "128.0.0.0", 1 }, + .{ "0.0.0.0", 0 }, // invalid masks .{ "255.0.0.255", null }, .{ "128.0.0.255", null }, - .{ "128.0.0.1", null }, + .{ "128.0.0.1", null }, }; inline for (ipv4_tests) |t| { const addr = try std.net.Address.parseIp4(t[0], 0); @@ -804,12 +782,12 @@ test "netmaskToCIDRSuffix" { const ipv6_tests = .{ .{ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 128 }, - .{ "ffff:ffff:ffff:ffff::", 64 }, - .{ "::", 0 }, + .{ "ffff:ffff:ffff:ffff::", 64 }, + .{ "::", 0 }, // invalid masks - .{ "ff00:1::", null }, - .{ "0:1::", null }, + .{ "ff00:1::", null }, + .{ "0:1::", null }, }; inline for (ipv6_tests) |t| { const addr = try std.net.Address.parseIp6(t[0], 0); diff --git a/test/bun.js/os.test.js b/test/bun.js/os.test.js index 122969337..ea685cdb7 100644 --- a/test/bun.js/os.test.js +++ b/test/bun.js/os.test.js @@ -42,7 +42,11 @@ it("tmpdir", () => { expect(os.tmpdir()).toBe(process.env.TEMP || process.env.TMP); expect(os.tmpdir()).toBe(`${process.env.SystemRoot || process.env.windir}\\temp`); } else { - expect(os.tmpdir()).toBe(process.env.TMPDIR || process.env.TMP || process.env.TEMP || "/tmp"); + let dir = process.env.TMPDIR || process.env.TMP || process.env.TEMP || "/tmp"; + if (dir.length > 1 && dir.endsWith("/")) { + dir = dir.substring(0, dir.length - 1); + } + expect(os.tmpdir()).toBe(dir); } }); @@ -110,7 +114,8 @@ it("networkInterfaces", () => { expect(typeof nI.family === "string").toBe(true); expect(typeof nI.mac === "string").toBe(true); expect(typeof nI.internal === "boolean").toBe(true); - if (nI.cidr) // may be null + if (nI.cidr) + // may be null expect(typeof nI.cidr).toBe("string"); } } |