Remove returned bool from access and faccessat in sys/linux.

Switch to using AT_EMPTY_PATH to execve with file descriptors.
This commit is contained in:
jason
2024-08-04 00:59:40 -04:00
parent 2b89829b52
commit 2a7db08c20
3 changed files with 45 additions and 24 deletions
+1 -2
View File
@@ -386,8 +386,7 @@ _fchtimes :: proc(f: ^File, atime, mtime: time.Time) -> Error {
_exists :: proc(name: string) -> bool {
TEMP_ALLOCATOR_GUARD()
name_cstr, _ := temp_cstring(name)
res, errno := linux.access(name_cstr, linux.F_OK)
return !res && errno == .NONE
return linux.access(name_cstr, linux.F_OK) == .NONE
}
/* For reading Linux system files that stat to size 0 */
+37 -15
View File
@@ -300,6 +300,12 @@ _Sys_Process_Attributes :: struct {}
@(private="package")
_process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
_has_executable_permissions :: proc(fd: linux.Fd) -> bool {
backing: [48]u8
_ = fmt.bprintf(backing[:], "/proc/self/fd/%d", fd)
return linux.access(cstring(&backing[0]), linux.X_OK) == .NONE
}
TEMP_ALLOCATOR_GUARD()
if len(desc.command) == 0 {
@@ -314,38 +320,54 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
return process, _get_platform_error(errno)
}
}
defer if desc.working_dir != "" {
linux.close(dir_fd)
}
// search PATH if just a plain name is provided
exe_fd: linux.Fd
executable_name := desc.command[0]
executable_path: cstring
if strings.index_byte(executable_name, '/') == -1 {
path_env := get_env("PATH", temp_allocator())
path_dirs := filepath.split_list(path_env, temp_allocator())
found: bool
for dir in path_dirs {
executable_path = fmt.caprintf("%s/%s", dir, executable_name, temp_allocator())
fail: bool
if fail, errno = linux.faccessat(dir_fd, executable_path, linux.F_OK); errno == .NONE && !fail {
found = true
break
exe_path := fmt.caprintf("%s/%s", dir, executable_name, allocator=temp_allocator())
if exe_fd, errno = linux.openat(dir_fd, exe_path, {.PATH, .CLOEXEC}); errno != .NONE {
continue
}
if !_has_executable_permissions(exe_fd) {
linux.close(exe_fd)
continue
}
found = true
break
}
if !found {
// check in cwd to match windows behavior
executable_path = fmt.caprintf("./%s", name, temp_allocator())
fail: bool
if fail, errno = linux.faccessat(dir_fd, executable_path, linux.F_OK); errno != .NONE || fail {
exe_path := fmt.caprintf("./%s", executable_name, allocator=temp_allocator())
if exe_fd, errno = linux.openat(dir_fd, exe_path, {.PATH, .CLOEXEC}); errno != .NONE {
return process, .Not_Exist
}
if !_has_executable_permissions(exe_fd) {
linux.close(exe_fd)
return process, .Permission_Denied
}
}
} else {
executable_path = temp_cstring(executable_name) or_return
exe_path := temp_cstring(executable_name) or_return
if exe_fd, errno = linux.openat(dir_fd, exe_path, {.PATH, .CLOEXEC}); errno != .NONE {
return process, _get_platform_error(errno)
}
if !_has_executable_permissions(exe_fd) {
linux.close(exe_fd)
return process, .Permission_Denied
}
}
not_exec: bool
if not_exec, errno = linux.faccessat(dir_fd, executable_path, linux.F_OK | linux.X_OK); errno != .NONE || not_exec {
return process, errno == .NONE ? .Permission_Denied : _get_platform_error(errno)
}
// At this point, we have an executable.
defer linux.close(exe_fd)
// args and environment need to be a list of cstrings
// that are terminated by a nil pointer.
@@ -409,7 +431,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
}
}
if errno = linux.execveat(dir_fd, executable_path, &cargs[0], env); errno != .NONE {
if errno = linux.execveat(exe_fd, "", &cargs[0], env, {.AT_EMPTY_PATH}); errno != .NONE {
intrinsics.trap()
}
unreachable()
+7 -7
View File
@@ -279,13 +279,13 @@ writev :: proc "contextless" (fd: Fd, iov: []IO_Vec) -> (int, Errno) {
Available since Linux 1.0.
For ARM64 available since Linux 2.6.16.
*/
access :: proc "contextless" (name: cstring, mode: Mode = F_OK) -> (bool, Errno) {
access :: proc "contextless" (name: cstring, mode: Mode = F_OK) -> (Errno) {
when ODIN_ARCH == .arm64 {
ret := syscall(SYS_faccessat, AT_FDCWD, cast(rawptr) name, transmute(u32) mode)
return errno_unwrap(ret, bool)
return Errno(-ret)
} else {
ret := syscall(SYS_access, cast(rawptr) name, transmute(u32) mode)
return errno_unwrap(ret, bool)
return Errno(-ret)
}
}
@@ -2616,9 +2616,9 @@ fchmodat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode, flags: FD_
Checks the user permissions for a file at specified dirfd.
Available since Linux 2.6.16.
*/
faccessat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode = F_OK) -> (bool, Errno) {
faccessat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode = F_OK) -> (Errno) {
ret := syscall(SYS_faccessat, dirfd, cast(rawptr) name, transmute(u32) mode)
return errno_unwrap(ret, bool)
return Errno(-ret)
}
/*
@@ -2916,9 +2916,9 @@ pidfd_getfd :: proc "contextless" (pidfd: Pid_FD, fd: Fd, flags: i32 = 0) -> (Fd
Checks the user permissions for a file at specified dirfd (with flags).
Available since Linux 5.8.
*/
faccessat2 :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode = F_OK, flags: FD_Flags = FD_Flags{}) -> (bool, Errno) {
faccessat2 :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode = F_OK, flags: FD_Flags = FD_Flags{}) -> (Errno) {
ret := syscall(SYS_faccessat2, dirfd, cast(rawptr) name, transmute(u32) mode, transmute(i32) flags)
return errno_unwrap(ret, bool)
return Errno(-ret)
}
// TODO(flysand): process_madvise