const objc = @import("objc"); const std = @import("std"); const c = @cImport({ @cInclude("sys/types.h"); @cInclude("sys/utsname.h"); @cInclude("sys/sysctl.h"); @cInclude("sys/time.h"); }); const OsVersion = struct { name: []const u8, major: i64, }; pub fn macosVersionAtLeast(major: i64, minor: i64, patch: i64) bool { // Get the objc class from the runtime const NSProcessInfo = objc.getClass("NSProcessInfo").?; // Call a class method with no arguments that returns another objc object. const info = NSProcessInfo.msgSend(objc.Object, "processInfo", .{}); // var NSOperatingSystemVersion = objc.getClass("NSOperatingSystemVersion").?; // const os = info.msgSend(objc.Object, "") // Call an instance method that returns a boolean and takes a single // argument. return info.msgSend(bool, "isOperatingSystemAtLeastVersion:", .{ NSOperatingSystemVersion{ .major = major, .minor = minor, .patch = patch }, }); } pub fn macos_version(allocator: std.mem.Allocator) ![]const u8 { const NSProcessInfo = objc.getClass("NSProcessInfo").?; // Call a class method with no arguments that returns another objc object. const info = NSProcessInfo.msgSend(objc.Object, "processInfo", .{}); const koko = info.msgSend(NSOperatingSystemVersion, "operatingSystemVersion", .{}); const buf = try std.fmt.allocPrint(allocator, ": macOS {s} {d}.{d}.{d}\n", .{ version_to_name(koko), koko.major, koko.minor, koko.patch }); return buf; } pub fn macos_kernel_version(allocator: std.mem.Allocator) ![]const u8 { var name: c.struct_utsname = undefined; if (c.uname(&name) != 0) { return error.UnameFailed; } const sysname = std.mem.sliceTo(name.sysname[0..], 0); const version = std.mem.sliceTo(name.release[0..], 0); const buf = try std.fmt.allocPrint(allocator, ": {s} {s}\n", .{ sysname, version }); return buf; } pub fn macos_cpu_info(allocator: std.mem.Allocator) ![]const u8 { var cpu_brand: [128]u8 = undefined; var cpu_brand_size: usize = cpu_brand.len; var cpu_cores: c_int = 0; var cpu_cores_size: usize = @sizeOf(c_int); if (c.sysctlbyname("machdep.cpu.core_count", &cpu_cores, @as([*c]usize, &cpu_cores_size), null, 0) < 0) { return error.SysctlFailed; } if (c.sysctlbyname("machdep.cpu.brand_string", &cpu_brand, &cpu_brand_size, null, 0) < 0) { return error.SysctlFailed; } // if (c.sysctlbyname("hw.cpufrequency", &)) const buf = try std.fmt.allocPrint(allocator, ": {s} ({d} cores)\n", .{ cpu_brand[0..cpu_brand_size], cpu_cores }); return buf; } pub fn macos_uptime(allocator: std.mem.Allocator) ![]const u8 { var mib: [2]c.integer_t = [_]c.integer_t{ c.CTL_KERN, c.KERN_BOOTTIME }; var boottime: c.struct_timeval = undefined; var size: u64 = @sizeOf(c.struct_timeval); if (c.sysctl(&mib[0], 2, &boottime, @as([*c]usize, &size), null, 0) < 0) { return error.SysctlFailed; } var now: c.time_t = 0; _ = c.time(&now); const uptime_seconds: i64 = now - boottime.tv_sec; const days = @divFloor(uptime_seconds, (24 * 60 * 60)); const hours = @divFloor(@rem(uptime_seconds, (24 * 60 * 60)), (60 * 60)); const minutes = @divFloor(@rem(uptime_seconds, (60 * 60)), 60); const buf = try std.fmt.allocPrint(allocator, ": {d} days, {d} hours, {d} mins\n", .{ days, hours, minutes }); return buf; } fn version_to_name(version: NSOperatingSystemVersion) []const u8 { switch (version.major) { 15 => return "Sequoia", 14 => return "Sonoma", 13 => return "Ventura", 12 => return "Monterey", 11 => return "Big Sur", 10 => { switch (version.minor) { 15 => return "Catalina", 14 => return "Mojave", else => return "Unknown", } }, else => return "Unknown", } } /// This extern struct matches the Cocoa headers for layout. const NSOperatingSystemVersion = extern struct { major: i64, minor: i64, patch: i64, };