nix 0.1.3

Rust friendly bindings to Posix APIs
use std::fmt;
use std::os::errno;
use std::num::from_uint;
use libc::c_int;

pub use self::consts::*;
pub use self::consts::Errno::*;

pub type SysResult<T> = Result<T, SysError>;

#[derive(Clone, PartialEq, Copy)]
pub struct SysError {
    pub kind: Errno,
}

impl SysError {
    pub fn last() -> SysError {
        match from_uint(errno()) {
            Some(no) => SysError::new(no),
            _ => SysError::new(UnknownErrno)
        }
    }

    pub fn new(kind: Errno) -> SysError {
        SysError { kind: kind }
    }

    pub fn errno(&self) -> usize {
        self.kind as usize
    }

    pub fn desc(&self) -> &'static str {
        match self.kind {
            UnknownErrno    => "Unknown errno",
            EPERM           => "Operation not permitted",
            ENOENT          => "No such file or directory",
            ESRCH           => "No such process",
            EINTR           => "Interrupted system call",
            EIO             => "I/O error",
            ENXIO           => "No such device or address",
            E2BIG           => "Argument list too long",
            ENOEXEC         => "Exec format error",
            EBADF           => "Bad file number",
            ECHILD          => "No child processes",
            EAGAIN          => "Try again",
            ENOMEM          => "Out of memory",
            EACCES          => "Permission denied",
            EFAULT          => "Bad address",
            ENOTBLK         => "Block device required",
            EBUSY           => "Device or resource busy",
            EEXIST          => "File exists",
            EXDEV           => "Cross-device link",
            ENODEV          => "No such device",
            ENOTDIR         => "Not a directory",
            EISDIR          => "Is a directory",
            EINVAL          => "Invalid argument",
            ENFILE          => "File table overflow",
            EMFILE          => "Too many open files",
            ENOTTY          => "Not a typewriter",
            ETXTBSY         => "Text file busy",
            EFBIG           => "File too large",
            ENOSPC          => "No space left on device",
            ESPIPE          => "Illegal seek",
            EROFS           => "Read-only file system",
            EMLINK          => "Too many links",
            EPIPE           => "Broken pipe",
            EDOM            => "Math argument out of domain of func",
            ERANGE          => "Math result not representable",
            EDEADLK         => "Resource deadlock would occur",
            ENAMETOOLONG    => "File name too long",
            ENOLCK          => "No record locks available",
            ENOSYS          => "Function not implemented",
            ENOTEMPTY       => "Directory not empty",
            ELOOP           => "Too many symbolic links encountered",
            ENOMSG          => "No message of desired type",
            EIDRM           => "Identifier removed",
            EINPROGRESS     => "Operation now in progress",
            EALREADY        => "Operation already in progress",
            ENOTSOCK        => "Socket operation on non-socket",
            EDESTADDRREQ    => "Destination address required",
            EMSGSIZE        => "Message too long",
            EPROTOTYPE      => "Protocol wrong type for socket",
            ENOPROTOOPT     => "Protocol not available",
            EPROTONOSUPPORT => "Protocol not supported",
            ESOCKTNOSUPPORT => "Socket type not supported",
            EPFNOSUPPORT    => "Protocol family not supported",
            EAFNOSUPPORT    => "Address family not supported by protocol",
            EADDRINUSE      => "Address already in use",
            EADDRNOTAVAIL   => "Cannot assign requested address",
            ENETDOWN        => "Network is down",
            ENETUNREACH     => "Network is unreachable",
            ENETRESET       => "Network dropped connection because of reset",
            ECONNABORTED    => "Software caused connection abort",
            ECONNRESET      => "Connection reset by peer",
            ENOBUFS         => "No buffer space available",
            EISCONN         => "Transport endpoint is already connected",
            ENOTCONN        => "Transport endpoint is not connected",
            ESHUTDOWN       => "Cannot send after transport endpoint shutdown",
            ETOOMANYREFS    => "Too many references: cannot splice",
            ETIMEDOUT       => "Connection timed out",
            ECONNREFUSED    => "Connection refused",
            EHOSTDOWN       => "Host is down",
            EHOSTUNREACH    => "No route to host",

            #[cfg(target_os = "linux")]
            ECHRNG          => "Channel number out of range",

            #[cfg(target_os = "linux")]
            EL2NSYNC        => "Level 2 not synchronized",

            #[cfg(target_os = "linux")]
            EL3HLT          => "Level 3 halted",

            #[cfg(target_os = "linux")]
            EL3RST          => "Level 3 reset",

            #[cfg(target_os = "linux")]
            ELNRNG          => "Link number out of range",

            #[cfg(target_os = "linux")]
            EUNATCH         => "Protocol driver not attached",

            #[cfg(target_os = "linux")]
            ENOCSI          => "No CSI structure available",

            #[cfg(target_os = "linux")]
            EL2HLT          => "Level 2 halted",

            #[cfg(target_os = "linux")]
            EBADE           => "Invalid exchange",

            #[cfg(target_os = "linux")]
            EBADR           => "Invalid request descriptor",

            #[cfg(target_os = "linux")]
            EXFULL          => "Exchange full",

            #[cfg(target_os = "linux")]
            ENOANO          => "No anode",

            #[cfg(target_os = "linux")]
            EBADRQC         => "Invalid request code",

            #[cfg(target_os = "linux")]
            EBADSLT         => "Invalid slot",

            #[cfg(target_os = "linux")]
            EBFONT          => "Bad font file format",

            #[cfg(target_os = "linux")]
            ENOSTR          => "Device not a stream",

            #[cfg(target_os = "linux")]
            ENODATA         => "No data available",

            #[cfg(target_os = "linux")]
            ETIME           => "Timer expired",

            #[cfg(target_os = "linux")]
            ENOSR           => "Out of streams resources",

            #[cfg(target_os = "linux")]
            ENONET          => "Machine is not on the network",

            #[cfg(target_os = "linux")]
            ENOPKG          => "Package not installed",

            #[cfg(target_os = "linux")]
            EREMOTE         => "Object is remote",

            #[cfg(target_os = "linux")]
            ENOLINK         => "Link has been severed",

            #[cfg(target_os = "linux")]
            EADV            => "Advertise error",

            #[cfg(target_os = "linux")]
            ESRMNT          => "Srmount error",

            #[cfg(target_os = "linux")]
            ECOMM           => "Communication error on send",

            #[cfg(target_os = "linux")]
            EPROTO          => "Protocol error",

            #[cfg(target_os = "linux")]
            EMULTIHOP       => "Multihop attempted",

            #[cfg(target_os = "linux")]
            EDOTDOT         => "RFS specific error",

            #[cfg(target_os = "linux")]
            EBADMSG         => "Not a data message",

            #[cfg(target_os = "linux")]
            EOVERFLOW       => "Value too large for defined data type",

            #[cfg(target_os = "linux")]
            ENOTUNIQ        => "Name not unique on network",

            #[cfg(target_os = "linux")]
            EBADFD          => "File descriptor in bad state",

            #[cfg(target_os = "linux")]
            EREMCHG         => "Remote address changed",

            #[cfg(target_os = "linux")]
            ELIBACC         => "Can not acces a needed shared library",

            #[cfg(target_os = "linux")]
            ELIBBAD         => "Accessing a corrupted shared library",

            #[cfg(target_os = "linux")]
            ELIBSCN         => ".lib section in a.out corrupted",

            #[cfg(target_os = "linux")]
            ELIBMAX         => "Attempting to link in too many shared libraries",

            #[cfg(target_os = "linux")]
            ELIBEXEC        => "Cannot exec a shared library directly",

            #[cfg(target_os = "linux")]
            EILSEQ          => "Illegal byte sequence",

            #[cfg(target_os = "linux")]
            ERESTART        => "Interrupted system call should be restarted",

            #[cfg(target_os = "linux")]
            ESTRPIPE        => "Streams pipe error",

            #[cfg(target_os = "linux")]
            EUSERS          => "Too many users",

            #[cfg(target_os = "linux")]
            EOPNOTSUPP      => "Operation not supported on transport endpoint",

            #[cfg(target_os = "linux")]
            ESTALE          => "Stale file handle",

            #[cfg(target_os = "linux")]
            EUCLEAN         => "Structure needs cleaning",

            #[cfg(target_os = "linux")]
            ENOTNAM         => "Not a XENIX named type file",

            #[cfg(target_os = "linux")]
            ENAVAIL         => "No XENIX semaphores available",

            #[cfg(target_os = "linux")]
            EISNAM          => "Is a named type file",

            #[cfg(target_os = "linux")]
            EREMOTEIO       => "Remote I/O error",

            #[cfg(target_os = "linux")]
            EDQUOT          => "Quota exceeded",

            #[cfg(target_os = "linux")]
            ENOMEDIUM       => "No medium found",

            #[cfg(target_os = "linux")]
            EMEDIUMTYPE     => "Wrong medium type",

            #[cfg(target_os = "linux")]
            ECANCELED       => "Operation canceled",

            #[cfg(target_os = "linux")]
            ENOKEY          => "Required key not available",

            #[cfg(target_os = "linux")]
            EKEYEXPIRED     => "Key has expired",

            #[cfg(target_os = "linux")]
            EKEYREVOKED     => "Key has been revoked",

            #[cfg(target_os = "linux")]
            EKEYREJECTED    => "Key was rejected by service",

            #[cfg(target_os = "linux")]
            EOWNERDEAD      => "Owner died",

            #[cfg(target_os = "linux")]
            ENOTRECOVERABLE => "State not recoverable",

            #[cfg(target_os = "linux")]
            ERFKILL         => "Operation not possible due to RF-kill",

            #[cfg(target_os = "linux")]
            EHWPOISON       => "Memory page has hardware error",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            ENOTSUP         => "Operation not supported",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            EPROCLIM        => "Too many processes",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            EUSERS          => "Too many users",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            EDQUOT          => "Disc quota exceeded",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            ESTALE          => "Stale NFS file handle",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            EREMOTE         => "Stale NFS file handle",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            EBADRPC         => "RPC struct is bad",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            ERPCMISMATCH    => "RPC version wrong",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            EPROGUNAVAIL    => "RPC prog. not avail",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            EPROGMISMATCH   => "Program version wrong",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            EPROCUNAVAIL    => "Bad procedure for program",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            EFTYPE          => "Inappropriate file type or format",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            EAUTH           => "Authentication error",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            ENEEDAUTH       => "Need authenticator",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            EPWROFF         => "Device power is off",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            EDEVERR         => "Device error, e.g. paper out",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            EOVERFLOW       => "Value too large to be stored in data type",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            EBADEXEC        => "Bad executable",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            EBADARCH        => "Bad CPU type in executable",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            ESHLIBVERS      => "Shared library version mismatch",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            EBADMACHO       => "Malformed Macho file",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            ECANCELED       => "Operation canceled",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            EILSEQ          => "Illegal byte sequence",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            ENOATTR         => "Attribute not found",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            EBADMSG         => "Bad message",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            EMULTIHOP       => "Reserved",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            ENODATA         => "No message available on STREAM",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            ENOLINK         => "Reserved",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            ENOSR           => "No STREAM resources",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            ENOSTR          => "Not a STREAM",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            EPROTO          => "Protocol error",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            ETIME           => "STREAM ioctl timeout",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            EOPNOTSUPP      => "Operation not supported on socket",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            ENOPOLICY       => "No such policy registered",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            ENOTRECOVERABLE => "State not recoverable",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            EOWNERDEAD      => "Previous owner died",

            #[cfg(any(target_os = "macos", target_os = "ios"))]
            EQFULL          => "Interface output queue is full",
        }
    }
}

