Browse Source

sys/info: improve platform_linux

1. fix the `linux.open` call, passing `{ .RDONLY }` becomes `0x00000001`
   while `RDONLY` is supposed to be `0x00000000`
2. fix the case where `/etc/os-release` starts with `PRETTY_NAME`
   `strings.index` was used but was checking `> 0` while `0` is valid
3. remove unneccesary temporary allocations
4. simplify the logic
Laytan Laats 1 year ago
parent
commit
485afb011c
1 changed files with 57 additions and 45 deletions
  1. 57 45
      core/sys/info/platform_linux.odin

+ 57 - 45
core/sys/info/platform_linux.odin

@@ -1,10 +1,9 @@
 package sysinfo
 package sysinfo
 
 
 import "base:intrinsics"
 import "base:intrinsics"
-import "base:runtime"
-import "core:strings"
-import "core:strconv"
 
 
+import "core:strconv"
+import "core:strings"
 import "core:sys/linux"
 import "core:sys/linux"
 
 
 @(private)
 @(private)
@@ -13,32 +12,37 @@ version_string_buf: [1024]u8
 @(init, private)
 @(init, private)
 init_os_version :: proc () {
 init_os_version :: proc () {
 	os_version.platform = .Linux
 	os_version.platform = .Linux
-	// Try to parse `/etc/os-release` for `PRETTY_NAME="Ubuntu 20.04.3 LTS`
-	fd, errno := linux.open("/etc/os-release", {.RDONLY}, {})
-	assert(errno == .NONE, "Failed to read /etc/os-release")
-	defer {
-		cerrno := linux.close(fd)
-		assert(cerrno == .NONE, "Failed to close the file descriptor")
-	}
-	os_release_buf: [2048]u8
-	n, read_errno := linux.read(fd, os_release_buf[:])
-	assert(read_errno == .NONE, "Failed to read data from /etc/os-release")
-	release := string(os_release_buf[:n])
-	// Search the line in the file until we find "PRETTY_NAME="
-	NEEDLE :: "PRETTY_NAME=\""
-	pretty_start := strings.index(release, NEEDLE)
+
 	b := strings.builder_from_bytes(version_string_buf[:])
 	b := strings.builder_from_bytes(version_string_buf[:])
-	if pretty_start > 0 {
-		for r, i in release[pretty_start + len(NEEDLE):] {
-			if r == '"' {
-				strings.write_string(&b, release[pretty_start + len(NEEDLE):][:i])
-				break
-			} else if r == '\r' || r == '\n' {
-				strings.write_string(&b, "Unknown Linux Distro")
-				break
+
+	// Try to parse `/etc/os-release` for `PRETTY_NAME="Ubuntu 20.04.3 LTS`
+	{
+		fd, errno := linux.open("/etc/os-release", {})
+		assert(errno == .NONE, "Failed to read /etc/os-release")
+		defer {
+			cerrno := linux.close(fd)
+			assert(cerrno == .NONE, "Failed to close the file descriptor")
+		}
+
+		os_release_buf: [2048]u8
+		n, read_errno := linux.read(fd, os_release_buf[:])
+		assert(read_errno == .NONE, "Failed to read data from /etc/os-release")
+		release := string(os_release_buf[:n])
+
+		// Search the line in the file until we find "PRETTY_NAME="
+		NEEDLE :: "PRETTY_NAME=\""
+		_, _, post := strings.partition(release, NEEDLE)
+		if len(post) > 0 {
+			end := strings.index_any(post, "\"\n")
+			if end > -1 && post[end] == '"' {
+				strings.write_string(&b, post[:end])
 			}
 			}
 		}
 		}
+		if strings.builder_len(b) == 0 {
+			strings.write_string(&b, "Unknown Linux Distro")
+		}
 	}
 	}
+
 	// Grab kernel info using `uname()` syscall, https://linux.die.net/man/2/uname
 	// Grab kernel info using `uname()` syscall, https://linux.die.net/man/2/uname
 	uts: linux.UTS_Name
 	uts: linux.UTS_Name
 	uname_errno := linux.uname(&uts)
 	uname_errno := linux.uname(&uts)
@@ -47,28 +51,36 @@ init_os_version :: proc () {
 	strings.write_string(&b, ", ")
 	strings.write_string(&b, ", ")
 	strings.write_string(&b, string(cstring(&uts.sysname[0])))
 	strings.write_string(&b, string(cstring(&uts.sysname[0])))
 	strings.write_rune(&b, ' ')
 	strings.write_rune(&b, ' ')
-	l := strings.builder_len(b)
+
+	release_i := strings.builder_len(b)
 	strings.write_string(&b, string(cstring(&uts.release[0])))
 	strings.write_string(&b, string(cstring(&uts.release[0])))
-	// Parse kernel version, as substrings of the version info in `version_string_buf`
-	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
-	version_bits := strings.split_n(strings.to_string(b)[l:], "-", 2, context.temp_allocator)
-	if len(version_bits) > 1 {
-		os_version.version = version_bits[1]
-	}
-	// Parse major, minor, patch from release info
-	triplet := strings.split(version_bits[0], ".", context.temp_allocator)
-	if len(triplet) == 3 {
-		major, major_ok := strconv.parse_int(triplet[0])
-		minor, minor_ok := strconv.parse_int(triplet[1])
-		patch, patch_ok := strconv.parse_int(triplet[2])
-		if major_ok && minor_ok && patch_ok {
-			os_version.major = major
-			os_version.minor = minor
-			os_version.patch = patch
+	release_str := string(b.buf[release_i:])
+
+	os_version.as_string = strings.to_string(b)
+
+	// Parse the Linux version out of the release string
+	{
+		version_num, _, version_suffix := strings.partition(release_str, "-")
+		os_version.version = version_suffix
+
+		i: int
+		for part in strings.split_iterator(&version_num, ".") {
+			defer i += 1
+
+			dst: ^int
+			switch i {
+			case 0: dst = &os_version.major
+			case 1: dst = &os_version.minor
+			case 2: dst = &os_version.patch
+			case:   break
+			}
+
+			num, ok := strconv.parse_int(part)
+			if !ok { break }
+
+			dst^ = num
 		}
 		}
 	}
 	}
-	// Finish the string
-	os_version.as_string = strings.to_string(b)
 }
 }
 
 
 @(init)
 @(init)
@@ -83,4 +95,4 @@ init_ram :: proc() {
 		total_swap = int(sys_info.totalswap) * int(sys_info.mem_unit),
 		total_swap = int(sys_info.totalswap) * int(sys_info.mem_unit),
 		free_swap  = int(sys_info.freeswap)  * int(sys_info.mem_unit),
 		free_swap  = int(sys_info.freeswap)  * int(sys_info.mem_unit),
 	}
 	}
-}
+}