comparison 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
comparison
equal deleted inserted replaced
133:32b2a545ca3e 134:6c1e1bdb4164
1 use libpam_sys_impls::__pam_impl_enum__; 1 #![allow(unexpected_cfgs)]
2 use strum::{EnumIter, IntoEnumIterator};
3 2
4 __pam_impl_enum__!(#[derive(EnumIter)]); 3 use std::env;
4 use std::ffi::{c_void, CString};
5 use std::fs;
6 use std::ptr::NonNull;
7
8 include!("src/pam_impl.rs");
5 9
6 fn main() { 10 fn main() {
7 println!("cargo:rustc-link-lib=pam"); 11 println!("cargo:rustc-link-lib=pam");
8 let pam_impl_strs: Vec<_> = PamImpl::iter().map(|e| format!("\"{:?}\"", e)).collect(); 12
9 let pam_impls = pam_impl_strs.join(","); 13 let pam_impl = match option_env!("LIBPAMSYS_IMPL") {
10 // We use this for ctest. Don't do what we've done; just use cfg_pam_impl. 14 // The default option: Guess what PAM impl we're using based on OS.
11 println!("cargo:rustc-check-cfg=cfg(_hack_impl, values({pam_impls}))"); 15 None | Some("") => detect(),
12 println!("cargo:rustc-cfg=_hack_impl=\"{:?}\"", PamImpl::CURRENT); 16 Some(other) => match PamImpl::try_from(other) {
17 Ok(i) => i,
18 Err(_) => {
19 panic!(
20 "unknown PAM implementation {other:?}. valid LIBPAMSYS_IMPLs are {:?}, or unset to detect", PamImpl::items()
21 )
22 }
23 },
24 };
25 println!("{}", checkcfg());
26 let impl_str = format!("{pam_impl:?}");
27 println!("{}", implcfg(&impl_str));
28 println!("cargo:rustc-env=LIBPAMSYS_IMPL={impl_str}");
29 fs::write(
30 format!("{}/pam_impl_const.rs", env::var("OUT_DIR").unwrap()),
31 format!(
32 "\
33 impl PamImpl {{\
34 /// The implementation of libpam this was built for (`{impl_str}`).
35 pub const CURRENT: Self = Self::{impl_str};\
36 /// String version for internal consumption.
37 const CURRENT_STR: &'static str = {impl_str:?};\
38 }}
39 "
40 ),
41 )
42 .unwrap();
13 } 43 }
44
45 fn detect() -> PamImpl {
46 if let Some(lib) = LibPam::open() {
47 if lib.has("pam_syslog") {
48 return PamImpl::LinuxPam;
49 } else if lib.has("_openpam_log") {
50 return PamImpl::OpenPam;
51 } else if lib.has("__pam_get_authtok") {
52 return PamImpl::Sun;
53 }
54 }
55 if cfg!(target_os = "linux") {
56 PamImpl::LinuxPam
57 } else if cfg!(any(
58 target_os = "macos",
59 target_os = "freebsd",
60 target_os = "netbsd",
61 target_os = "dragonfly",
62 target_os = "openbsd",
63 )) {
64 PamImpl::OpenPam
65 } else if cfg!(any(target_os = "illumos", target_os = "solaris")) {
66 PamImpl::Sun
67 } else {
68 PamImpl::XSso
69 }
70 }
71
72 struct LibPam(NonNull<c_void>);
73
74 impl LibPam {
75 fn open() -> Option<Self> {
76 NonNull::new(unsafe { libc::dlopen(b"libpam.so\0".as_ptr().cast(), libc::RTLD_LAZY) })
77 .map(Self)
78 }
79
80 fn has(&self, name: &str) -> bool {
81 let name = CString::new(name).unwrap();
82 let symbol = unsafe { libc::dlsym(self.0.as_ptr(), name.as_ptr()) };
83 !symbol.is_null()
84 }
85 }
86
87 impl Drop for LibPam {
88 fn drop(&mut self) {
89 unsafe {
90 libc::dlclose(self.0.as_ptr());
91 }
92 }
93 }