impl fmt::Debug for SysError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{:?} - {:?}", self.kind, self.desc())
    }
}

#[inline]
pub fn from_ffi(res: c_int) -> SysResult<()> {
    if res != 0 {
        return Err(SysError::last());
    }

    Ok(())
}


#[cfg(target_os = "linux")]
mod consts {
    #[derive(Debug, Clone, PartialEq, FromPrimitive, Copy)]
    pub enum Errno {
        UnknownErrno    = 0,
        EPERM           = 1,
        ENOENT          = 2,
        ESRCH           = 3,
        EINTR           = 4,
        EIO             = 5,
        ENXIO           = 6,
        E2BIG           = 7,
        ENOEXEC         = 8,
        EBADF           = 9,
        ECHILD          = 10,
        EAGAIN          = 11,
        ENOMEM          = 12,
        EACCES          = 13,
        EFAULT          = 14,
        ENOTBLK         = 15,
        EBUSY           = 16,
        EEXIST          = 17,
        EXDEV           = 18,
        ENODEV          = 19,
        ENOTDIR         = 20,
        EISDIR          = 21,
        EINVAL          = 22,
        ENFILE          = 23,
        EMFILE          = 24,
        ENOTTY          = 25,
        ETXTBSY         = 26,
        EFBIG           = 27,
        ENOSPC          = 28,
        ESPIPE          = 29,
        EROFS           = 30,
        EMLINK          = 31,
        EPIPE           = 32,
        EDOM            = 33,
        ERANGE          = 34,
        EDEADLK         = 35,
        ENAMETOOLONG    = 36,
        ENOLCK          = 37,
        ENOSYS          = 38,
        ENOTEMPTY       = 39,
        ELOOP           = 40,
        ENOMSG          = 42,
        EIDRM           = 43,
        ECHRNG          = 44,
        EL2NSYNC        = 45,
        EL3HLT          = 46,
        EL3RST          = 47,
        ELNRNG          = 48,
        EUNATCH         = 49,
        ENOCSI          = 50,
        EL2HLT          = 51,
        EBADE           = 52,
        EBADR           = 53,
        EXFULL          = 54,
        ENOANO          = 55,
        EBADRQC         = 56,
        EBADSLT         = 57,
        EBFONT          = 59,
        ENOSTR          = 60,
        ENODATA         = 61,
        ETIME           = 62,
        ENOSR           = 63,
        ENONET          = 64,
        ENOPKG          = 65,
        EREMOTE         = 66,
        ENOLINK         = 67,
        EADV            = 68,
        ESRMNT          = 69,
        ECOMM           = 70,
        EPROTO          = 71,
        EMULTIHOP       = 72,
        EDOTDOT         = 73,
        EBADMSG         = 74,
        EOVERFLOW       = 75,
        ENOTUNIQ        = 76,
        EBADFD          = 77,
        EREMCHG         = 78,
        ELIBACC         = 79,
        ELIBBAD         = 80,
        ELIBSCN         = 81,
        ELIBMAX         = 82,
        ELIBEXEC        = 83,
        EILSEQ          = 84,
        ERESTART        = 85,
        ESTRPIPE        = 86,
        EUSERS          = 87,
        ENOTSOCK        = 88,
        EDESTADDRREQ    = 89,
        EMSGSIZE        = 90,
        EPROTOTYPE      = 91,
        ENOPROTOOPT     = 92,
        EPROTONOSUPPORT = 93,
        ESOCKTNOSUPPORT = 94,
        EOPNOTSUPP      = 95,
        EPFNOSUPPORT    = 96,
        EAFNOSUPPORT    = 97,
        EADDRINUSE      = 98,
        EADDRNOTAVAIL   = 99,
        ENETDOWN        = 100,
        ENETUNREACH     = 101,
        ENETRESET       = 102,
        ECONNABORTED    = 103,
        ECONNRESET      = 104,
        ENOBUFS         = 105,
        EISCONN         = 106,
        ENOTCONN        = 107,
        ESHUTDOWN       = 108,
        ETOOMANYREFS    = 109,
        ETIMEDOUT       = 110,
        ECONNREFUSED    = 111,
        EHOSTDOWN       = 112,
        EHOSTUNREACH    = 113,
        EALREADY        = 114,
        EINPROGRESS     = 115,
        ESTALE          = 116,
        EUCLEAN         = 117,
        ENOTNAM         = 118,
        ENAVAIL         = 119,
        EISNAM          = 120,
        EREMOTEIO       = 121,
        EDQUOT          = 122,
        ENOMEDIUM       = 123,
        EMEDIUMTYPE     = 124,
        ECANCELED       = 125,
        ENOKEY          = 126,
        EKEYEXPIRED     = 127,
        EKEYREVOKED     = 128,
        EKEYREJECTED    = 129,
        EOWNERDEAD      = 130,
        ENOTRECOVERABLE = 131,
        ERFKILL         = 132,
        EHWPOISON       = 133,
    }

    pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
    pub const EDEADLOCK:   Errno = Errno::EDEADLK;
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
mod consts {
    #[derive(Copy, Debug, Clone, PartialEq, FromPrimitive)]
    pub enum Errno {
        UnknownErrno    = 0,
        EPERM           = 1,
        ENOENT          = 2,
        ESRCH           = 3,
        EINTR           = 4,
        EIO             = 5,
        ENXIO           = 6,
        E2BIG           = 7,
        ENOEXEC         = 8,
        EBADF           = 9,
        ECHILD          = 10,
        EDEADLK         = 11,
        ENOMEM          = 12,
        EACCES          = 13,
        EFAULT          = 14,
        ENOTBLK         = 15,
        EBUSY           = 16,
        EEXIST          = 17,
        EXDEV           = 18,
        ENODEV          = 19,
        ENOTDIR         = 20,
        EISDIR          = 21,
        EINVAL          = 22,
        ENFILE          = 23,
        EMFILE          = 24,
        ENOTTY          = 25,
        ETXTBSY         = 26,
        EFBIG           = 27,
        ENOSPC          = 28,
        ESPIPE          = 29,
        EROFS           = 30,
        EMLINK          = 31,
        EPIPE           = 32,
        EDOM            = 33,
        ERANGE          = 34,
        EAGAIN          = 35,
        EINPROGRESS     = 36,
        EALREADY        = 37,
        ENOTSOCK        = 38,
        EDESTADDRREQ    = 39,
        EMSGSIZE        = 40,
        EPROTOTYPE      = 41,
        ENOPROTOOPT     = 42,
        EPROTONOSUPPORT = 43,
        ESOCKTNOSUPPORT = 44,
        ENOTSUP         = 45,
        EPFNOSUPPORT    = 46,
        EAFNOSUPPORT    = 47,
        EADDRINUSE      = 48,
        EADDRNOTAVAIL   = 49,
        ENETDOWN        = 50,
        ENETUNREACH     = 51,
        ENETRESET       = 52,
        ECONNABORTED    = 53,
        ECONNRESET      = 54,
        ENOBUFS         = 55,
        EISCONN         = 56,
        ENOTCONN        = 57,
        ESHUTDOWN       = 58,
        ETOOMANYREFS    = 59,
        ETIMEDOUT       = 60,
        ECONNREFUSED    = 61,
        ELOOP           = 62,
        ENAMETOOLONG    = 63,
        EHOSTDOWN       = 64,
        EHOSTUNREACH    = 65,
        ENOTEMPTY       = 66,
        EPROCLIM        = 67,
        EUSERS          = 68,
        EDQUOT          = 69,
        ESTALE          = 70,
        EREMOTE         = 71,
        EBADRPC         = 72,
        ERPCMISMATCH    = 73,
        EPROGUNAVAIL    = 74,
        EPROGMISMATCH   = 75,
        EPROCUNAVAIL    = 76,
        ENOLCK          = 77,
        ENOSYS          = 78,
        EFTYPE          = 79,
        EAUTH           = 80,
        ENEEDAUTH       = 81,
        EPWROFF         = 82,
        EDEVERR         = 83,
        EOVERFLOW       = 84,
        EBADEXEC        = 85,
        EBADARCH        = 86,
        ESHLIBVERS      = 87,
        EBADMACHO       = 88,
        ECANCELED       = 89,
        EIDRM           = 90,
        ENOMSG          = 91,
        EILSEQ          = 92,
        ENOATTR         = 93,
        EBADMSG         = 94,
        EMULTIHOP       = 95,
        ENODATA         = 96,
        ENOLINK         = 97,
        ENOSR           = 98,
        ENOSTR          = 99,
        EPROTO          = 100,
        ETIME           = 101,
        EOPNOTSUPP      = 102,
        ENOPOLICY       = 103,
        ENOTRECOVERABLE = 104,
        EOWNERDEAD      = 105,
        EQFULL          = 106,
    }

    pub const ELAST: Errno       = Errno::EQFULL;
    pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
    pub const EDEADLOCK:   Errno = Errno::EDEADLK;

    pub const EL2NSYNC: Errno = Errno::UnknownErrno;
}