lints 0.2.0

Writes [lints.rust] to stdout such that all lints are denied or allowed.
extern crate alloc;
use super::{
    Error, ExitCode,
    io::{self, Write as _},
};
#[cfg(target_os = "openbsd")]
use super::{Permissions, Promises, env};
use alloc::string::FromUtf8Error;
#[cfg(target_os = "openbsd")]
use std::{ffi::OsStr, fs, io::ErrorKind};
use std::{
    io::Read as _,
    path::{Path, PathBuf},
    process::{Command, Stdio},
};
/// Error when executing `rustc -Whelp`.
pub(crate) enum E {
    /// I/O error.
    Io(Error),
    /// Error when there is no `$PATH` variable.
    #[cfg(target_os = "openbsd")]
    NoPathVariable,
    /// Error when `"rustc"` is unable to be located in `$PATH`.
    #[cfg(target_os = "openbsd")]
    NoRustcInPath,
    /// `rustc -Whelp` didn't return a status code, and nothing was written to `stderr`.
    NoStatusNoErr,
    /// `rustc -Whelp` didn't return a status code, and invalid UTF-8 was written to `stderr`.
    NoStatusInvalidUtf8(FromUtf8Error),
    /// `rustc -Whelp` didn't return a status code, and the contained `String` was written to `stderr`.
    NoStatusErr(String),
    /// `rustc -Whelp` returned an error code, but nothing was written to `stderr`.
    ErrStatusNoErr(i32),
    /// `rustc -Whelp` returned an error code, but `stderr` contained invalid UTF-8.
    ErrStatusInvalidUtf8(i32, FromUtf8Error),
    /// `rustc -Whelp` returned an error code, and the contained `String` was written to `stderr`.
    ErrStatus(i32, String),
    /// `rustc -Whelp` returned a success code, but `stderr` contained invalid UTF-8.
    SuccessErrInvalidUtf8(FromUtf8Error),
    /// `rustc -Whelp` returned a success code, but the contained `String` was written to `stderr`.
    SuccessErr(String),
}
impl E {
    /// Writes `self` into `stderr`.
    pub(crate) fn into_exit_code(self) -> ExitCode {
        let mut stderr = io::stderr().lock();
        match self {
            Self::Io(err) => writeln!(stderr, "I/O issue: {err}."),
            #[cfg(target_os = "openbsd")]
            Self::NoPathVariable => writeln!(
                stderr,
                "No PATH variable."
            ),
            #[cfg(target_os = "openbsd")]
            Self::NoRustcInPath => writeln!(
                stderr,
                "rustc could not be found based on the PATH variable."
            ),
            Self::NoStatusNoErr => writeln!(
                stderr,
                "rustc -Whelp didn't return a status code but didn't write anything to stderr."
            ),
            Self::NoStatusInvalidUtf8(err) => writeln!(
                stderr,
                "rustc -Whelp didn't return a status code, but stderr contained invalid UTF-8: {err}."
            ),
            Self::NoStatusErr(err) => writeln!(
                stderr,
                "rustc -Whelp didn't return a status code, and the following was written to stderr: {err}."
            ),
            Self::ErrStatusNoErr(code) => writeln!(
                stderr,
                "rustc -Whelp returned status {code}, but didn't write anything to stderr."
            ),
            Self::ErrStatusInvalidUtf8(code, err) => writeln!(
                stderr,
                "rustc -Whelp returned status {code}, but stderr contained invalid UTF-8: {err}."
            ),
            Self::ErrStatus(code, err) => writeln!(
                stderr,
                "rustc -Whelp returned status {code}, and the following was written to stderr: {err}."
            ),
            Self::SuccessErrInvalidUtf8(err) => writeln!(
                stderr,
                "rustc -Whelp returned a successful status code, but stderr contained invalid UTF-8: {err}."
            ),
            Self::SuccessErr(err) => writeln!(
                stderr,
                "rustc -Whelp returned a successful status code, but the following was written to stderr: {err}."
            ),
        }.map_or(ExitCode::FAILURE, |()| ExitCode::FAILURE)
    }
}
/// `"rustc"`.
const RUSTC: &str = "rustc";
/// Returns [`RUSTC`] as a `PathBuf`.
#[expect(clippy::unnecessary_wraps, reason = "unify with OpenBSD")]
#[cfg(not(target_os = "openbsd"))]
fn priv_sep<Never>() -> Result<PathBuf, Never> {
    Ok(RUSTC.into())
}
/// `unveil(2)`s the file system for read-only permissions.
/// Traverses `$PATH` to find `"rustc"`; when found, removes read permissions on the file system before
/// `unveil(2)`ing `"rustc"` with execute permissions. Last, `pledge(2)`s `c"exec proc stdio unveil"`.
#[expect(unsafe_code, reason = "comment justifies correctness")]
#[expect(clippy::option_if_let_else, reason = "false positive")]
#[cfg(target_os = "openbsd")]
fn priv_sep() -> Result<PathBuf, E> {
    Permissions::unveil_raw(c"/", c"r")
        .map_err(|e| E::Io(e.into()))
        .and_then(|()| {
            env::var_os("PATH").map_or(Err(E::NoPathVariable), |path| {
                path.as_encoded_bytes()
                    .split(|b| *b == b':')
                    .try_fold((), |(), dir| {
                        // SAFETY:
                        // `dir` is obtained directly from `path.as_encoded_bytes` with at most a single
                        // `b':'` removed ensuring any valid UTF-8 that existed before still does.
                        let dir_os = unsafe { OsStr::from_encoded_bytes_unchecked(dir) };
                        fs::read_dir(dir_os).map_or_else(
                            |e| {
                                if matches!(e.kind(), ErrorKind::NotADirectory) {
                                    let val = PathBuf::from(dir_os);
                                    match val.file_name() {
                                        None => Ok(()),
                                        Some(file) => {
                                            if file == RUSTC {
                                                Err(val)
                                            } else {
                                                Ok(())
                                            }
                                        }
                                    }
                                } else {
                                    Ok(())
                                }
                            },
                            |mut ents| {
                                ents.try_fold((), |(), ent_res| {
                                    ent_res.map_or(Ok(()), |ent| {
                                        if ent.file_name() == RUSTC {
                                            Err(PathBuf::from(dir_os).join(RUSTC))
                                        } else {
                                            Ok(())
                                        }
                                    })
                                })
                            },
                        )
                    })
                    .map_or_else(
                        |rustc| {
                            Permissions::unveil_raw(c"/", c"")
                                .and_then(|()| {
                                    Permissions::unveil_raw(&rustc, c"x").and_then(|()| {
                                        Promises::pledge_raw(c"exec proc stdio unveil")
                                            .map(|()| rustc)
                                    })
                                })
                                .map_err(|e| E::Io(e.into()))
                        },
                        |()| Err(E::NoRustcInPath),
                    )
            })
        })
}
/// No-op.
#[expect(clippy::unnecessary_wraps, reason = "unify with OpenBSD")]
#[cfg(not(target_os = "openbsd"))]
const fn priv_sep_final<Never>(_: &Path) -> Result<(), Never> {
    Ok(())
}
/// Removes execute permissions on `path` before `pledge(2)`ing `c"stdio"`.
#[cfg(target_os = "openbsd")]
fn priv_sep_final(path: &Path) -> Result<(), E> {
    Permissions::unveil_raw(path, c"")
        .and_then(|()| Promises::pledge_raw(c"stdio"))
        .map_err(|e| E::Io(e.into()))
}
/// No-op.
#[expect(clippy::unnecessary_wraps, reason = "unify with OpenBSD")]
#[cfg(not(target_os = "openbsd"))]
const fn priv_sep_stdin<Never>() -> Result<(), Never> {
    Ok(())
}
/// `pledge(2)`s `c"stdio"`.
#[cfg(target_os = "openbsd")]
fn priv_sep_stdin() -> Result<(), E> {
    Promises::pledge_raw(c"stdio").map_err(|e| E::Io(e.into()))
}
/// Gets output of `rustc -Whelp`.
pub(crate) fn execute(read_stdin: bool) -> Result<Vec<u8>, E> {
    if read_stdin {
        priv_sep_stdin().and_then(|()| {
            let mut output = Vec::with_capacity(0x8000);
            io::stdin()
                .lock()
                .read_to_end(&mut output)
                .map_err(E::Io)
                .map(|_| output)
        })
    } else {
        priv_sep().and_then(|path| {
            Command::new(&path)
                .arg("-Whelp")
                .stderr(Stdio::piped())
                .stdin(Stdio::null())
                .stdout(Stdio::piped())
                .output()
                .map_err(E::Io)
                .and_then(|output| {
                    priv_sep_final(&path).and_then(|()| match output.status.code() {
                        None => {
                            if output.stderr.is_empty() {
                                Err(E::NoStatusNoErr)
                            } else {
                                String::from_utf8(output.stderr)
                                    .map_err(E::NoStatusInvalidUtf8)
                                    .and_then(|err| Err(E::NoStatusErr(err)))
                            }
                        }
                        Some(code) => {
                            if code == 0i32 {
                                if output.stderr.is_empty() {
                                    Ok(output.stdout)
                                } else {
                                    String::from_utf8(output.stderr)
                                        .map_err(E::SuccessErrInvalidUtf8)
                                        .and_then(|err| Err(E::SuccessErr(err)))
                                }
                            } else if output.stderr.is_empty() {
                                Err(E::ErrStatusNoErr(code))
                            } else {
                                String::from_utf8(output.stderr)
                                    .map_err(|err| E::ErrStatusInvalidUtf8(code, err))
                                    .and_then(|err| Err(E::ErrStatus(code, err)))
                            }
                        }
                    })
                })
        })
    }
}
#[cfg(test)]
mod tests {
    #[cfg(not(target_os = "openbsd"))]
    use core::convert::Infallible;
    #[cfg(target_os = "openbsd")]
    use std::ffi::OsString;
    #[test]
    #[cfg(not(target_os = "openbsd"))]
    fn priv_sep() {
        assert_eq!(super::priv_sep::<Infallible>(), Ok("rustc".into()));
    }
    #[ignore = "interferes with testing. should run separately to avoid issues."]
    #[test]
    #[cfg(target_os = "openbsd")]
    fn priv_sep() {
        assert!(super::priv_sep().is_ok_and(
            |path| path.is_absolute() && path.file_name() == Some(&OsString::from("rustc"))
        ));
    }
}