platform_linux.odin 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. // +build linux
  2. package sysinfo
  3. import "core:c"
  4. import sys "core:sys/unix"
  5. import "core:intrinsics"
  6. import "core:os"
  7. import "core:strings"
  8. import "core:strconv"
  9. @(private)
  10. version_string_buf: [1024]u8
  11. @(init, private)
  12. init_os_version :: proc () {
  13. os_version.platform = .Linux
  14. // Try to parse `/etc/os-release` for `PRETTY_NAME="Ubuntu 20.04.3 LTS`
  15. fd, err := os.open("/etc/os-release", os.O_RDONLY, 0)
  16. if err != 0 {
  17. return
  18. }
  19. defer os.close(fd)
  20. os_release_buf: [2048]u8
  21. n, read_err := os.read(fd, os_release_buf[:])
  22. if read_err != 0 {
  23. return
  24. }
  25. release := string(os_release_buf[:n])
  26. NEEDLE :: "PRETTY_NAME=\""
  27. pretty_start := strings.index(release, NEEDLE)
  28. b := strings.builder_from_bytes(version_string_buf[:])
  29. if pretty_start > 0 {
  30. for r, i in release[pretty_start + len(NEEDLE):] {
  31. if r == '"' {
  32. strings.write_string(&b, release[pretty_start + len(NEEDLE):][:i])
  33. break
  34. } else if r == '\r' || r == '\n' {
  35. strings.write_string(&b, "Unknown Linux Distro")
  36. break
  37. }
  38. }
  39. }
  40. NEW_UTS_LEN :: 64
  41. UTS_Name :: struct {
  42. sys_name: [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`,
  43. node_name: [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`,
  44. release: [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`,
  45. version: [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`,
  46. machine: [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`,
  47. domain_name: [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`,
  48. }
  49. uts: UTS_Name
  50. // Grab kernel info using `uname()` syscall, https://linux.die.net/man/2/uname
  51. if intrinsics.syscall(sys.SYS_uname, uintptr(&uts)) != 0 {
  52. return
  53. }
  54. strings.write_string(&b, ", ")
  55. strings.write_string(&b, string(cstring(&uts.sys_name[0])))
  56. strings.write_rune(&b, ' ')
  57. l := strings.builder_len(b)
  58. strings.write_string(&b, string(cstring(&uts.release[0])))
  59. // Parse kernel version, as substrings of the version info in `version_string_buf`
  60. version_bits := strings.split_n(strings.to_string(b)[l:], "-", 2, context.temp_allocator)
  61. if len(version_bits) > 1 {
  62. os_version.version = version_bits[1]
  63. }
  64. // Parse major, minor, patch from release info
  65. triplet := strings.split(version_bits[0], ".", context.temp_allocator)
  66. if len(triplet) == 3 {
  67. major, major_ok := strconv.parse_int(triplet[0])
  68. minor, minor_ok := strconv.parse_int(triplet[1])
  69. patch, patch_ok := strconv.parse_int(triplet[2])
  70. if major_ok && minor_ok && patch_ok {
  71. os_version.major = major
  72. os_version.minor = minor
  73. os_version.patch = patch
  74. }
  75. }
  76. // Finish the string
  77. os_version.as_string = strings.to_string(b)
  78. }
  79. Sys_Info :: struct {
  80. uptime: c.long, // Seconds since boot
  81. loads: [3]c.long, // 1, 5, 15 minute load averages
  82. totalram: c.ulong, // Total usable main memory size
  83. freeram: c.ulong, // Available memory size
  84. sharedram: c.ulong, // Amount of shared memory
  85. bufferram: c.ulong, // Memory used by buffers
  86. totalswap: c.ulong, // Total swap space size
  87. freeswap: c.ulong, // Swap space still available
  88. procs: c.ushort, // Number of current processes
  89. totalhigh: c.ulong, // Total high memory size
  90. freehigh: c.ulong, // Available high memory size
  91. mem_unit: c.int, // Memory unit size in bytes
  92. _padding: [20 - (2 * size_of(c.long)) - size_of(c.int)]u8,
  93. }
  94. get_sysinfo :: proc "c" () -> (res: Sys_Info, ok: bool) {
  95. si: Sys_Info
  96. err := intrinsics.syscall(sys.SYS_sysinfo, uintptr(rawptr(&si)))
  97. if err != 0 {
  98. // Unable to retrieve sysinfo
  99. return {}, false
  100. }
  101. return si, true
  102. }
  103. @(init)
  104. init_ram :: proc() {
  105. // Retrieve RAM info using `sysinfo`
  106. si, ok := get_sysinfo()
  107. if !ok {
  108. return
  109. }
  110. ram = RAM{
  111. total_ram = int(si.totalram) * int(si.mem_unit),
  112. free_ram = int(si.freeram) * int(si.mem_unit),
  113. total_swap = int(si.totalswap) * int(si.mem_unit),
  114. free_swap = int(si.freeswap) * int(si.mem_unit),
  115. }
  116. }