platform_linux.odin 3.7 KB

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