Skip to main content

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}