view libpam-sys/src/pam_impl.rs @ 135:b52594841480

Split libpam-sys into its own sub-workspace. Nonstick is basically a normal dependency of libpam-sys. But libpam-sys is integrated packages that should be versioned together.
author Paul Fisher <paul@pfish.zone>
date Thu, 03 Jul 2025 11:14:49 -0400
parents 6c1e1bdb4164
children
line wrap: on
line source

/// An enum that knows its own values.
macro_rules! self_aware_enum {
        (
            $(#[$enumeta:meta])*
            $viz:vis enum $name:ident {
                $(
                    $(#[$itemeta:meta])*
                    $item:ident,
                )*
            }
        ) => {
            $(#[$enumeta])*
            $viz enum $name {
                $(
                    $(#[$itemeta])*
                    $item,
                )*
            }

            // The implementations in this block are private for now
            // to avoid putting a contract into the public API.
            #[allow(dead_code)]
            impl $name {
                /// Iterator over the items in the enum. For internal use.
                fn items() -> Vec<Self> {
                    vec![$(Self::$item),*]
                }

                /// Attempts to parse the enum from the string. For internal use.
                fn try_from(value: &str) -> Result<Self, String> {
                    match value {
                        $(stringify!($item) => Ok(Self::$item),)*
                        _ => Err(value.into()),
                    }
                }
            }
        };
    }

self_aware_enum! {
    /// The PAM implementations supported by `libpam-sys`.
    #[derive(Clone, Copy, Debug, PartialEq, Eq)]
    #[cfg_attr(pam_impl, non_exhaustive)]
    pub enum PamImpl {
        /// [Linux-PAM] is provided by most Linux distributions.
        ///
        /// [Linux-PAM]: https://github.com/linux-pam/linux-pam
        LinuxPam,
        /// [OpenPAM] is used by most BSDs, including Mac OS X.
        ///
        /// [OpenPAM]: https://git.des.dev/OpenPAM/OpenPAM
        OpenPam,
        /// Illumos and Solaris use a derivative of [Sun's implementation][sun].
        ///
        /// [sun]: https://code.illumos.org/plugins/gitiles/illumos-gate/+/refs/heads/master/usr/src/lib/libpam
        Sun,
        /// Only the functionality and constants in [the PAM spec].
        ///
        /// [the PAM spec]: https://pubs.opengroup.org/onlinepubs/8329799/toc.htm
        XSso,
    }
}

#[cfg(pam_impl)]
include!(concat!(env!("OUT_DIR"), "/pam_impl_const.rs"));

/// Generates `cargo` directives for build scripts to enable `cfg(pam_impl)`.
///
/// Print this in your `build.rs` script to be able to use the custom `pam_impl`
/// configuration directive.
///
/// ```
/// // build.rs
/// use libpam_sys::pam_impl;
/// fn main() {
///     println!("{}", pam_impl::enable_pam_impl_cfg())
///
///     // Whatever other stuff you do in your build.rs.
/// }
/// ```
///
/// This will set the current `pam_impl` as well as registering all known
/// PAM implementations with `rustc-check-cfg` so you can easily use them:
///
/// ```
/// #[cfg(pam_impl = "OpenPam")]
/// fn openpam_specific_func(handle: *const libpam_sys::pam_handle) {
///     let environ = libpam_sys::pam_getenvlist(handle);
///     // ...
///     libpam_sys::openpam_free_envlist()
/// }
///
/// // This will give you a warning since "UnknownImpl" is not in the cfg.
/// #[cfg(not(pam_impl = "UnknownImpl"))]
/// fn do_something() {
///     // ...
/// }
/// ```
#[cfg(pam_impl)]
pub fn enable_pam_impl_cfg() -> String {
    format!("{}\n{}", checkcfg(), implcfg(PamImpl::CURRENT_STR))
}

/// Generates the `cargo:rustc-check-cfg` directive to print in build scripts.
fn checkcfg() -> String {
    let impls: Vec<_> = PamImpl::items()
        .into_iter()
        .map(|i| format!(r#""{i:?}""#))
        .collect();
    format!(
        "\
            cargo:rustc-check-cfg=cfg(pam_impl)\n\
            cargo:rustc-check-cfg=cfg(pam_impl, values({impls}))\
        ",
        impls = impls.join(",")
    )
}

fn implcfg(name: &str) -> String {
    format!("cargo:rustc-cfg=pam_impl\ncargo:rustc-cfg=pam_impl={name:?}")
}