linux_errno/
linux-errno.rs

1// Copyright (c) 2022 John Millikin <john@john-millikin.com>
2//
3// Permission to use, copy, modify, and/or distribute this software for any
4// purpose with or without fee is hereby granted.
5//
6// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
7// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
8// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
9// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
10// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
11// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
12// PERFORMANCE OF THIS SOFTWARE.
13//
14// SPDX-License-Identifier: 0BSD
15
16//! This library defines an [Error] struct that represents error numbers
17//! returned from Linux system calls.
18//!
19//! On Linux, error numbers are architecture-specific. The [arch] modules
20//! provide access to error numbers for all supported architectures, and the
21//! top-level module re-exports error numbers for the current target platform.
22
23#![no_std]
24
25use core::{fmt, num};
26
27/// Type for error numbers returned from Linux system calls.
28///
29/// The `Error` type implements `PartialEq` for many integer types, and
30/// (optionally) with the POSIX error numbers defined in the [`posix-errno`]
31/// library.
32///
33/// [`posix-errno`]: https://crates.io/crates/posix-errno
34#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
35pub struct Error(num::NonZeroU16);
36
37impl Error {
38	/// Create a new error from a raw error number. If outside the permitted
39	/// range `[1, 4096)` for Linux error numbers, returns `None`.
40	pub const fn new(errno: u16) -> Option<Error> {
41		if errno > 0xFFF {
42			return errno_out_of_range();
43		}
44		match num::NonZeroU16::new(errno) {
45			Some(n) => Some(Self(n)),
46			None => errno_out_of_range(),
47		}
48	}
49
50	/// Unsafely create a new error from a raw error number, without checking
51	/// whether it's within the permitted range for Linux error numbers.
52	///
53	/// # Safety
54	///
55	/// The caller must ensure that `0 < errno <= 0xFFF`. In particular, it is
56	/// undefined behavior if `errno` is zero.
57	#[inline]
58	pub const unsafe fn new_unchecked(errno: u16) -> Error {
59		Error(num::NonZeroU16::new_unchecked(errno))
60	}
61
62	/// Returns the error number as a primitive `u16`.
63	#[inline]
64	pub const fn get(&self) -> u16 {
65		self.0.get()
66	}
67
68	/// Returns the error number as a [`NonZeroU16`](num::NonZeroU16).
69	#[inline]
70	pub const fn get_nonzero(&self) -> num::NonZeroU16 {
71		self.0
72	}
73}
74
75#[cold]
76#[inline]
77const fn errno_out_of_range() -> Option<Error> {
78	None
79}
80
81impl From<Error> for u16 {
82	#[inline]
83	fn from(err: Error) -> u16 {
84		err.0.get()
85	}
86}
87
88impl From<Error> for num::NonZeroU16 {
89	#[inline]
90	fn from(err: Error) -> num::NonZeroU16 {
91		err.0
92	}
93}
94
95impl From<Error> for u32 {
96	#[inline]
97	fn from(err: Error) -> u32 {
98		err.0.get().into()
99	}
100}
101
102impl From<Error> for num::NonZeroU32 {
103	#[inline]
104	fn from(err: Error) -> num::NonZeroU32 {
105		err.0.into()
106	}
107}
108
109impl From<Error> for i32 {
110	#[inline]
111	fn from(err: Error) -> i32 {
112		err.0.get().into()
113	}
114}
115
116impl From<Error> for num::NonZeroI32 {
117	#[inline]
118	fn from(err: Error) -> num::NonZeroI32 {
119		err.0.into()
120	}
121}
122
123impl From<Error> for u64 {
124	#[inline]
125	fn from(err: Error) -> u64 {
126		err.0.get().into()
127	}
128}
129
130impl From<Error> for num::NonZeroU64 {
131	#[inline]
132	fn from(err: Error) -> num::NonZeroU64 {
133		err.0.into()
134	}
135}
136
137impl From<Error> for i64 {
138	#[inline]
139	fn from(err: Error) -> i64 {
140		err.0.get().into()
141	}
142}
143
144impl From<Error> for num::NonZeroI64 {
145	#[inline]
146	fn from(err: Error) -> num::NonZeroI64 {
147		err.0.into()
148	}
149}
150
151impl fmt::Binary for Error {
152	#[inline]
153	fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
154		self.0.fmt(fmt)
155	}
156}
157
158impl fmt::LowerHex for Error {
159	#[inline]
160	fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
161		self.0.fmt(fmt)
162	}
163}
164
165impl fmt::UpperHex for Error {
166	#[inline]
167	fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
168		self.0.fmt(fmt)
169	}
170}
171
172impl PartialEq<i16> for Error {
173	#[inline]
174	fn eq(&self, other: &i16) -> bool {
175		(*other as u16) == self.0.get()
176	}
177}
178
179impl PartialEq<Error> for i16 {
180	#[inline]
181	fn eq(&self, other: &Error) -> bool {
182		(*self as u16) == other.0.get()
183	}
184}
185
186impl PartialEq<isize> for Error {
187	#[inline]
188	fn eq(&self, other: &isize) -> bool {
189		(*other as usize) == usize::from(self.0.get())
190	}
191}
192
193impl PartialEq<Error> for isize {
194	#[inline]
195	fn eq(&self, other: &Error) -> bool {
196		(*self as usize) == usize::from(other.0.get())
197	}
198}
199
200impl PartialEq<num::NonZeroI16> for Error {
201	#[inline]
202	fn eq(&self, other: &num::NonZeroI16) -> bool {
203		(other.get() as u16) == self.0.get()
204	}
205}
206
207impl PartialEq<Error> for num::NonZeroI16 {
208	#[inline]
209	fn eq(&self, other: &Error) -> bool {
210		(self.get() as u16) == other.0.get()
211	}
212}
213
214impl PartialEq<num::NonZeroIsize> for Error {
215	#[inline]
216	fn eq(&self, other: &num::NonZeroIsize) -> bool {
217		(other.get() as usize) == usize::from(self.0.get())
218	}
219}
220
221impl PartialEq<Error> for num::NonZeroIsize {
222	#[inline]
223	fn eq(&self, other: &Error) -> bool {
224		(self.get() as usize) == usize::from(other.0.get())
225	}
226}
227
228macro_rules! impl_partial_eq {
229	($t:ty) => {
230		impl PartialEq<$t> for Error {
231			#[inline]
232			fn eq(&self, other: &$t) -> bool {
233				<$t>::from(self.0.get()) == *other
234			}
235		}
236
237		impl PartialEq<Error> for $t {
238			#[inline]
239			fn eq(&self, other: &Error) -> bool {
240				<$t>::from(other.0.get()) == *self
241			}
242		}
243	};
244}
245
246macro_rules! impl_partial_eq_nonzero {
247	($t:ty) => {
248		impl PartialEq<$t> for Error {
249			#[inline]
250			fn eq(&self, other: &$t) -> bool {
251				<$t>::from(self.0) == *other
252			}
253		}
254
255		impl PartialEq<Error> for $t {
256			#[inline]
257			fn eq(&self, other: &Error) -> bool {
258				<$t>::from(other.0) == *self
259			}
260		}
261	};
262}
263
264impl_partial_eq!(i32);
265impl_partial_eq!(i64);
266impl_partial_eq!(u16);
267impl_partial_eq!(u32);
268impl_partial_eq!(u64);
269impl_partial_eq!(usize);
270
271impl_partial_eq_nonzero!(num::NonZeroI32);
272impl_partial_eq_nonzero!(num::NonZeroI64);
273impl_partial_eq_nonzero!(num::NonZeroU16);
274impl_partial_eq_nonzero!(num::NonZeroU32);
275impl_partial_eq_nonzero!(num::NonZeroU64);
276impl_partial_eq_nonzero!(num::NonZeroUsize);
277
278macro_rules! errno_constants {
279	( $( $(#[$meta:meta])* $name:ident = $value:literal , )+ ) => {
280		use core::fmt;
281
282		$(
283			$(#[$meta])*
284			pub const $name: $crate::Error = unsafe {
285				$crate::Error::new_unchecked($value)
286			};
287		)*
288
289		#[inline]
290		pub(crate) const fn err_name(err: $crate::Error) -> Option<&'static str> {
291			match err.0.get() {
292			$(
293				$value => Some(stringify!($name)),
294			)*
295				_ => None,
296			}
297		}
298	}
299}
300
301#[path = "linux-errno_generic.rs"]
302mod arch_generic;
303
304#[path = "linux-errno_alpha.rs"]
305mod arch_alpha;
306
307#[path = "linux-errno_mips.rs"]
308mod arch_mips;
309
310#[path = "linux-errno_parisc.rs"]
311mod arch_parisc;
312
313#[path = "linux-errno_sparc.rs"]
314mod arch_sparc;
315
316/// Linux error numbers for specific target architectures.
317pub mod arch {
318	/// Linux error numbers for the `alpha` architecture.
319	#[cfg(any(target_arch = "alpha", doc))]
320	pub mod alpha {
321		pub use crate::arch_alpha::*;
322	}
323
324	/// Linux error numbers for the `arm` and `aarch64` architectures.
325	#[cfg(any(
326		target_arch = "arm",
327		target_arch = "aarch64",
328		doc,
329	))]
330	pub mod arm {
331		pub use crate::arch_generic::*;
332	}
333
334	/// Linux error numbers for the `m68k` architecture.
335	#[cfg(any(target_arch = "m68k", doc))]
336	pub mod m68k {
337		pub use crate::arch_generic::*;
338	}
339
340	/// Linux error numbers for the `mips` and `mips64` architectures.
341	#[cfg(any(
342		target_arch = "mips",
343		target_arch = "mips64",
344		doc,
345	))]
346	pub mod mips {
347		pub use crate::arch_mips::*;
348	}
349
350	/// Linux error numbers for the `powerpc` and `powerpc64` architectures.
351	#[cfg(any(
352		target_arch = "powerpc",
353		target_arch = "powerpc64",
354		doc,
355	))]
356	pub mod powerpc {
357		pub use crate::arch_generic::*;
358
359		/// File locking deadlock error
360		pub const EDEADLOCK: crate::Error = unsafe {
361			crate::Error::new_unchecked(58)
362		};
363
364		#[inline]
365		pub(crate) const fn err_name(err: crate::Error) -> Option<&'static str> {
366			if err.0.get() == EDEADLOCK.0.get() {
367				return Some(stringify!("EDEADLOCK"));
368			}
369			crate::arch_generic::err_name(err)
370		}
371	}
372
373	/// Linux error numbers for the `parisc` architecture.
374	#[cfg(any(target_arch = "parisc", doc))]
375	pub mod parisc {
376		pub use crate::arch_parisc::*;
377	}
378
379	/// Linux error numbers for the `riscv32` and `riscv64` architectures.
380	#[cfg(any(
381		target_arch = "riscv32",
382		target_arch = "riscv64",
383		doc,
384	))]
385	pub mod riscv32 {
386		pub use crate::arch_generic::*;
387	}
388
389	/// Linux error numbers for the `s390x` architecture.
390	#[cfg(any(target_arch = "s390x", doc))]
391	pub mod s390x {
392		pub use crate::arch_generic::*;
393	}
394
395	/// Linux error numbers for the `sparc` and `sparc64` architectures.
396	#[cfg(any(
397		target_arch = "sparc",
398		target_arch = "sparc64",
399		doc,
400	))]
401	pub mod sparc {
402		pub use crate::arch_sparc::*;
403	}
404
405	/// Linux error numbers for the `x86` and `x86_64` architectures.
406	#[cfg(any(
407		target_arch = "x86",
408		target_arch = "x86_64",
409		doc,
410	))]
411	pub mod x86 {
412		pub use crate::arch_generic::*;
413	}
414}
415
416#[cfg(target_arch = "alpha")]
417use crate::arch::alpha as target;
418
419#[cfg(any(
420	target_arch = "arm",
421	target_arch = "aarch64",
422))]
423use crate::arch::arm as target;
424
425#[cfg(any(
426	target_arch = "mips",
427	target_arch = "mips64",
428))]
429use crate::arch::mips as target;
430
431#[cfg(any(
432	target_arch = "powerpc",
433	target_arch = "powerpc64",
434))]
435use crate::arch::powerpc as target;
436
437#[cfg(target_arch = "parisc")]
438use crate::arch::parisc as target;
439
440#[cfg(any(
441	target_arch = "riscv32",
442	target_arch = "riscv64",
443))]
444use crate::arch::riscv32 as target;
445
446#[cfg(target_arch = "s390x")]
447use crate::arch::s390x as target;
448
449#[cfg(any(
450	target_arch = "sparc",
451	target_arch = "sparc64",
452))]
453use crate::arch::sparc as target;
454
455#[cfg(any(
456	target_arch = "x86",
457	target_arch = "x86_64",
458))]
459use crate::arch::x86 as target;
460
461#[doc(inline)]
462pub use crate::target::*;
463
464impl fmt::Debug for Error {
465	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
466		match crate::target::err_name(*self) {
467			Some(name) => f.write_str(name),
468			_ => f.debug_tuple("Error").field(&self.0.get()).finish(),
469		}
470	}
471}
472
473#[cfg(feature = "posix-traits")]
474const fn from_posix(err: posix_errno::Error) -> Option<Error> {
475	use posix_errno::Error as P;
476	match err {
477		P::E2BIG           => Some(target::E2BIG),
478		P::EACCES          => Some(target::EACCES),
479		P::EADDRINUSE      => Some(target::EADDRINUSE),
480		P::EADDRNOTAVAIL   => Some(target::EADDRNOTAVAIL),
481		P::EAFNOSUPPORT    => Some(target::EAFNOSUPPORT),
482		P::EAGAIN          => Some(target::EAGAIN),
483		P::EALREADY        => Some(target::EALREADY),
484		P::EBADF           => Some(target::EBADF),
485		P::EBADMSG         => Some(target::EBADMSG),
486		P::EBUSY           => Some(target::EBUSY),
487		P::ECANCELED       => Some(target::ECANCELED),
488		P::ECHILD          => Some(target::ECHILD),
489		P::ECONNABORTED    => Some(target::ECONNABORTED),
490		P::ECONNREFUSED    => Some(target::ECONNREFUSED),
491		P::ECONNRESET      => Some(target::ECONNRESET),
492		P::EDEADLK         => Some(target::EDEADLK),
493		P::EDESTADDRREQ    => Some(target::EDESTADDRREQ),
494		P::EDOM            => Some(target::EDOM),
495		P::EDQUOT          => Some(target::EDQUOT),
496		P::EEXIST          => Some(target::EEXIST),
497		P::EFAULT          => Some(target::EFAULT),
498		P::EFBIG           => Some(target::EFBIG),
499		P::EHOSTUNREACH    => Some(target::EHOSTUNREACH),
500		P::EIDRM           => Some(target::EIDRM),
501		P::EILSEQ          => Some(target::EILSEQ),
502		P::EINPROGRESS     => Some(target::EINPROGRESS),
503		P::EINTR           => Some(target::EINTR),
504		P::EINVAL          => Some(target::EINVAL),
505		P::EIO             => Some(target::EIO),
506		P::EISCONN         => Some(target::EISCONN),
507		P::EISDIR          => Some(target::EISDIR),
508		P::ELOOP           => Some(target::ELOOP),
509		P::EMFILE          => Some(target::EMFILE),
510		P::EMLINK          => Some(target::EMLINK),
511		P::EMSGSIZE        => Some(target::EMSGSIZE),
512		P::EMULTIHOP       => Some(target::EMULTIHOP),
513		P::ENAMETOOLONG    => Some(target::ENAMETOOLONG),
514		P::ENETDOWN        => Some(target::ENETDOWN),
515		P::ENETRESET       => Some(target::ENETRESET),
516		P::ENETUNREACH     => Some(target::ENETUNREACH),
517		P::ENFILE          => Some(target::ENFILE),
518		P::ENOBUFS         => Some(target::ENOBUFS),
519		P::ENODATA         => Some(target::ENODATA),
520		P::ENODEV          => Some(target::ENODEV),
521		P::ENOENT          => Some(target::ENOENT),
522		P::ENOEXEC         => Some(target::ENOEXEC),
523		P::ENOLCK          => Some(target::ENOLCK),
524		P::ENOLINK         => Some(target::ENOLINK),
525		P::ENOMEM          => Some(target::ENOMEM),
526		P::ENOMSG          => Some(target::ENOMSG),
527		P::ENOPROTOOPT     => Some(target::ENOPROTOOPT),
528		P::ENOSPC          => Some(target::ENOSPC),
529		P::ENOSR           => Some(target::ENOSR),
530		P::ENOSTR          => Some(target::ENOSTR),
531		P::ENOSYS          => Some(target::ENOSYS),
532		P::ENOTCONN        => Some(target::ENOTCONN),
533		P::ENOTDIR         => Some(target::ENOTDIR),
534		P::ENOTEMPTY       => Some(target::ENOTEMPTY),
535		P::ENOTRECOVERABLE => Some(target::ENOTRECOVERABLE),
536		P::ENOTSOCK        => Some(target::ENOTSOCK),
537		P::ENOTSUP         => None,
538		P::ENOTTY          => Some(target::ENOTTY),
539		P::ENXIO           => Some(target::ENXIO),
540		P::EOPNOTSUPP      => Some(target::EOPNOTSUPP),
541		P::EOVERFLOW       => Some(target::EOVERFLOW),
542		P::EOWNERDEAD      => Some(target::EOWNERDEAD),
543		P::EPERM           => Some(target::EPERM),
544		P::EPIPE           => Some(target::EPIPE),
545		P::EPROTO          => Some(target::EPROTO),
546		P::EPROTONOSUPPORT => Some(target::EPROTONOSUPPORT),
547		P::EPROTOTYPE      => Some(target::EPROTOTYPE),
548		P::ERANGE          => Some(target::ERANGE),
549		P::EROFS           => Some(target::EROFS),
550		P::ESPIPE          => Some(target::ESPIPE),
551		P::ESRCH           => Some(target::ESRCH),
552		P::ESTALE          => Some(target::ESTALE),
553		P::ETIME           => Some(target::ETIME),
554		P::ETIMEDOUT       => Some(target::ETIMEDOUT),
555		P::ETXTBSY         => Some(target::ETXTBSY),
556		P::EWOULDBLOCK     => Some(target::EWOULDBLOCK),
557		P::EXDEV           => Some(target::EXDEV),
558		_ => None,
559	}
560}
561
562#[cfg(any(feature = "posix-traits", doc))]
563impl PartialEq<posix_errno::Error> for Error {
564	#[inline]
565	fn eq(&self, other: &posix_errno::Error) -> bool {
566		from_posix(*other) == Some(*self)
567	}
568}
569
570#[cfg(any(feature = "posix-traits", doc))]
571impl PartialEq<Error> for posix_errno::Error {
572	#[inline]
573	fn eq(&self, other: &Error) -> bool {
574		from_posix(*self) == Some(*other)
575	}
576}