Mercurial > crates > nonstick
diff libpam-sys/build.rs @ 134:6c1e1bdb4164
Use standard #[cfg] directives rather than custom proc macros.
Instead of having to do a bunch of custom parsing and other logic
that tools often choke on, this change introduces an easy way
to depend upon custom #[cfg]s provided by the libpam-sys crate.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Thu, 03 Jul 2025 11:03:36 -0400 |
parents | a632a8874131 |
children | efbc235f01d3 |
line wrap: on
line diff
--- a/libpam-sys/build.rs Wed Jul 02 03:33:09 2025 -0400 +++ b/libpam-sys/build.rs Thu Jul 03 11:03:36 2025 -0400 @@ -1,13 +1,93 @@ -use libpam_sys_impls::__pam_impl_enum__; -use strum::{EnumIter, IntoEnumIterator}; +#![allow(unexpected_cfgs)] -__pam_impl_enum__!(#[derive(EnumIter)]); +use std::env; +use std::ffi::{c_void, CString}; +use std::fs; +use std::ptr::NonNull; + +include!("src/pam_impl.rs"); fn main() { println!("cargo:rustc-link-lib=pam"); - let pam_impl_strs: Vec<_> = PamImpl::iter().map(|e| format!("\"{:?}\"", e)).collect(); - let pam_impls = pam_impl_strs.join(","); - // We use this for ctest. Don't do what we've done; just use cfg_pam_impl. - println!("cargo:rustc-check-cfg=cfg(_hack_impl, values({pam_impls}))"); - println!("cargo:rustc-cfg=_hack_impl=\"{:?}\"", PamImpl::CURRENT); + + let pam_impl = match option_env!("LIBPAMSYS_IMPL") { + // The default option: Guess what PAM impl we're using based on OS. + None | Some("") => detect(), + Some(other) => match PamImpl::try_from(other) { + Ok(i) => i, + Err(_) => { + panic!( + "unknown PAM implementation {other:?}. valid LIBPAMSYS_IMPLs are {:?}, or unset to detect", PamImpl::items() + ) + } + }, + }; + println!("{}", checkcfg()); + let impl_str = format!("{pam_impl:?}"); + println!("{}", implcfg(&impl_str)); + println!("cargo:rustc-env=LIBPAMSYS_IMPL={impl_str}"); + fs::write( + format!("{}/pam_impl_const.rs", env::var("OUT_DIR").unwrap()), + format!( + "\ + impl PamImpl {{\ + /// The implementation of libpam this was built for (`{impl_str}`). + pub const CURRENT: Self = Self::{impl_str};\ + /// String version for internal consumption. + const CURRENT_STR: &'static str = {impl_str:?};\ + }} + " + ), + ) + .unwrap(); } + +fn detect() -> PamImpl { + if let Some(lib) = LibPam::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; + } + } + 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 { + PamImpl::XSso + } +} + +struct LibPam(NonNull<c_void>); + +impl LibPam { + fn open() -> Option<Self> { + NonNull::new(unsafe { libc::dlopen(b"libpam.so\0".as_ptr().cast(), libc::RTLD_LAZY) }) + .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()); + } + } +}