improve error handling; do not report errors from failed execve

This commit is contained in:
jason
2024-07-30 08:45:53 -04:00
parent a5fa93e06d
commit a03dffcd1a

View File

@@ -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