diff --git a/src/kernel/src/errno.rs b/src/kernel/src/errno.rs index 87d404f65..151174301 100644 --- a/src/kernel/src/errno.rs +++ b/src/kernel/src/errno.rs @@ -1,6 +1,7 @@ use std::convert::Infallible; use std::error::Error; use std::num::NonZeroI32; + // This file contains errno used in a PS4 system. The value of each errno must be the same as the // PS4. diff --git a/src/kernel/src/fs/dev/mod.rs b/src/kernel/src/fs/dev/mod.rs index 9cf72ab1d..d1645b527 100644 --- a/src/kernel/src/fs/dev/mod.rs +++ b/src/kernel/src/fs/dev/mod.rs @@ -9,7 +9,6 @@ use crate::errno::{Errno, EEXIST, ENOENT, EOPNOTSUPP}; use crate::ucred::{Gid, Ucred, Uid}; use bitflags::bitflags; use macros::Errno; -use std::num::NonZeroI32; use std::sync::atomic::{AtomicU32, AtomicUsize, Ordering}; use std::sync::{Arc, Mutex, RwLock}; use thiserror::Error; @@ -310,20 +309,13 @@ impl Devices { } /// Represents an error when [`make_dev()`] is failed. -#[derive(Debug, Error)] +#[derive(Debug, Error, Errno)] pub enum MakeDevError { #[error("the device with the same name already exist")] + #[errno(EEXIST)] AlreadyExist(String), } -impl Errno for MakeDevError { - fn errno(&self) -> NonZeroI32 { - match self { - Self::AlreadyExist(_) => EEXIST, - } - } -} - pub fn mount( conf: &'static FsConfig, cred: &Arc, diff --git a/src/kernel/src/fs/dev/vnode.rs b/src/kernel/src/fs/dev/vnode.rs index 926c3b3f9..bde4f1e81 100644 --- a/src/kernel/src/fs/dev/vnode.rs +++ b/src/kernel/src/fs/dev/vnode.rs @@ -7,7 +7,6 @@ use crate::fs::{ }; use crate::process::VThread; use macros::Errno; -use std::num::NonZeroI32; use std::sync::Arc; use thiserror::Error; @@ -209,36 +208,27 @@ impl crate::fs::VnodeBackend for VnodeBackend { } /// Represents an error when [`lookup()`] is failed. -#[derive(Debug, Error)] +#[derive(Debug, Error, Errno)] enum LookupError { #[error("file is not a directory")] + #[errno(ENOTDIR)] NotDirectory, #[error("cannot resolve '..' on the root directory")] + #[errno(EIO)] DotdotOnRoot, #[error("access denied")] AccessDenied(#[source] Box), #[error("file have no parent")] + #[errno(ENOENT)] NoParent, #[error("cannot allocate a vnode")] AllocVnodeFailed(#[source] AllocVnodeError), } -impl Errno for LookupError { - fn errno(&self) -> NonZeroI32 { - match self { - Self::NotDirectory => ENOTDIR, - Self::DotdotOnRoot => EIO, - Self::AccessDenied(e) => e.errno(), - Self::NoParent => ENOENT, - Self::AllocVnodeFailed(e) => e.errno(), - } - } -} - /// Represents an error when [`open()`] is failed. #[derive(Debug, Error, Errno)] enum OpenError { diff --git a/src/kernel/src/fs/host/vnode.rs b/src/kernel/src/fs/host/vnode.rs index 6f8b5dadc..8396927a3 100644 --- a/src/kernel/src/fs/host/vnode.rs +++ b/src/kernel/src/fs/host/vnode.rs @@ -6,7 +6,6 @@ use crate::process::VThread; use crate::ucred::{Gid, Uid}; use macros::Errno; use std::borrow::Cow; -use std::num::NonZeroI32; use std::sync::Arc; use thiserror::Error; @@ -128,34 +127,28 @@ enum GetAttrError { } /// Represents an error when [`lookup()`] fails. -#[derive(Debug, Error)] +#[derive(Debug, Error, Errno)] enum LookupError { #[error("current file is not a directory")] + #[errno(ENOTDIR)] NotDirectory, #[error("cannot resolve '..' on the root directory")] + #[errno(EIO)] DotdotOnRoot, #[error("access denied")] AccessDenied(#[source] Box), #[error("name contains unsupported characters")] + #[errno(ENOENT)] InvalidName, #[error("couldn't open the specified file")] + #[errno(EIO)] OpenFailed(#[source] std::io::Error), #[error("cannot get vnode")] + #[errno(EIO)] GetVnodeFailed(#[source] GetVnodeError), } - -impl Errno for LookupError { - fn errno(&self) -> NonZeroI32 { - match self { - Self::NotDirectory => ENOTDIR, - Self::DotdotOnRoot | Self::GetVnodeFailed(_) | Self::OpenFailed(_) => EIO, - Self::AccessDenied(e) => e.errno(), - Self::InvalidName => ENOENT, - } - } -} diff --git a/src/kernel/src/fs/mod.rs b/src/kernel/src/fs/mod.rs index cf7f18820..bd9803544 100644 --- a/src/kernel/src/fs/mod.rs +++ b/src/kernel/src/fs/mod.rs @@ -10,7 +10,7 @@ use macros::vpath; use macros::Errno; use param::Param; use std::fmt::{Display, Formatter}; -use std::num::{NonZeroI32, TryFromIntError}; +use std::num::TryFromIntError; use std::path::PathBuf; use std::sync::Arc; use thiserror::Error; @@ -1093,15 +1093,18 @@ pub enum FsInitError { } /// Represents an error when FS mounting fails. -#[derive(Debug, Error)] +#[derive(Debug, Error, Errno)] pub enum MountError { #[error("fstype is too long")] + #[errno(ENAMETOOLONG)] FsTooLong, #[error("fspath is too long")] + #[errno(ENAMETOOLONG)] PathTooLong, #[error("fstype is not valid")] + #[errno(ENODEV)] InvalidFs, #[error("fspath is not found")] @@ -1111,95 +1114,51 @@ pub enum MountError { MountFailed(#[source] Box), #[error("fspath is already mounted")] + #[errno(EBUSY)] PathAlreadyMounted, #[error("cannot get root")] GetRootFailed(#[source] Box), } -impl Errno for MountError { - fn errno(&self) -> NonZeroI32 { - match self { - Self::FsTooLong | Self::PathTooLong => ENAMETOOLONG, - Self::InvalidFs => ENODEV, - Self::LookupPathFailed(e) => e.errno(), - Self::MountFailed(e) => e.errno(), - Self::PathAlreadyMounted => EBUSY, - Self::GetRootFailed(e) => e.errno(), - } - } -} - /// Represents an error when [`Fs::open()`] fails. -#[derive(Debug, Error)] +#[derive(Debug, Error, Errno)] pub enum OpenError { #[error("cannot lookup the file")] LookupFailed(#[source] LookupError), } -impl Errno for OpenError { - fn errno(&self) -> NonZeroI32 { - match self { - Self::LookupFailed(e) => e.errno(), - } - } -} - -#[derive(Debug, Error)] +#[derive(Debug, Error, Errno)] pub enum WriteError {} -impl Errno for WriteError { - fn errno(&self) -> NonZeroI32 { - todo!() - } -} - -#[derive(Debug, Error)] +#[derive(Debug, Error, Errno)] pub enum IoctlError { #[error("Couldn't get file")] FailedToGetFile(#[from] GetFileError), #[error("Bad file flags {0:?}")] + #[errno(EBADF)] BadFileFlags(VFileFlags), #[error(transparent)] FileIoctlFailed(#[from] Box), } -impl Errno for IoctlError { - fn errno(&self) -> NonZeroI32 { - match self { - Self::FailedToGetFile(e) => e.errno(), - Self::BadFileFlags(_) => EBADF, - Self::FileIoctlFailed(e) => e.errno(), - } - } -} - /// Represents an error when [`Fs::lookup()`] fails. -#[derive(Debug, Error)] +#[derive(Debug, Error, Errno)] pub enum LookupError { #[error("failed to get mount root")] GetRootFailed(#[source] Box), #[error("no such file or directory")] + #[errno(ENOENT)] NotFound, #[error("cannot lookup '{1}' from component #{0}")] LookupFailed(usize, Box, #[source] Box), } -impl Errno for LookupError { - fn errno(&self) -> NonZeroI32 { - match self { - Self::GetRootFailed(e) => e.errno(), - Self::NotFound => ENOENT, - Self::LookupFailed(_, _, e) => e.errno(), - } - } -} - -#[derive(Debug, Error)] +#[derive(Debug, Error, Errno)] pub enum RevokeError { #[error("failed to get file attr")] GetAttrError(#[source] Box), @@ -1211,17 +1170,8 @@ pub enum RevokeError { RevokeFailed(#[source] Box), } -impl Errno for RevokeError { - fn errno(&self) -> NonZeroI32 { - match self { - Self::GetAttrError(e) => e.errno(), - Self::PrivelegeError(e) => e.errno(), - Self::RevokeFailed(e) => e.errno(), - } - } -} /// Represents an error when one of the stat syscalls fails -#[derive(Debug, Error)] +#[derive(Debug, Error, Errno)] pub enum StatError { #[error("failed to get file")] FailedToGetFile(#[from] GetFileError), @@ -1230,65 +1180,39 @@ pub enum StatError { GetAttrError(#[from] Box), } -impl Errno for StatError { - fn errno(&self) -> NonZeroI32 { - match self { - Self::FailedToGetFile(e) => e.errno(), - Self::GetAttrError(e) => e.errno(), - } - } -} - -#[derive(Debug, Error)] +#[derive(Debug, Error, Errno)] pub enum TruncateError { #[error("the provided length is invalid")] + #[errno(EINVAL)] InvalidLength, #[error("failed to get file")] FailedToLookupFile(#[from] LookupError), } -impl Errno for TruncateError { - fn errno(&self) -> NonZeroI32 { - match self { - Self::InvalidLength => EINVAL, - Self::FailedToLookupFile(e) => e.errno(), - } - } -} - impl From for TruncateError { fn from(_: TruncateLengthError) -> Self { Self::InvalidLength } } -#[derive(Debug, Error)] +#[derive(Debug, Error, Errno)] pub enum FileTruncateError { #[error("the provided length is invalid")] + #[errno(EINVAL)] InvalidLength, #[error("failed to get file")] FailedToGetFile(#[from] GetFileError), #[error("file is not writable")] + #[errno(EINVAL)] FileNotWritable, #[error(transparent)] TruncateError(#[from] Box), } -impl Errno for FileTruncateError { - fn errno(&self) -> NonZeroI32 { - match self { - Self::InvalidLength => EINVAL, - Self::FailedToGetFile(e) => e.errno(), - Self::FileNotWritable => EINVAL, - Self::TruncateError(e) => e.errno(), - } - } -} - impl From for FileTruncateError { fn from(_: TruncateLengthError) -> Self { Self::InvalidLength diff --git a/src/kernel/src/fs/null/vnode.rs b/src/kernel/src/fs/null/vnode.rs index 3cc72b117..4e729c7a5 100644 --- a/src/kernel/src/fs/null/vnode.rs +++ b/src/kernel/src/fs/null/vnode.rs @@ -3,7 +3,8 @@ use crate::{ fs::{perm::Access, Mount, MountFlags, OpenFlags, VFile, Vnode, VnodeAttrs, VnodeType}, process::VThread, }; -use std::{num::NonZeroI32, sync::Arc}; +use macros::Errno; +use std::sync::Arc; use thiserror::Error; #[derive(Debug)] @@ -87,83 +88,45 @@ impl crate::fs::VnodeBackend for VnodeBackend { } } -#[derive(Debug, Error)] +/// See `null_nodeget` on the PS4 for a reference. +pub(super) fn null_nodeget( + mnt: &Arc, + lower: Arc, +) -> Result, NodeGetError> { + todo!() +} + +#[derive(Debug, Error, Errno)] pub enum AccessError { #[error("mounted as readonly")] + #[errno(EROFS)] Readonly, #[error("vnode is directory")] + #[errno(EISDIR)] IsDirectory, #[error("access from lower vnode failed")] AccessFromLowerFailed(#[from] Box), } -impl Errno for AccessError { - fn errno(&self) -> NonZeroI32 { - match self { - Self::Readonly => EROFS, - Self::IsDirectory => EISDIR, - Self::AccessFromLowerFailed(e) => e.errno(), - } - } -} - -#[derive(Debug, Error)] +#[derive(Debug, Error, Errno)] pub enum GetAttrError { #[error("getattr from lower vnode failed")] GetAttrFromLowerFailed(#[from] Box), } -impl Errno for GetAttrError { - fn errno(&self) -> NonZeroI32 { - match self { - Self::GetAttrFromLowerFailed(e) => e.errno(), - } - } -} - -#[derive(Debug, Error)] +#[derive(Debug, Error, Errno)] pub enum LookupError { #[error("lookup from lower vnode failed")] LookupFromLowerFailed(#[source] Box), } -impl Errno for LookupError { - fn errno(&self) -> NonZeroI32 { - match self { - Self::LookupFromLowerFailed(e) => e.errno(), - } - } -} - -#[derive(Debug, Error)] +#[derive(Debug, Error, Errno)] pub enum OpenError { #[error("open from lower vnode failed")] OpenFromLowerFailed(#[source] Box), } -impl Errno for OpenError { - fn errno(&self) -> NonZeroI32 { - match self { - Self::OpenFromLowerFailed(e) => e.errno(), - } - } -} - -/// See `null_nodeget` on the PS4 for a reference. -pub(super) fn null_nodeget( - mnt: &Arc, - lower: Arc, -) -> Result, NodeGetError> { - todo!() -} - -#[derive(Debug, Error)] +#[derive(Debug, Error, Errno)] pub(super) enum NodeGetError {} - -impl Errno for NodeGetError { - fn errno(&self) -> NonZeroI32 { - todo!() - } -} diff --git a/src/kernel/src/fs/tmp/mod.rs b/src/kernel/src/fs/tmp/mod.rs index c40d32aa4..b6d7e9462 100644 --- a/src/kernel/src/fs/tmp/mod.rs +++ b/src/kernel/src/fs/tmp/mod.rs @@ -2,7 +2,7 @@ use self::node::{AllocNodeError, Node, Nodes}; use super::{Filesystem, FsConfig, Mount, MountFlags, MountOpts, MountSource, VPathBuf, Vnode}; use crate::errno::{Errno, EINVAL}; use crate::ucred::{Ucred, Uid}; -use std::num::NonZeroI32; +use macros::Errno; use std::sync::atomic::AtomicI32; use std::sync::Arc; use thiserror::Error; @@ -119,9 +119,10 @@ fn alloc_vnode(mnt: &Arc, node: &Arc) -> Result, AllocVn } /// Represents an error when [`mount()`] fails. -#[derive(Debug, Error)] +#[derive(Debug, Error, Errno)] enum MountError { #[error("update is not supported")] + #[errno(EINVAL)] UpdateNotSupported, #[error("cannot get mount point attributes")] @@ -131,21 +132,5 @@ enum MountError { AllocRootFailed(#[from] AllocNodeError), } -impl Errno for MountError { - fn errno(&self) -> NonZeroI32 { - match self { - Self::UpdateNotSupported => EINVAL, - Self::GetParentAttrsFailed(e) => e.errno(), - Self::AllocRootFailed(e) => e.errno(), - } - } -} - -#[derive(Debug, Error)] +#[derive(Debug, Error, Errno)] enum AllocVnodeError {} - -impl Errno for AllocVnodeError { - fn errno(&self) -> NonZeroI32 { - todo!() - } -} diff --git a/src/kernel/src/net/socket.rs b/src/kernel/src/net/socket.rs index a9558b942..0cc9969ce 100644 --- a/src/kernel/src/net/socket.rs +++ b/src/kernel/src/net/socket.rs @@ -5,7 +5,8 @@ use crate::{ process::VThread, }; use bitflags::bitflags; -use std::{num::NonZeroI32, sync::Arc}; +use macros::Errno; +use std::sync::Arc; use thiserror::Error; #[derive(Debug)] @@ -54,15 +55,6 @@ bitflags! { } } -#[derive(Debug, Error)] -pub enum SocketCreateError {} - -impl Errno for SocketCreateError { - fn errno(&self) -> NonZeroI32 { - match *self {} - } -} - impl FileBackend for Socket { /// See soo_read on the PS4 for a reference. fn read( @@ -118,25 +110,15 @@ impl FileBackend for Socket { } } -#[derive(Debug, Error)] -enum ReceiveError {} +#[derive(Debug, Error, Errno)] +pub enum SocketCreateError {} -impl Errno for ReceiveError { - fn errno(&self) -> NonZeroI32 { - todo!() - } -} +#[derive(Debug, Error, Errno)] +enum ReceiveError {} -#[derive(Debug, Error)] +#[derive(Debug, Error, Errno)] enum SendError { #[error("Broken pipe")] + #[errno(EPIPE)] BrokenPipe, } - -impl Errno for SendError { - fn errno(&self) -> NonZeroI32 { - match self { - Self::BrokenPipe => EPIPE, - } - } -} diff --git a/src/kernel/src/process/thread.rs b/src/kernel/src/process/thread.rs index 3e3b98050..cbb004a85 100644 --- a/src/kernel/src/process/thread.rs +++ b/src/kernel/src/process/thread.rs @@ -6,6 +6,7 @@ use crate::ucred::{Privilege, PrivilegeError, Ucred}; use bitflags::bitflags; use gmtx::{Gutex, GutexGroup, GutexReadGuard, GutexWriteGuard}; use llt::{OsThread, SpawnError}; +use macros::Errno; use std::num::NonZeroI32; use std::sync::atomic::Ordering; use std::sync::Arc; @@ -185,11 +186,5 @@ impl Drop for Running { static VTHREAD: Tls> = Tls::new(); -#[derive(Debug, Error)] +#[derive(Debug, Error, Errno)] pub enum FileAllocError {} - -impl Errno for FileAllocError { - fn errno(&self) -> NonZeroI32 { - match *self {} - } -} diff --git a/src/kernel/src/shm/mod.rs b/src/kernel/src/shm/mod.rs index e23b0825d..4a26e1624 100644 --- a/src/kernel/src/shm/mod.rs +++ b/src/kernel/src/shm/mod.rs @@ -1,3 +1,4 @@ +use macros::Errno; use thiserror::Error; use crate::{ @@ -11,7 +12,7 @@ use crate::{ syscalls::{SysErr, SysIn, SysOut, Syscalls}, ucred::{Gid, Ucred, Uid}, }; -use std::{convert::Infallible, num::NonZeroI32, sync::Arc}; +use std::{convert::Infallible, sync::Arc}; pub struct SharedMemoryManager { mm: Arc, @@ -159,11 +160,5 @@ impl FileBackend for Shm { } } -#[derive(Debug, Error)] +#[derive(Debug, Error, Errno)] pub enum TruncateError {} - -impl Errno for TruncateError { - fn errno(&self) -> NonZeroI32 { - match *self {} - } -} diff --git a/src/macros/src/errno.rs b/src/macros/src/errno.rs index fb7c79ab1..0da1e31dc 100644 --- a/src/macros/src/errno.rs +++ b/src/macros/src/errno.rs @@ -1,6 +1,6 @@ use proc_macro2::{Ident, TokenStream}; use quote::quote; -use syn::{punctuated::Punctuated, Fields, ItemEnum, Meta, Token, Variant}; +use syn::{punctuated::Punctuated, Fields, Index, ItemEnum, Meta, Token, Variant}; pub fn transform(arg: ItemEnum) -> syn::Result { let enum_name = &arg.ident; @@ -11,17 +11,25 @@ pub fn transform(arg: ItemEnum) -> syn::Result { .map(|variant| process_variant(variant, enum_name)) .collect::, _>>()?; - let res = quote!( - impl Errno for #enum_name { - fn errno(&self) -> std::num::NonZeroI32 { - match self { - #(#arms)* + if arms.is_empty() { + Ok(quote!( + impl Errno for #enum_name { + fn errno(&self) -> std::num::NonZeroI32 { + match *self {} } } - } - ); - - Ok(res) + )) + } else { + Ok(quote!( + impl Errno for #enum_name { + fn errno(&self) -> std::num::NonZeroI32 { + match self { + #(#arms)* + } + } + } + )) + } } fn process_variant(variant: &Variant, enum_name: &Ident) -> syn::Result { @@ -61,8 +69,59 @@ fn process_variant(variant: &Variant, enum_name: &Ident) -> syn::Result todo!("Named fields are not supported yet"), + Fields::Unnamed(fields) => { + let ref fields = fields.unnamed; + + let mut pos = None; + + fields + .iter() + .enumerate() + .try_for_each(|(i, field)| { + for attr in field.attrs.iter() { + if attr.path().is_ident("source") || attr.path().is_ident("from") { + if let Some(_) = pos.replace(i) { + return Err(syn::Error::new_spanned( + attr, + format!( + "multiple fields marked with either #[source] or #[from] found. \ + Only one field is allowed" + ), + )) + } + } + + } + + Ok(()) + })?; + + return match pos { + Some(pos) => { + let variant_name = &variant.ident; + // The field at index `pos` is the one we are interested in + + // We have to use this. otherwise the macro would expand to something like + // `{ 0usize: e, .. }` which is accepted, but only temporarily + let index = Index::from(pos); + + Ok(quote!(#enum_name::#variant_name { #index: e, .. } => e.errno(),)) + } + None => Err(syn::Error::new_spanned( + variant, + "no fields of this variant are marked with either #[source] or #[from]", + )), + }; + } + Fields::Unit => Err(syn::Error::new_spanned( + variant, + "no errno attribute found on a variant with no fields", + )), + } }