From a03dffcd1aab0f13c538620ac3006953bbd2372e Mon Sep 17 00:00:00 2001 From: jason Date: Tue, 30 Jul 2024 08:45:53 -0400 Subject: [PATCH] improve error handling; do not report errors from failed execve --- core/os/os2/process_linux.odin | 56 +++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/core/os/os2/process_linux.odin b/core/os/os2/process_linux.odin index 7458d06d6..0879f9b16 100644 --- a/core/os/os2/process_linux.odin +++ b/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