change_user_run/error.rs
1//! Error handling.
2
3use std::{path::PathBuf, process::ExitStatus, str::Utf8Error};
4
5/// An error that may occur when creating users or running a command as different user.
6#[derive(Debug, thiserror::Error)]
7pub enum Error {
8 /// The environment variable CARGO_LLVM_COV_TARGET_DIR is not set.
9 #[error("The environment variable CARGO_LLVM_COV_TARGET_DIR is not set")]
10 CargoLlvmCovTargetDirNotSet,
11
12 /// Unable to attach to stdin of a command.
13 #[error("Unable to attach to stdin of command \"{command}\"")]
14 CommandAttachToStdin {
15 /// The command for which attaching to stdin failed.
16 command: String,
17 },
18
19 /// A command exited unsuccessfully.
20 #[error("The command \"{command}\" could not be started in the background:\n{source}")]
21 CommandBackground {
22 /// The command that could not be started in the background.
23 command: String,
24 /// The source error.
25 source: std::io::Error,
26 },
27
28 /// A command could not be executed.
29 #[error("The command \"{command}\" could not be executed:\n{source}")]
30 CommandExec {
31 /// The command that could not be executed.
32 command: String,
33 /// The source error.
34 source: std::io::Error,
35 },
36
37 /// A command exited unsuccessfully.
38 #[error(
39 "The command \"{command}\" exited with non-zero status code \"{exit_status}\":\nstderr:\n{stderr}"
40 )]
41 CommandNonZero {
42 /// The command that exited with a non-zero exit code.
43 command: String,
44 /// The exit status of `command`.
45 exit_status: ExitStatus,
46 /// The stderr of `command`.
47 stderr: String,
48 },
49
50 /// Unable to write to stdin of a command.
51 #[error("Unable to write to stdin of command \"{command}\"")]
52 CommandWriteToStdin {
53 /// The command for which writing to stdin failed.
54 command: String,
55 /// The source error.
56 source: std::io::Error,
57 },
58
59 /// An executable that is supposed to be called, is not found.
60 #[error("Unable to to find executable \"{command}\"")]
61 ExecutableNotFound {
62 /// The executable that could not be found.
63 command: String,
64 /// The source error.
65 source: which::Error,
66 },
67
68 /// An I/O error.
69 #[error("I/O error while {context}:\n{source}")]
70 Io {
71 /// The short description of the operation.
72 context: String,
73
74 /// The source error.
75 source: std::io::Error,
76 },
77
78 /// An I/O error with a specific path.
79 #[error("I/O error at {path} while {context}:\n{source}")]
80 IoPath {
81 /// The file that was being accessed.
82 path: PathBuf,
83
84 /// The short description of the operation.
85 context: String,
86
87 /// The source error.
88 source: std::io::Error,
89 },
90
91 /// A password hash error occurred.
92 #[error("Password hash error while {context}: {source}")]
93 PasswordHash {
94 /// The context in which the error occurred.
95 ///
96 /// This is meant to complete the sentence "Password hash error while ".
97 context: String,
98
99 /// The source error.
100 source: yescrypt::password_hash::Error,
101 },
102
103 /// A UTF-8 error occurred when trying to convert a byte vector to a string.
104 #[error("Converting a byte vector to a string failed while {context}:\n{source}")]
105 Utf8String {
106 /// The context in which the error occurred.
107 ///
108 /// Should complete the sentence "Converting a byte vector to a string failed while ".
109 context: String,
110 /// The source error.
111 source: Utf8Error,
112 },
113}
114
115/// An interface for error variants that internally rely on [`std::io::Error`].
116pub trait IoError<T> {
117 /// Map this error to a an Error variant, that offers a descriptive `context`.
118 fn map_io_err(self, context: impl ToString) -> Result<T, Error>;
119
120 /// Map this error to a an Error variant, that offers a descriptive `context` and a `path`.
121 fn map_io_path_err(self, path: impl Into<PathBuf>, context: impl ToString) -> Result<T, Error>;
122}
123
124impl<T> IoError<T> for std::io::Result<T> {
125 fn map_io_path_err(self, path: impl Into<PathBuf>, context: impl ToString) -> Result<T, Error> {
126 self.map_err(|source| Error::IoPath {
127 path: path.into(),
128 context: context.to_string(),
129 source,
130 })
131 }
132
133 fn map_io_err(self, context: impl ToString) -> Result<T, Error> {
134 self.map_err(|source| Error::Io {
135 context: context.to_string(),
136 source,
137 })
138 }
139}