Mercurial > crates > nonstick
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 } |