diff --git a/Cargo.lock b/Cargo.lock
index 89e454e4a09de190a494ff1c0e459257fe128444..2dbd6be7ed231ce015de7444913b34acc02d218d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
 
 [[package]]
 name = "autocfg"
-version = "1.1.0"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
 
 [[package]]
 name = "base64ct"
@@ -27,9 +27,9 @@ dependencies = [
 
 [[package]]
 name = "bitflags"
-version = "2.4.2"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
+checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
 
 [[package]]
 name = "block-buffer"
@@ -67,9 +67,9 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.0.90"
+version = "1.0.99"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
+checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695"
 
 [[package]]
 name = "cfg-if"
@@ -178,15 +178,15 @@ version = "0.1.0"
 
 [[package]]
 name = "libc"
-version = "0.2.153"
+version = "0.2.155"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
+checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
 
 [[package]]
 name = "libredox"
-version = "0.1.2"
+version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "309ba69985d5170852ebbe8fbb33850d20794d0aed5b210dfea2db798df64e10"
+checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
 dependencies = [
  "bitflags",
  "libc",
@@ -210,24 +210,24 @@ dependencies = [
 
 [[package]]
 name = "memchr"
-version = "2.7.1"
+version = "2.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 
 [[package]]
 name = "memoffset"
-version = "0.9.0"
+version = "0.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
+checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
 dependencies = [
  "autocfg",
 ]
 
 [[package]]
 name = "num-traits"
-version = "0.2.18"
+version = "0.2.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
 dependencies = [
  "autocfg",
 ]
@@ -272,18 +272,18 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.79"
+version = "1.0.85"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
+checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.35"
+version = "1.0.36"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
 dependencies = [
  "proc-macro2",
 ]
@@ -378,7 +378,7 @@ checksum = "64072665120942deff5fd5425d6c1811b854f4939e7f1c01ce755f64432bbea7"
 [[package]]
 name = "redox_event"
 version = "0.4.0"
-source = "git+https://gitlab.redox-os.org/redox-os/event.git#269452fca1655396536f38eba0f860c77e11cb92"
+source = "git+https://gitlab.redox-os.org/redox-os/event.git#36ac5a57a8573f7546d7dc0893596ebe99bd2b7f"
 dependencies = [
  "bitflags",
  "libredox",
@@ -387,9 +387,9 @@ dependencies = [
 
 [[package]]
 name = "redox_syscall"
-version = "0.5.1"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e"
+checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd"
 dependencies = [
  "bitflags",
 ]
@@ -502,9 +502,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
 
 [[package]]
 name = "syn"
-version = "2.0.53"
+version = "2.0.66"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032"
+checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -525,9 +525,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
 
 [[package]]
 name = "unicode-width"
-version = "0.1.11"
+version = "0.1.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
+checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
 
 [[package]]
 name = "version_check"
diff --git a/src/fs.rs b/src/fs.rs
index 37ad5174fb90f5b3ecc502fa924c48724d140967..dcf77e2f13779df0b45438519875eb7b271d711b 100644
--- a/src/fs.rs
+++ b/src/fs.rs
@@ -6,6 +6,7 @@ use crate::{
     },
     io,
     platform::{types::*, Pal, Sys},
+    pthread::ResultExt,
 };
 use core::ops::Deref;
 
@@ -72,7 +73,7 @@ impl File {
 
 impl io::Read for &File {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
-        match Sys::read(self.fd, buf) {
+        match Sys::read(self.fd, buf).or_minus_one_errno() /* TODO */ {
             -1 => Err(io::last_os_error()),
             ok => Ok(ok as usize),
         }
@@ -81,7 +82,7 @@ impl io::Read for &File {
 
 impl io::Write for &File {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        match Sys::write(self.fd, buf) {
+        match Sys::write(self.fd, buf).or_minus_one_errno() {
             -1 => Err(io::last_os_error()),
             ok => Ok(ok as usize),
         }
diff --git a/src/header/unistd/mod.rs b/src/header/unistd/mod.rs
index ee9e87bfc11628dbc724ce3bfe74a68ab67904b6..4ac3347f1880cd8d0384312971f3737f5ef114cf 100644
--- a/src/header/unistd/mod.rs
+++ b/src/header/unistd/mod.rs
@@ -17,6 +17,7 @@ use crate::{
         time::timespec,
     },
     platform::{self, types::*, Pal, Sys},
+    pthread::ResultExt,
 };
 use alloc::collections::LinkedList;
 
@@ -577,24 +578,18 @@ pub unsafe extern "C" fn pipe2(fildes: *mut c_int, flags: c_int) -> c_int {
 }
 
 #[no_mangle]
-pub extern "C" fn pread(fildes: c_int, buf: *mut c_void, nbyte: size_t, offset: off_t) -> ssize_t {
-    //TODO: better pread using system calls
-
-    let previous = lseek(fildes, offset, SEEK_SET);
-    if previous == -1 {
-        return -1;
-    }
-
-    let res = read(fildes, buf, nbyte);
-    if res < 0 {
-        return res;
-    }
-
-    if lseek(fildes, previous, SEEK_SET) == -1 {
-        return -1;
-    }
-
-    res
+pub unsafe extern "C" fn pread(
+    fildes: c_int,
+    buf: *mut c_void,
+    nbyte: size_t,
+    offset: off_t,
+) -> ssize_t {
+    Sys::pread(
+        fildes,
+        slice::from_raw_parts_mut(buf.cast::<u8>(), nbyte),
+        offset,
+    )
+    .or_minus_one_errno()
 }
 
 #[no_mangle]
@@ -617,36 +612,25 @@ pub extern "C" fn pthread_atfork(
 }
 
 #[no_mangle]
-pub extern "C" fn pwrite(
+pub unsafe extern "C" fn pwrite(
     fildes: c_int,
     buf: *const c_void,
     nbyte: size_t,
     offset: off_t,
 ) -> ssize_t {
-    //TODO: better pwrite using system calls
-
-    let previous = lseek(fildes, offset, SEEK_SET);
-    if previous == -1 {
-        return -1;
-    }
-
-    let res = write(fildes, buf, nbyte);
-    if res < 0 {
-        return res;
-    }
-
-    if lseek(fildes, previous, SEEK_SET) == -1 {
-        return -1;
-    }
-
-    res
+    Sys::pwrite(
+        fildes,
+        slice::from_raw_parts(buf.cast::<u8>(), nbyte),
+        offset,
+    )
+    .or_minus_one_errno()
 }
 
 #[no_mangle]
-pub extern "C" fn read(fildes: c_int, buf: *const c_void, nbyte: size_t) -> ssize_t {
+pub unsafe extern "C" fn read(fildes: c_int, buf: *const c_void, nbyte: size_t) -> ssize_t {
     let buf = unsafe { slice::from_raw_parts_mut(buf as *mut u8, nbyte as usize) };
     trace_expr!(
-        Sys::read(fildes, buf),
+        Sys::read(fildes, buf).or_minus_one_errno(),
         "read({}, {:p}, {})",
         fildes,
         buf,
@@ -853,7 +837,7 @@ pub extern "C" fn vfork() -> pid_t {
 }
 
 #[no_mangle]
-pub extern "C" fn write(fildes: c_int, buf: *const c_void, nbyte: size_t) -> ssize_t {
-    let buf = unsafe { slice::from_raw_parts(buf as *const u8, nbyte as usize) };
-    Sys::write(fildes, buf)
+pub unsafe extern "C" fn write(fildes: c_int, buf: *const c_void, nbyte: size_t) -> ssize_t {
+    let buf = slice::from_raw_parts(buf as *const u8, nbyte as usize);
+    Sys::write(fildes, buf).or_minus_one_errno()
 }
diff --git a/src/ld_so/tcb.rs b/src/ld_so/tcb.rs
index 4bf0c627bf0e9a371ab708a66d87f84eea7aefad..fd3ac90bb27913b580339dd57476e3595327978a 100644
--- a/src/ld_so/tcb.rs
+++ b/src/ld_so/tcb.rs
@@ -4,7 +4,11 @@ use goblin::error::{Error, Result};
 
 use super::ExpectTlsFree;
 use crate::{
-    header::sys_mman, ld_so::linker::Linker, platform::{Dlmalloc, Pal, Sys}, pthread::{OsTid, Pthread}, sync::{mutex::Mutex, waitval::Waitval}
+    header::sys_mman,
+    ld_so::linker::Linker,
+    platform::{Dlmalloc, Pal, Sys},
+    pthread::{OsTid, Pthread},
+    sync::{mutex::Mutex, waitval::Waitval},
 };
 
 #[repr(C)]
diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs
index 2a82ffff21537aaa2d2d09eb2cd7b7896da18ef5..71f3ba0ce396794292b0db2df5a24d68f8b86258 100644
--- a/src/platform/linux/mod.rs
+++ b/src/platform/linux/mod.rs
@@ -14,7 +14,10 @@ use crate::header::{
     sys_time::{timeval, timezone},
 };
 // use header::sys_times::tms;
-use crate::header::{sys_utsname::utsname, time::timespec};
+use crate::{
+    header::{sys_utsname::utsname, time::timespec},
+    pthread::Errno,
+};
 
 mod epoll;
 mod ptrace;
@@ -52,9 +55,9 @@ struct linux_statfs {
 // TODO
 const ERRNO_MAX: usize = 4095;
 
-pub fn e_raw(sys: usize) -> Result<usize, usize> {
+pub fn e_raw(sys: usize) -> Result<usize, Errno> {
     if sys > ERRNO_MAX.wrapping_neg() {
-        Err(sys.wrapping_neg())
+        Err(Errno(sys.wrapping_neg() as _))
     } else {
         Ok(sys)
     }
@@ -62,7 +65,7 @@ pub fn e_raw(sys: usize) -> Result<usize, usize> {
 pub fn e(sys: usize) -> usize {
     match e_raw(sys) {
         Ok(value) => value,
-        Err(errcode) => {
+        Err(Errno(errcode)) => {
             ERRNO.set(errcode as c_int);
             !0
         }
@@ -251,15 +254,13 @@ impl Pal for Sys {
                 0xffffffff  // val3: FUTEX_BITSET_MATCH_ANY
             )
         })
-        .map_err(|e| crate::pthread::Errno(e as c_int))
         .map(|_| ())
     }
     #[inline]
-    unsafe fn futex_wake(addr: *mut u32, num: u32) -> Result<c_int, crate::pthread::Errno> {
+    unsafe fn futex_wake(addr: *mut u32, num: u32) -> Result<c_int, Errno> {
         e_raw(unsafe {
             syscall!(FUTEX, addr, 1 /* FUTEX_WAKE */, num)
         })
-        .map_err(|e| crate::pthread::Errno(e as c_int))
         .map(|n| n as c_int)
     }
 
@@ -457,9 +458,7 @@ impl Pal for Sys {
     }
 
     #[cfg(target_arch = "x86_64")]
-    unsafe fn rlct_clone(
-        stack: *mut usize,
-    ) -> Result<crate::pthread::OsTid, crate::pthread::Errno> {
+    unsafe fn rlct_clone(stack: *mut usize) -> Result<crate::pthread::OsTid, Errno> {
         let flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD;
         let pid;
         asm!("
@@ -508,18 +507,13 @@ impl Pal for Sys {
             out("r14") _,
             out("r15") _,
         );
-        let tid = e_raw(pid).map_err(|err| crate::pthread::Errno(err as c_int))?;
+        let tid = e_raw(pid)?;
 
         Ok(crate::pthread::OsTid { thread_id: tid })
     }
-    unsafe fn rlct_kill(
-        os_tid: crate::pthread::OsTid,
-        signal: usize,
-    ) -> Result<(), crate::pthread::Errno> {
+    unsafe fn rlct_kill(os_tid: crate::pthread::OsTid, signal: usize) -> Result<(), Errno> {
         let tgid = Self::getpid();
-        e_raw(unsafe { syscall!(TGKILL, tgid, os_tid.thread_id, signal) })
-            .map(|_| ())
-            .map_err(|err| crate::pthread::Errno(err as c_int))
+        e_raw(unsafe { syscall!(TGKILL, tgid, os_tid.thread_id, signal) }).map(|_| ())
     }
     fn current_os_tid() -> crate::pthread::OsTid {
         crate::pthread::OsTid {
@@ -527,8 +521,14 @@ impl Pal for Sys {
         }
     }
 
-    fn read(fildes: c_int, buf: &mut [u8]) -> ssize_t {
-        e(unsafe { syscall!(READ, fildes, buf.as_mut_ptr(), buf.len()) }) as ssize_t
+    fn read(fildes: c_int, buf: &mut [u8]) -> Result<ssize_t, Errno> {
+        Ok(e_raw(unsafe { syscall!(READ, fildes, buf.as_mut_ptr(), buf.len()) })? as ssize_t)
+    }
+    fn pread(fildes: c_int, buf: &mut [u8], off: off_t) -> Result<ssize_t, Errno> {
+        Ok(
+            e_raw(unsafe { syscall!(PREAD64, fildes, buf.as_mut_ptr(), buf.len(), off) })?
+                as ssize_t,
+        )
     }
 
     fn readlink(pathname: CStr, out: &mut [u8]) -> ssize_t {
@@ -603,8 +603,11 @@ impl Pal for Sys {
         e(unsafe { syscall!(WAIT4, pid, stat_loc, options, 0) }) as pid_t
     }
 
-    fn write(fildes: c_int, buf: &[u8]) -> ssize_t {
-        e(unsafe { syscall!(WRITE, fildes, buf.as_ptr(), buf.len()) }) as ssize_t
+    fn write(fildes: c_int, buf: &[u8]) -> Result<ssize_t, Errno> {
+        Ok(e_raw(unsafe { syscall!(WRITE, fildes, buf.as_ptr(), buf.len()) })? as ssize_t)
+    }
+    fn pwrite(fildes: c_int, buf: &[u8], off: off_t) -> Result<ssize_t, Errno> {
+        Ok(e_raw(unsafe { syscall!(PWRITE64, fildes, buf.as_ptr(), buf.len(), off) })? as ssize_t)
     }
 
     fn verify() -> bool {
diff --git a/src/platform/mod.rs b/src/platform/mod.rs
index f506742940a8980224a85361a65a9db1d32a7b21..9a5fbaa01e45ac47e4006b8c37397eed251162eb 100644
--- a/src/platform/mod.rs
+++ b/src/platform/mod.rs
@@ -1,4 +1,7 @@
-use crate::io::{self, Read, Write};
+use crate::{
+    io::{self, Read, Write},
+    pthread::ResultExt,
+};
 use alloc::{boxed::Box, vec::Vec};
 use core::{cell::Cell, fmt, ptr};
 
@@ -83,7 +86,7 @@ pub struct FileWriter(pub c_int);
 
 impl FileWriter {
     pub fn write(&mut self, buf: &[u8]) -> isize {
-        Sys::write(self.0, buf)
+        Sys::write(self.0, buf).or_minus_one_errno()
     }
 }
 
@@ -105,13 +108,13 @@ pub struct FileReader(pub c_int);
 
 impl FileReader {
     pub fn read(&mut self, buf: &mut [u8]) -> isize {
-        Sys::read(self.0, buf)
+        Sys::read(self.0, buf).or_minus_one_errno()
     }
 }
 
 impl Read for FileReader {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
-        let i = Sys::read(self.0, buf);
+        let i = Sys::read(self.0, buf).or_minus_one_errno(); // TODO
         if i >= 0 {
             Ok(i as usize)
         } else {
diff --git a/src/platform/pal/mod.rs b/src/platform/pal/mod.rs
index e8a6b21fd2bd5bb0349796aedfd3b2e953ef11e8..ea226f7ad9ff027ed4741aa92886466384b5393b 100644
--- a/src/platform/pal/mod.rs
+++ b/src/platform/pal/mod.rs
@@ -10,7 +10,7 @@ use crate::{
         sys_utsname::utsname,
         time::timespec,
     },
-    pthread,
+    pthread::{self, Errno},
 };
 
 pub use self::epoll::PalEpoll;
@@ -190,7 +190,8 @@ pub trait Pal {
     ) -> Result<(), crate::pthread::Errno>;
     fn current_os_tid() -> crate::pthread::OsTid;
 
-    fn read(fildes: c_int, buf: &mut [u8]) -> ssize_t;
+    fn read(fildes: c_int, buf: &mut [u8]) -> Result<ssize_t, Errno>;
+    fn pread(fildes: c_int, buf: &mut [u8], offset: off_t) -> Result<ssize_t, Errno>;
 
     fn readlink(pathname: CStr, out: &mut [u8]) -> ssize_t;
 
@@ -224,7 +225,8 @@ pub trait Pal {
 
     fn waitpid(pid: pid_t, stat_loc: *mut c_int, options: c_int) -> pid_t;
 
-    fn write(fildes: c_int, buf: &[u8]) -> ssize_t;
+    fn write(fildes: c_int, buf: &[u8]) -> Result<ssize_t, Errno>;
+    fn pwrite(fildes: c_int, buf: &[u8], offset: off_t) -> Result<ssize_t, Errno>;
 
     fn verify() -> bool;
 }
diff --git a/src/platform/redox/epoll.rs b/src/platform/redox/epoll.rs
index 7303054396d5800c9d2207d46f8a0c8136519753..87fd12801831dc5c6cb9a0edcd2431f619dfbc0b 100644
--- a/src/platform/redox/epoll.rs
+++ b/src/platform/redox/epoll.rs
@@ -8,6 +8,7 @@ use crate::{
     header::{errno::*, fcntl::*, signal::sigset_t, sys_epoll::*},
     io::prelude::*,
     platform,
+    pthread::ResultExt,
 };
 use core::{mem, slice};
 use syscall::{
@@ -67,7 +68,9 @@ impl PalEpoll for Sys {
                         // systems. If this is needed, use a box or something
                         data: unsafe { (*event).data.u64 as usize },
                     },
-                ) < 0
+                )
+                .or_minus_one_errno()
+                    < 0
                 {
                     -1
                 } else {
@@ -83,7 +86,9 @@ impl PalEpoll for Sys {
                         //TODO: Is data required?
                         data: 0,
                     },
-                ) < 0
+                )
+                .or_minus_one_errno()
+                    < 0
                 {
                     -1
                 } else {
@@ -123,7 +128,9 @@ impl PalEpoll for Sys {
                             flags: EVENT_READ,
                             data: 0,
                         },
-                    ) == -1
+                    )
+                    .or_minus_one_errno()
+                        == -1
                     {
                         return -1;
                     }
@@ -150,7 +157,8 @@ impl PalEpoll for Sys {
                 events as *mut u8,
                 maxevents as usize * mem::size_of::<syscall::Event>(),
             )
-        });
+        })
+        .or_minus_one_errno(); // TODO
         if bytes_read == -1 {
             return -1;
         }
diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs
index 69001a0dbf47754d2eb5849cc3bcb294b34a4f98..079031c28be96930eb1271699c8c2b6533de01bd 100644
--- a/src/platform/redox/mod.rs
+++ b/src/platform/redox/mod.rs
@@ -24,7 +24,7 @@ use crate::{
         unistd::{F_OK, R_OK, W_OK, X_OK},
     },
     io::{self, prelude::*, BufReader},
-    pthread,
+    pthread::{self, Errno, ResultExt},
 };
 
 pub use redox_exec::FdGuard;
@@ -823,8 +823,20 @@ impl Pal for Sys {
         }
     }
 
-    fn read(fd: c_int, buf: &mut [u8]) -> ssize_t {
-        e(syscall::read(fd as usize, buf)) as ssize_t
+    fn read(fd: c_int, buf: &mut [u8]) -> Result<ssize_t, Errno> {
+        Ok(syscall::read(fd as usize, buf)? as ssize_t)
+    }
+    fn pread(fd: c_int, buf: &mut [u8], offset: off_t) -> Result<ssize_t, Errno> {
+        unsafe {
+            Ok(syscall::syscall5(
+                syscall::SYS_READ2,
+                fd as usize,
+                buf.as_mut_ptr() as usize,
+                buf.len(),
+                offset as usize,
+                !0,
+            )? as ssize_t)
+        }
     }
 
     fn fpath(fildes: c_int, out: &mut [u8]) -> ssize_t {
@@ -870,7 +882,7 @@ impl Pal for Sys {
             pathname,
             fcntl::O_RDONLY | fcntl::O_SYMLINK | fcntl::O_CLOEXEC,
         ) {
-            Ok(file) => Self::read(*file, out),
+            Ok(file) => Self::read(*file, out).or_minus_one_errno(),
             Err(_) => return -1,
         }
     }
@@ -1111,8 +1123,20 @@ impl Pal for Sys {
         res as pid_t
     }
 
-    fn write(fd: c_int, buf: &[u8]) -> ssize_t {
-        e(syscall::write(fd as usize, buf)) as ssize_t
+    fn write(fd: c_int, buf: &[u8]) -> Result<ssize_t, Errno> {
+        Ok(syscall::write(fd as usize, buf)? as ssize_t)
+    }
+    fn pwrite(fd: c_int, buf: &[u8], offset: off_t) -> Result<ssize_t, Errno> {
+        unsafe {
+            Ok(syscall::syscall5(
+                syscall::SYS_WRITE2,
+                fd as usize,
+                buf.as_ptr() as usize,
+                buf.len(),
+                offset as usize,
+                !0,
+            )? as ssize_t)
+        }
     }
 
     fn verify() -> bool {
diff --git a/src/platform/redox/socket.rs b/src/platform/redox/socket.rs
index f01b6e9626a087f6f1151fb9d729c15d2f969f86..9c860537cd681518413e0aec1838f9dfb8880f60 100644
--- a/src/platform/redox/socket.rs
+++ b/src/platform/redox/socket.rs
@@ -6,13 +6,16 @@ use super::{
     super::{types::*, Pal, PalSocket, ERRNO},
     e, Sys,
 };
-use crate::header::{
-    arpa_inet::inet_aton,
-    netinet_in::{in_addr, in_port_t, sockaddr_in},
-    string::strnlen,
-    sys_socket::{constants::*, msghdr, sa_family_t, sockaddr, socklen_t},
-    sys_time::timeval,
-    sys_un::sockaddr_un,
+use crate::{
+    header::{
+        arpa_inet::inet_aton,
+        netinet_in::{in_addr, in_port_t, sockaddr_in},
+        string::strnlen,
+        sys_socket::{constants::*, msghdr, sa_family_t, sockaddr, socklen_t},
+        sys_time::timeval,
+        sys_un::sockaddr_un,
+    },
+    pthread::ResultExt,
 };
 
 macro_rules! bind_or_connect {
@@ -299,7 +302,7 @@ impl PalSocket for Sys {
             return -1;
         }
         if address == ptr::null_mut() || address_len == ptr::null_mut() {
-            Self::read(socket, slice::from_raw_parts_mut(buf as *mut u8, len))
+            Self::read(socket, slice::from_raw_parts_mut(buf as *mut u8, len)).or_minus_one_errno()
         } else {
             let fd = e(syscall::dup(socket as usize, b"listen"));
             if fd == !0 {
@@ -310,7 +313,8 @@ impl PalSocket for Sys {
                 return -1;
             }
 
-            let ret = Self::read(fd as c_int, slice::from_raw_parts_mut(buf as *mut u8, len));
+            let ret = Self::read(fd as c_int, slice::from_raw_parts_mut(buf as *mut u8, len))
+                .or_minus_one_errno();
             let _ = syscall::close(fd);
             ret
         }
@@ -343,10 +347,11 @@ impl PalSocket for Sys {
             return -1;
         }
         if dest_addr == ptr::null() || dest_len == 0 {
-            Self::write(socket, slice::from_raw_parts(buf as *const u8, len))
+            Self::write(socket, slice::from_raw_parts(buf as *const u8, len)).or_minus_one_errno()
         } else {
             let fd = bind_or_connect!(connect copy, socket, dest_addr, dest_len);
-            let ret = Self::write(fd as c_int, slice::from_raw_parts(buf as *const u8, len));
+            let ret = Self::write(fd as c_int, slice::from_raw_parts(buf as *const u8, len))
+                .or_minus_one_errno();
             let _ = syscall::close(fd);
             ret
         }
@@ -380,7 +385,7 @@ impl PalSocket for Sys {
                 tv_nsec: timeval.tv_usec * 1000,
             };
 
-            let ret = Self::write(fd as c_int, &timespec);
+            let ret = Self::write(fd as c_int, &timespec).or_minus_one_errno();
 
             let _ = syscall::close(fd);
 
diff --git a/src/platform/rlb.rs b/src/platform/rlb.rs
index c71426a2134ca22c62e6212c244c8c446316f0e6..e9beaea52261911ec5302cbfb7585b1700d80f46 100644
--- a/src/platform/rlb.rs
+++ b/src/platform/rlb.rs
@@ -2,7 +2,10 @@ use alloc::vec::Vec;
 
 use crate::platform::{types::*, Pal, Sys};
 
-use crate::header::unistd::{lseek, SEEK_SET};
+use crate::{
+    header::unistd::{lseek, SEEK_SET},
+    pthread::ResultExt,
+};
 /// Implements an `Iterator` which returns on either newline or EOF.
 #[derive(Clone)]
 pub struct RawLineBuffer {
@@ -58,7 +61,7 @@ impl RawLineBuffer {
                 self.buf.set_len(capacity);
             }
 
-            let read = Sys::read(self.fd, &mut self.buf[len..]);
+            let read = Sys::read(self.fd, &mut self.buf[len..]).or_minus_one_errno();
 
             let read_usize = read.max(0) as usize;
 
diff --git a/src/pthread/mod.rs b/src/pthread/mod.rs
index 1da4bd3348e2dd5109b847ea2d2d8e1acd773d52..37402d45136d4d1eca44100e661ee2dab0d69f2e 100644
--- a/src/pthread/mod.rs
+++ b/src/pthread/mod.rs
@@ -12,7 +12,8 @@ use crate::{
     header::{errno::*, pthread as header, sched::sched_param, sys_mman},
     ld_so::{
         linker::Linker,
-        tcb::{Master, Tcb}, ExpectTlsFree,
+        tcb::{Master, Tcb},
+        ExpectTlsFree,
     },
     platform::{types::*, Pal, Sys},
 };
@@ -23,7 +24,9 @@ const MAIN_PTHREAD_ID: usize = 1;
 
 /// Called only by the main thread, as part of relibc_start.
 pub unsafe fn init() {
-    Tcb::current().expect_notls("no TCB present for main thread").pthread = Pthread {
+    Tcb::current()
+        .expect_notls("no TCB present for main thread")
+        .pthread = Pthread {
         waitval: Waitval::new(),
         has_enabled_cancelation: AtomicBool::new(false),
         has_queued_cancelation: AtomicBool::new(false),
@@ -83,6 +86,28 @@ unsafe impl Sync for Pthread {}
 // TODO: Move to a more generic place.
 pub struct Errno(pub c_int);
 
+#[cfg(target_os = "redox")]
+impl From<syscall::Error> for Errno {
+    fn from(value: syscall::Error) -> Self {
+        Errno(value.errno)
+    }
+}
+
+pub trait ResultExt<T> {
+    fn or_minus_one_errno(self) -> T;
+}
+impl<T: From<i8>> ResultExt<T> for Result<T, Errno> {
+    fn or_minus_one_errno(self) -> T {
+        match self {
+            Self::Ok(v) => v,
+            Self::Err(Errno(errno)) => unsafe {
+                crate::platform::ERRNO.set(errno);
+                T::from(-1)
+            },
+        }
+    }
+}
+
 #[derive(Clone, Copy, Debug)]
 pub struct Retval(pub *mut c_void);