Mercurial > crates > nonstick
view libpam-sys/libpam-sys-consts/build.rs @ 171:e27c5c667a5a
Create full new types for return code and flags, separate end to end.
This plumbs the ReturnCode and RawFlags types through the places where
we call into or are called from PAM.
Also adds Sun documentation to the project.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Fri, 25 Jul 2025 20:52:14 -0400 |
parents | 09dff285ff5e |
children | 46e8ce5cd5d1 |
line wrap: on
line source
#![allow(unexpected_cfgs)] use std::ffi::{c_void, CString}; use std::ptr::NonNull; use std::{env, fs}; include!("src/pam_impl.rs"); /// The strategy to use to detect PAM. enum Detect { /// Use the default PAM implementation based on the OS, /// or the currently-installed version if the OS is not recognized. TargetDefault, /// Detect the installed implementation. Installed, /// Use the named version of PAM. Specified(PamImpl), } const INSTALLED: &str = "__installed__"; fn main() { let detection = match option_env!("LIBPAMSYS_IMPL") { Some("") | None => Detect::TargetDefault, Some(INSTALLED) => Detect::Installed, Some(val) => Detect::Specified(PamImpl::try_from(val).unwrap_or_else(|_| { panic!( "unknown PAM implementation {val:?}. \ valid LIBPAMSYS_IMPLs are {:?}, \ {INSTALLED:?} to use the OS default, \ or unset to detect", PamImpl::items() ) })), }; let pam_impl = match detection { Detect::TargetDefault => LibPam::target_default(), Detect::Installed => LibPam::probe_detect(), Detect::Specified(other) => other, }; let impl_str = format!("{pam_impl:?}"); println!("{}", generate_cfg(&impl_str)); // We set this environment variable to substitute into docstrings. println!("cargo:rustc-env=LIBPAMSYS_IMPL={impl_str}"); fs::write( format!("{}/pam_impl_const.rs", env::var("OUT_DIR").unwrap()), generate_consts(&impl_str), ) .unwrap(); } fn generate_consts(impl_str: &str) -> String { format!( "\ impl PamImpl {{ /// The implementation of libpam this was built for (`{impl_str}`). pub const CURRENT: Self = Self::{impl_str}; }} /// String name of [`PamImpl::CURRENT`], for substituting into docs. #[macro_export] macro_rules! pam_impl_name {{ () => ({impl_str:?}) }} " ) } struct LibPam(NonNull<c_void>); impl LibPam { /// Guess the PAM implementation based on the current OS. fn target_default() -> PamImpl { if cfg!(target_os = "linux") { PamImpl::LinuxPam } else if cfg!(any( target_os = "macos", target_os = "freebsd", target_os = "netbsd", target_os = "dragonfly", target_os = "openbsd", )) { PamImpl::OpenPam } else if cfg!(any(target_os = "illumos", target_os = "solaris")) { PamImpl::Sun } else { Self::probe_detect() } } /// Look at the currently-installed LibPAM. fn probe_detect() -> PamImpl { if let Some(lib) = Self::open() { if lib.has("pam_syslog") { return PamImpl::LinuxPam; } else if lib.has("_openpam_log") { return PamImpl::OpenPam; } else if lib.has("__pam_get_authtok") { return PamImpl::Sun; } } // idk PamImpl::XSso } fn open() -> Option<Self> { let dlopen = |s: &[u8]| unsafe { libc::dlopen(s.as_ptr().cast(), libc::RTLD_LAZY) }; NonNull::new(dlopen(b"libpam.so\0")) .or_else(|| NonNull::new(dlopen(b"libpam.dylib\0"))) .map(Self) } fn has(&self, name: &str) -> bool { let name = CString::new(name).unwrap(); let symbol = unsafe { libc::dlsym(self.0.as_ptr(), name.as_ptr()) }; !symbol.is_null() } } impl Drop for LibPam { fn drop(&mut self) { unsafe { libc::dlclose(self.0.as_ptr()); } } }