posix_errors/
lib.rs

1//! Posix error codes and handy functions for using them.
2//!
3//! Error codes taken from [http://fxr.watson.org/fxr/source/sys/errno.h](http://fxr.watson.org/fxr/source/sys/errno.h)
4
5/// This module makes it easy.
6use std::fmt;
7use std::io::ErrorKind;
8
9/// Struct containing a posix error code and an error message
10#[derive(Debug, Clone, PartialEq)]
11pub struct PosixError {
12    code: i32,
13    message: String,
14}
15
16/// Operation not permitted
17pub const EPERM: i32 = 1;
18/// No such file or directory
19pub const ENOENT: i32 = 2;
20/// No such process
21pub const ESRCH: i32 = 3;
22/// Interrupted system call
23pub const EINTR: i32 = 4;
24///  Input/output error
25pub const EIO: i32 = 5;
26/// Device not configured
27pub const ENXIO: i32 = 6;
28/// Argument list too long
29pub const E2BIG: i32 = 7;
30/// Exec format error
31pub const ENOEXEC: i32 = 8;
32/// Bad file descriptor
33pub const EBADF: i32 = 9;
34/// No child processes
35pub const ECHILD: i32 = 10;
36/// Resource deadlock avoided
37pub const EDEADLK: i32 = 11;
38/// Cannot allocate memory
39pub const ENOMEM: i32 = 12;
40/// Permission denied
41pub const EACCES: i32 = 13;
42/// Bad address
43pub const EFAULT: i32 = 14;
44/// Block device required
45pub const ENOTBLK: i32 = 15;
46/// Device busy
47pub const EBUSY: i32 = 16;
48/// File exists
49pub const EEXIST: i32 = 17;
50/// Cross-device link
51pub const EXDEV: i32 = 18;
52/// Operation not supported by device
53pub const ENODEV: i32 = 19;
54/// Not a directory
55pub const ENOTDIR: i32 = 20;
56/// Is a directory
57pub const EISDIR: i32 = 21;
58/// Invalid argument
59pub const EINVAL: i32 = 22;
60/// Too many open files in system
61pub const ENFILE: i32 = 23;
62/// Too many open files
63pub const EMFILE: i32 = 24;
64/// Inappropriate ioctl for device
65pub const ENOTTY: i32 = 25;
66/// Text file busy
67pub const ETXTBSY: i32 = 26;
68/// File too large
69pub const EFBIG: i32 = 27;
70/// No space left on device
71pub const ENOSPC: i32 = 28;
72/// Illegal seek
73pub const ESPIPE: i32 = 29;
74/// Read-only filesystem
75pub const EROFS: i32 = 30;
76/// Too many links
77pub const EMLINK: i32 = 31;
78/// Broken pipe
79pub const EPIPE: i32 = 32;
80/// Numerical argument out of domain
81pub const EDOM: i32 = 33;
82/// Result too large
83pub const ERANGE: i32 = 34;
84/// Resource temporarily unavailable
85pub const EAGAIN: i32 = 35;
86/// Resource temporarily unavailable
87pub const EWOULDBLOCK: i32 = 35;
88/// Operation now in progress
89pub const EINPROGRESS: i32 = 36;
90/// Operation already in progress
91pub const EALREADY: i32 = 37;
92/// Socket operation on non-socket
93pub const ENOTSOCK: i32 = 38;
94/// Destination address required
95pub const EDESTADDRREQ: i32 = 39;
96/// Message too long
97pub const EMSGSIZE: i32 = 40;
98/// Protocol wrong type for socket
99pub const EPROTOTYPE: i32 = 41;
100/// Protocol not available
101pub const ENOPROTOOPT: i32 = 42;
102/// Protocol not supported
103pub const EPROTONOSUPPORT: i32 = 43;
104/// Socket type not supported
105pub const ESOCKTNOSUPPORT: i32 = 44;
106/// Operation not supported
107pub const EOPNOTSUPP: i32 = 45;
108/// Operation not supported
109pub const ENOTSUP: i32 = 45;
110/// Protocol family not supported
111pub const EPFNOSUPPORT: i32 = 46;
112/// Address family not supported by protocol family
113pub const EAFNOSUPPORT: i32 = 47;
114/// Address already in use
115pub const EADDRINUSE: i32 = 48;
116/// Can't assign requested address
117pub const EADDRNOTAVAIL: i32 = 49;
118/// Network is down
119pub const ENETDOWN: i32 = 50;
120/// Network is unreachable
121pub const ENETUNREACH: i32 = 51;
122/// Network dropped connection on reset
123pub const ENETRESET: i32 = 52;
124/// Software caused connection abort
125pub const ECONNABORTED: i32 = 53;
126/// Connection reset by peer
127pub const ECONNRESET: i32 = 54;
128/// No buffer space available
129pub const ENOBUFS: i32 = 55;
130/// Socket is already connected
131pub const EISCONN: i32 = 56;
132/// Socket is not connected
133pub const ENOTCONN: i32 = 57;
134/// Can't send after socket shutdown
135pub const ESHUTDOWN: i32 = 58;
136/// Too many references: can't splice
137pub const ETOOMANYREFS: i32 = 59;
138/// Operation timed out
139pub const ETIMEDOUT: i32 = 60;
140/// Connection refused
141pub const ECONNREFUSED: i32 = 61;
142/// Too many levels of symbolic links
143pub const ELOOP: i32 = 62;
144/// File name too long
145pub const ENAMETOOLONG: i32 = 63;
146/// Host is down
147pub const EHOSTDOWN: i32 = 64;
148/// No route to host
149pub const EHOSTUNREACH: i32 = 65;
150/// Directory not empty
151pub const ENOTEMPTY: i32 = 66;
152/// Too many processes
153pub const EPROCLIM: i32 = 67;
154/// Too many users
155pub const EUSERS: i32 = 68;
156/// Disc quota exceeded
157pub const EDQUOT: i32 = 69;
158/// Stale NFS file handle
159pub const ESTALE: i32 = 70;
160/// Too many levels of remote in path
161pub const EREMOTE: i32 = 71;
162/// RPC struct is bad
163pub const EBADRPC: i32 = 72;
164/// RPC version wrong
165pub const ERPCMISMATCH: i32 = 73;
166/// RPC prog. not avail
167pub const EPROGUNAVAIL: i32 = 74;
168/// Program version wrong
169pub const EPROGMISMATCH: i32 = 75;
170/// Bad procedure for program
171pub const EPROCUNAVAIL: i32 = 76;
172/// No locks available
173pub const ENOLCK: i32 = 77;
174/// Function not implemented
175pub const ENOSYS: i32 = 78;
176/// Inappropriate file type or format
177pub const EFTYPE: i32 = 79;
178/// Authentication error
179pub const EAUTH: i32 = 80;
180/// Need authenticator
181pub const ENEEDAUTH: i32 = 81;
182/// Identifier removed
183pub const EIDRM: i32 = 82;
184/// No message of desired type
185pub const ENOMSG: i32 = 83;
186/// Value too large to be stored in data type
187pub const EOVERFLOW: i32 = 84;
188/// Operation canceled
189pub const ECANCELED: i32 = 85;
190/// Illegal byte sequence
191pub const EILSEQ: i32 = 86;
192/// Attribute not found
193pub const ENOATTR: i32 = 87;
194/// Programming error
195pub const EDOOFUS: i32 = 88;
196/// Bad message
197pub const EBADMSG: i32 = 89;
198/// Multihop attempted
199pub const EMULTIHOP: i32 = 90;
200/// Link has been severed
201pub const ENOLINK: i32 = 91;
202/// Protocol error
203pub const EPROTO: i32 = 92;
204/// Capabilities insufficient
205pub const ENOTCAPABLE: i32 = 93;
206/// Not permitted in capability mode
207pub const ECAPMODE: i32 = 94;
208/// State not recoverable
209pub const ENOTRECOVERABLE: i32 = 95;
210/// Previous owner died
211pub const EOWNERDEAD: i32 = 96;
212/// Must be equal largest errno
213pub const ELAST: i32 = 96;
214
215/// # Bash error codes
216/// Uses the range 126-165
217
218/// Command invoked cannot execute
219pub const ENOTEXEC: i32 = 126;
220
221/// Command not found
222pub const ENOCMD: i32 = 127;
223
224/// Invalid argument to exit
225pub const EINVALEXIT: i32 = 128;
226
227/// Terminated by CTRL-C
228pub const ECTRLC: i32 = 130;
229
230/// # My custom errors
231
232/// UTF8 decode/encode error
233pub const EUTF8: i32 = 166;
234
235impl fmt::Display for PosixError {
236    #[inline]
237    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
238        return write!(f, "{}", self.message);
239    }
240}
241
242impl From<std::io::Error> for PosixError {
243    #[inline]
244    fn from(error: std::io::Error) -> Self {
245        match error.kind() {
246            ErrorKind::NotFound => Self {
247                code: ENOENT,
248                message: error.to_string(),
249            },
250            ErrorKind::PermissionDenied => Self {
251                code: EACCES,
252                message: error.to_string(),
253            },
254            ErrorKind::ConnectionRefused => Self {
255                code: ECONNREFUSED,
256                message: error.to_string(),
257            },
258
259            ErrorKind::ConnectionReset => Self {
260                code: ECONNRESET,
261                message: error.to_string(),
262            },
263            ErrorKind::ConnectionAborted => Self {
264                code: ECONNABORTED,
265                message: error.to_string(),
266            },
267            ErrorKind::NotConnected => Self {
268                code: ENOTCONN,
269                message: error.to_string(),
270            },
271            ErrorKind::AddrInUse => Self {
272                code: EADDRINUSE,
273                message: error.to_string(),
274            },
275            ErrorKind::AddrNotAvailable => Self {
276                code: EADDRNOTAVAIL,
277                message: error.to_string(),
278            },
279            ErrorKind::BrokenPipe => Self {
280                code: EPIPE,
281                message: error.to_string(),
282            },
283            ErrorKind::AlreadyExists => Self {
284                code: EEXIST,
285                message: error.to_string(),
286            },
287            ErrorKind::WouldBlock => Self {
288                code: EWOULDBLOCK,
289                message: error.to_string(),
290            },
291            ErrorKind::InvalidInput => Self {
292                code: EINVAL,
293                message: error.to_string(),
294            },
295            ErrorKind::InvalidData => Self {
296                code: EFTYPE,
297                message: error.to_string(),
298            },
299            ErrorKind::TimedOut => Self {
300                code: ETIMEDOUT,
301                message: error.to_string(),
302            },
303            ErrorKind::WriteZero => Self {
304                code: ENOLINK,
305                message: error.to_string(),
306            },
307            ErrorKind::Interrupted => Self {
308                code: EINTR,
309                message: error.to_string(),
310            },
311            ErrorKind::UnexpectedEof => Self {
312                code: ESHUTDOWN,
313                message: error.to_string(),
314            },
315            _ => Self {
316                code: EPERM,
317                message: error.to_string(),
318            },
319        }
320    }
321}
322
323impl From<std::process::Output> for PosixError {
324    #[inline]
325    fn from(output: std::process::Output) -> Self {
326        let tmp = String::from_utf8_lossy(&output.stderr).to_string();
327        let mut code = output.status.code().unwrap_or(1);
328        if code == 0 {
329            // This should not happen, but who knows.
330            code = 1;
331        }
332        Self::new(code, tmp)
333    }
334}
335
336impl PosixError {
337    /// Create a new [`PosixError`]
338    #[must_use]
339    #[inline]
340    pub const fn new(code: i32, message: String) -> Self {
341        Self { code, message }
342    }
343
344    /// Return the posix error code
345    #[must_use]
346    #[inline]
347    pub const fn code(&self) -> i32 {
348        self.code
349    }
350
351    /// Return the error message
352    #[must_use]
353    #[inline]
354    pub fn message(&self) -> String {
355        self.message.clone()
356    }
357}
358
359/// Create new `PosixError`
360#[must_use]
361#[inline]
362pub fn posix_error(code: i32, msg: &str) -> PosixError {
363    PosixError::new(code, msg.to_owned())
364}
365
366/// Convert [`std::io::Error`] to a [`PosixError`]
367#[allow(clippy::needless_pass_by_value)]
368#[deprecated(since = "1.1.0", note = "Please use PosixError::from")]
369#[must_use]
370#[inline]
371pub fn to_posix_error(err: std::io::Error) -> PosixError {
372    PosixError::from(err)
373}
374
375/// Return a [`PosixError`] from a failed [`std::process::Output`]
376#[must_use]
377#[inline]
378#[deprecated(since = "1.1.0", note = "Please use PosixError::from")]
379pub fn error_from_output(output: std::process::Output) -> PosixError {
380    PosixError::from(output)
381}