lens

posix system fetch tool
git clone git://brookjeynes.dev/bjeynes/lens.git
Log | Files | Refs | README

stats.zig (7211B)


      1 const std = @import("std");
      2 const builtin = @import("builtin");
      3 
      4 pub fn getBattery(io: std.Io, allocator: std.mem.Allocator) ![]const u8 {
      5     if (builtin.os.tag != .linux and builtin.os.tag != .openbsd) return error.UnsupportedOs;
      6 
      7     var dir = try std.Io.Dir.openDirAbsolute(io, "/sys/class/power_supply/", .{ .iterate = true });
      8     defer dir.close(io);
      9 
     10     var smallest_battery: ?usize = null;
     11 
     12     // Walk dir and find the smallest battery.
     13     var it = try dir.walk(allocator);
     14     defer it.deinit();
     15     while (try it.next(io)) |entry| {
     16         if (std.mem.startsWith(u8, entry.basename, "BAT")) {
     17             const battery_no = try std.fmt.parseInt(usize, std.mem.trimStart(u8, entry.basename, "BAT"), 10);
     18             if (smallest_battery) |smallest| {
     19                 if (battery_no < smallest) smallest_battery = battery_no;
     20             } else {
     21                 smallest_battery = battery_no;
     22             }
     23         }
     24     }
     25 
     26     if (smallest_battery == null) return error.NoBatteryDetected;
     27 
     28     // Read battery capacity.
     29     var battery_capacity_path_buf: [std.Io.Dir.max_path_bytes]u8 = undefined;
     30     const battery_capacity_path = try std.fmt.bufPrint(
     31         &battery_capacity_path_buf,
     32         "/sys/class/power_supply/BAT{d}/capacity",
     33         .{smallest_battery.?},
     34     );
     35     const battery_capacity_file = try std.Io.Dir.openFileAbsolute(
     36         io,
     37         battery_capacity_path,
     38         .{ .mode = .read_only },
     39     );
     40     defer battery_capacity_file.close(io);
     41 
     42     var battery_capacity_buf: [1024]u8 = undefined;
     43     var battery_capacity_file_reader = battery_capacity_file.reader(io, &.{});
     44 
     45     const battery_capacity_bytes = try battery_capacity_file_reader.interface.readSliceShort(&battery_capacity_buf);
     46     const battery_capacity = try std.fmt.parseInt(
     47         usize,
     48         std.mem.trim(u8, battery_capacity_buf[0..battery_capacity_bytes], "\n"),
     49         10,
     50     );
     51 
     52     // Read battery status.
     53     var battery_status_path_buf: [std.Io.Dir.max_path_bytes]u8 = undefined;
     54     const battery_status_path = try std.fmt.bufPrint(
     55         &battery_status_path_buf,
     56         "/sys/class/power_supply/BAT{d}/status",
     57         .{smallest_battery.?},
     58     );
     59     const battery_status_file = try std.Io.Dir.openFileAbsolute(
     60         io,
     61         battery_status_path,
     62         .{ .mode = .read_only },
     63     );
     64     defer battery_status_file.close(io);
     65 
     66     var battery_status_buf: [1024]u8 = undefined;
     67     var battery_status_file_reader = battery_status_file.reader(io, &.{});
     68 
     69     const battery_status_bytes = try battery_status_file_reader.interface.readSliceShort(&battery_status_buf);
     70     const battery_status = std.mem.trim(
     71         u8,
     72         battery_status_buf[0..battery_status_bytes],
     73         "\n",
     74     );
     75 
     76     var output_buf: [1024]u8 = undefined;
     77     const output = try std.fmt.bufPrint(
     78         &output_buf,
     79         "{d}% ({s})",
     80         .{ battery_capacity, battery_status },
     81     );
     82     return try allocator.dupe(u8, output);
     83 }
     84 
     85 pub fn getMemory(io: std.Io, allocator: std.mem.Allocator, options: struct { mb: bool }) ![]const u8 {
     86     if (builtin.os.tag != .linux and builtin.os.tag != .openbsd) return error.UnsupportedOs;
     87 
     88     const file = try std.Io.Dir.openFileAbsolute(io, "/proc/meminfo", .{ .mode = .read_only });
     89     defer file.close(io);
     90 
     91     var file_buffer: [1024]u8 = undefined;
     92     var file_reader = file.reader(io, &file_buffer);
     93 
     94     const dividend: usize = if (options.mb) 1000 else 1024;
     95     const suffix = if (options.mb) "MB" else "MiB";
     96 
     97     const mem_total = lbl: {
     98         const line = try file_reader.interface.takeDelimiter('\n') orelse return error.MemAvailableIsNotSpecified;
     99         var line_it = std.mem.splitScalar(u8, line, ':');
    100         _ = line_it.next(); // Skip "MemTotal:"
    101         const mem_total_with_suffix = line_it.next() orelse return error.MemTotalIsNull;
    102         // TODO: Is it safe to assume the suffix will only ever be "kB"?
    103         const mem_total_str = std.mem.trim(u8, mem_total_with_suffix, " \tkB");
    104         const mem_total_int = (try std.fmt.parseInt(usize, mem_total_str, 10)) / dividend;
    105         break :lbl mem_total_int;
    106     };
    107 
    108     _ = try file_reader.interface.takeDelimiter('\n'); // Skip "MemFree: x"
    109 
    110     const mem_available = lbl: {
    111         const line = try file_reader.interface.takeDelimiter('\n') orelse return error.MemAvailableIsNotSpecified;
    112         var line_it = std.mem.splitScalar(u8, line, ':');
    113         _ = line_it.next(); // Skip "MemAvailable:"
    114         const mem_available_with_suffix = line_it.next() orelse return error.MemAvailableIsNull;
    115         // TODO: Is it safe to assume it'll only ever be "kB"?
    116         const mem_available_str = std.mem.trim(u8, mem_available_with_suffix, " \tkB");
    117         const mem_available_int = (try std.fmt.parseInt(usize, mem_available_str, 10)) / dividend;
    118         break :lbl mem_available_int;
    119     };
    120 
    121     const mem_used = mem_total - mem_available;
    122     const mem_percentage: usize = @intFromFloat(
    123         (@as(f32, @floatFromInt(mem_used)) / @as(f32, @floatFromInt(mem_total))) * 100,
    124     );
    125 
    126     var buf: [1024]u8 = undefined;
    127     const mem_str = try std.fmt.bufPrint(&buf, "{d} / {d} {s} ({d}%)", .{
    128         mem_used,
    129         mem_total,
    130         suffix,
    131         mem_percentage,
    132     });
    133     return try allocator.dupe(u8, mem_str);
    134 }
    135 
    136 pub fn getUptime() !struct { days: isize, minutes: isize, hours: isize } {
    137     switch (builtin.os.tag) {
    138         .linux, .openbsd => {
    139             var info: std.os.linux.Sysinfo = undefined;
    140             const result: std.os.linux.E = @enumFromInt(std.os.linux.sysinfo(&info));
    141             if (result != .SUCCESS) {
    142                 return error.UnknownUptime;
    143             }
    144             const uptime = info.uptime;
    145 
    146             const uptime_days = @divTrunc(uptime, 86400);
    147             const uptime_hours = @divTrunc(@rem(uptime, 86400), 3600);
    148             const uptime_minutes = @divTrunc(@rem(uptime, 3600), 60);
    149 
    150             return .{
    151                 .days = uptime_days,
    152                 .minutes = uptime_minutes,
    153                 .hours = uptime_hours,
    154             };
    155         },
    156         // TODO: upgrade to 0.16.0
    157         // .macos => {
    158         //     var boot_timeval: std.posix.timeval = undefined;
    159         //     var size: usize = @sizeOf(@TypeOf(boot_timeval));
    160         //     const kern_boottime = [_]c_int{ 1, 21 }; // CTL_KERN, KERN_BOOTTIME return void on macos
    161         //     std.posix.sysctl(
    162         //         &kern_boottime,
    163         //         @ptrCast(&boot_timeval),
    164         //         &size,
    165         //         null,
    166         //         0,
    167         //     ) catch return error.SysctlFailed;
    168         //
    169         //     const now = std.time.timestamp();
    170         //     const boot_time = boot_timeval.sec;
    171         //     const uptime = now - boot_time;
    172         //
    173         //     const uptime_days = @divTrunc(uptime, 86400);
    174         //     const uptime_hours = @divTrunc(@rem(uptime, 86400), 3600);
    175         //     const uptime_minutes = @divTrunc(@rem(uptime, 3600), 60);
    176         //
    177         //     return .{
    178         //         .days = uptime_days,
    179         //         .minutes = uptime_minutes,
    180         //         .hours = uptime_hours,
    181         //     };
    182         // },
    183         else => return error.UnsupportedOs,
    184     }
    185 }