comparison libpam-sys/libpam-sys-helpers/build.rs @ 136:efbc235f01d3

Separate libpam-sys-helpers from libpam-sys. This separates the parts of libpam-sys that don't need linking against libpam from the parts that do need to link against libpam.
author Paul Fisher <paul@pfish.zone>
date Thu, 03 Jul 2025 14:28:04 -0400
parents libpam-sys/build.rs@6c1e1bdb4164
children
comparison
equal deleted inserted replaced
135:b52594841480 136:efbc235f01d3
1 #![allow(unexpected_cfgs)]
2
3 use std::ffi::{c_void, CString};
4 use std::ptr::NonNull;
5 use std::{env, fs};
6
7 include!("src/pam_impl.rs");
8
9 fn main() {
10 let pam_impl = match option_env!("LIBPAMSYS_IMPL") {
11 // The default option: Guess what PAM impl we're using based on OS.
12 None | Some("") => LibPam::detect(),
13 Some(other) => match PamImpl::try_from(other) {
14 Ok(i) => i,
15 Err(_) => {
16 panic!(
17 "unknown PAM implementation {other:?}. valid LIBPAMSYS_IMPLs are {:?}, or unset to detect", PamImpl::items()
18 )
19 }
20 },
21 };
22 let impl_str = format!("{pam_impl:?}");
23 println!("{}", generate_cfg(&impl_str));
24 // We set this environment variable to substitute into docstrings.
25 println!("cargo:rustc-env=LIBPAMSYS_IMPL={impl_str}");
26 fs::write(
27 format!("{}/pam_impl_const.rs", env::var("OUT_DIR").unwrap()),
28 generate_consts(&impl_str),
29 )
30 .unwrap();
31 }
32
33 fn generate_consts(impl_str: &str) -> String {
34 format!(
35 "\
36 impl PamImpl {{
37 /// The implementation of libpam this was built for (`{impl_str}`).
38 pub const CURRENT: Self = Self::{impl_str};
39 }}
40
41 /// String name of [`PamImpl::CURRENT`], for substituting into docs.
42 #[macro_export]
43 macro_rules! pam_impl_name {{ () => ({impl_str:?}) }}
44 "
45 )
46 }
47
48 struct LibPam(NonNull<c_void>);
49
50 impl LibPam {
51 fn detect() -> PamImpl {
52 if let Some(lib) = Self::open() {
53 if lib.has("pam_syslog") {
54 return PamImpl::LinuxPam;
55 } else if lib.has("_openpam_log") {
56 return PamImpl::OpenPam;
57 } else if lib.has("__pam_get_authtok") {
58 return PamImpl::Sun;
59 }
60 }
61 if cfg!(target_os = "linux") {
62 PamImpl::LinuxPam
63 } else if cfg!(any(
64 target_os = "macos",
65 target_os = "freebsd",
66 target_os = "netbsd",
67 target_os = "dragonfly",
68 target_os = "openbsd",
69 )) {
70 PamImpl::OpenPam
71 } else if cfg!(any(target_os = "illumos", target_os = "solaris")) {
72 PamImpl::Sun
73 } else {
74 PamImpl::XSso
75 }
76 }
77
78 fn open() -> Option<Self> {
79 NonNull::new(unsafe { libc::dlopen(b"libpam.so\0".as_ptr().cast(), libc::RTLD_LAZY) })
80 .map(Self)
81 }
82
83 fn has(&self, name: &str) -> bool {
84 let name = CString::new(name).unwrap();
85 let symbol = unsafe { libc::dlsym(self.0.as_ptr(), name.as_ptr()) };
86 !symbol.is_null()
87 }
88 }
89
90 impl Drop for LibPam {
91 fn drop(&mut self) {
92 unsafe {
93 libc::dlclose(self.0.as_ptr());
94 }
95 }
96 }