Browse Source

improve error handling; do not report errors from failed execve

jason 1 year ago
parent
commit
a03dffcd1a
1 changed files with 39 additions and 17 deletions
  1. 39 17
      core/os/os2/process_linux.odin

+ 39 - 17
core/os/os2/process_linux.odin

@@ -63,7 +63,7 @@ _get_ppid :: proc() -> int {
 }
 
 @(private="package")
-_process_list :: proc(allocator: runtime.Allocator) -> ([]int, Error) {
+_process_list :: proc(allocator: runtime.Allocator) -> (list: []int, err: Error) {
 	TEMP_ALLOCATOR_GUARD()
 
 	dir_fd: linux.Fd
@@ -101,17 +101,21 @@ _process_list :: proc(allocator: runtime.Allocator) -> ([]int, Error) {
 
 			if pid, ok := strconv.parse_int(d_name_str); ok {
 				append(&dynamic_list, pid)
+			} else {
+				return nil, .Invalid_File
 			}
 		}
 	}
 
-	return slice.clone(dynamic_list[:], allocator), nil
+	list, err = slice.clone(dynamic_list[:], allocator)
+	return
 }
 
 @(private="package")
 _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) {
 	TEMP_ALLOCATOR_GUARD()
 
+	info.pid = pid
 	info.fields = selection
 
 	// Use this so we can use bprintf to make cstrings with less copying.
@@ -148,10 +152,15 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
 			passwd = passwd[strings.index_byte(passwd, ':') + 1:]
 
 			n = strings.index_byte(passwd, ':')
-			if uid, ok := strconv.parse_int(passwd[:n]); ok && uid == int(s.uid) {
-				info.username = strings.clone(username, allocator)
+			uid: int
+			ok: bool
+			if uid, ok = strconv.parse_int(passwd[:n]); ok && uid == int(s.uid) {
+				info.username = strings.clone(username, allocator) or_return
 				break
 			}
+			if !ok {
+				return info, .Invalid_File
+			}
 
 			eol := strings.index_byte(passwd, '\n')
 			if eol == -1 {
@@ -184,30 +193,31 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
 
 			cwd, cwd_err = _read_link_cstr(path_cstr, temp_allocator()) // allowed to fail
 			if cwd_err == nil && .Working_Dir in selection {
-				info.working_dir = strings.clone(cwd, allocator)
+				info.working_dir = strings.clone(cwd, allocator) or_return
 			}
 		}
 
 		if .Executable_Path in selection {
 			if cmdline[0] == '/' {
-				info.executable_path = strings.clone(cmdline[:terminator], allocator)
+				info.executable_path = strings.clone(cmdline[:terminator], allocator) or_return
 			} else if cwd_err == nil {
 				join_paths: [2]string = { cwd, cmdline[:terminator] }
 				info.executable_path = filepath.join(join_paths[:], allocator)
 			}
 		}
 		if .Command_Line in selection {
-			info.command_line = strings.clone(cmdline[:terminator], allocator)
+			info.command_line = strings.clone(cmdline[:terminator], allocator) or_return
 		}
 
 		if .Command_Args in selection {
 			// skip to first arg
 			cmdline = cmdline[terminator + 1:]
 
-			arg_list := make([dynamic]string, allocator)
+			arg_list := make([dynamic]string, allocator) or_return
 			for len(cmdline) > 0 {
 				terminator = strings.index_byte(cmdline, 0)
-				append(&arg_list, strings.clone(cmdline[:terminator], allocator))
+				arg := strings.clone(cmdline[:terminator], allocator) or_return
+				append(&arg_list, arg) or_return
 				cmdline = cmdline[terminator + 1:]
 			}
 			info.command_args = arg_list[:]
@@ -230,9 +240,11 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
 		stats = stats[strings.index_byte(stats, ' ') + 1:]
 
 		if .PPid in selection {
-			ppid_str := stats[strings.index_byte(stats, ' '):]
+			ppid_str := stats[:strings.index_byte(stats, ' ')]
 			if ppid, ok := strconv.parse_int(ppid_str); ok {
 				info.ppid = ppid
+			} else {
+				return info, .Invalid_File
 			}
 		}
 
@@ -241,9 +253,11 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
 			for _ in 4..<19 {
 				stats = stats[strings.index_byte(stats, ' ') + 1:]
 			}
-			nice_str := stats[strings.index_byte(stats, ' '):]
+			nice_str := stats[:strings.index_byte(stats, ' ')]
 			if nice, ok := strconv.parse_int(nice_str); ok {
 				info.priority = nice
+			} else {
+				return info, .Invalid_File
 			}
 		}
 	}
@@ -255,13 +269,14 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
 		if env_bytes, env_err := _read_entire_pseudo_file(path_cstr, temp_allocator()); env_err == nil {
 			env := string(env_bytes)
 
-			env_list := make([dynamic]string, allocator)
+			env_list := make([dynamic]string, allocator) or_return
 			for len(env) > 0 {
 				terminator := strings.index_byte(env, 0)
 				if terminator == -1 || terminator == 0 {
 					break
 				}
-				append(&env_list, strings.clone(env[:terminator], allocator))
+				e := strings.clone(env[:terminator], allocator) or_return
+				append(&env_list, e) or_return
 				env = env[terminator + 1:]
 			}
 			info.environment = env_list[:]
@@ -417,12 +432,13 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
 		}
 
 		if errno = linux.execveat(dir_fd, executable_path, &cargs[0], env); errno != .NONE {
-			print_error(stderr, _get_platform_error(errno), string(executable_path))
-			panic("execve failed to replace process")
+			linux.exit(1)
 		}
 		unreachable()
 	}
 
+	// TODO: We need to come up with a way to detect the execve failure from here.
+
 	process.pid = int(pid)
 	process.handle = PIDFD_UNASSIGNED
 	return
@@ -455,8 +471,14 @@ _process_state_update_times :: proc(p: Process, state: ^Process_State) -> (err:
 	stats = stats[idx + 1:]
 	stime_str := stats[:strings.index_byte(stats, ' ')]
 
-	utime, _ := strconv.parse_int(utime_str, 10)
-	stime, _ := strconv.parse_int(stime_str, 10)
+	utime, stime: int
+	ok: bool
+	if utime, ok = strconv.parse_int(utime_str, 10); !ok {
+		return .Invalid_File
+	}
+	if stime, ok = strconv.parse_int(stime_str, 10); !ok {
+		return .Invalid_File
+	}
 
 	// NOTE: Assuming HZ of 100, 1 jiffy == 10 ms
 	state.user_time = time.Duration(utime) * 10 * time.Millisecond