comparison libpam-sys/libpam-sys-consts/build.rs @ 158:d5b7b28d754e

Add `__TARGET_DEFAULT__` PamImpl and set up for docsrs build. Also fixes some formatting stuff.
author Paul Fisher <paul@pfish.zone>
date Sat, 12 Jul 2025 17:17:37 -0400
parents 4b3a5095f68c
children 09dff285ff5e
comparison
equal deleted inserted replaced
157:0099f2f79f86 158:d5b7b28d754e
4 use std::ptr::NonNull; 4 use std::ptr::NonNull;
5 use std::{env, fs}; 5 use std::{env, fs};
6 6
7 include!("src/pam_impl.rs"); 7 include!("src/pam_impl.rs");
8 8
9 /// The strategy to use to detect PAM.
10 enum Detect {
11 /// Automatically detect PAM, using the installed implementation if present
12 /// or the OS default if not.
13 Auto,
14 /// Use the default PAM implementation based on the OS.
15 TargetDefault,
16 /// Use the named version of PAM.
17 Specified(PamImpl),
18 }
19
20 const TARGET_DEFAULT: &str = "__TARGET_DEFAULT__";
21
9 fn main() { 22 fn main() {
10 let pam_impl = match option_env!("LIBPAMSYS_IMPL") { 23 let detection = match option_env!("LIBPAMSYS_IMPL") {
11 // The default option: Guess what PAM impl we're using based on OS. 24 None | Some("") => match option_env!("DOCS_RS") {
12 None | Some("") => LibPam::detect(), 25 // docs.rs cross-compiles, so we don't want to look at
13 Some(other) => match PamImpl::try_from(other) { 26 // its currently-installed PAM; instead we want to use the OS.
14 Ok(i) => i, 27 Some(_) => Detect::TargetDefault,
15 Err(_) => { 28 // In other cases, just auto-detect the actual installed library.
16 panic!( 29 None => Detect::Auto,
17 "unknown PAM implementation {other:?}. valid LIBPAMSYS_IMPLs are {:?}, or unset to detect", PamImpl::items()
18 )
19 }
20 }, 30 },
31 Some(TARGET_DEFAULT) => Detect::TargetDefault,
32 Some(val) => Detect::Specified(PamImpl::try_from(val).unwrap_or_else(|_| {
33 panic!(
34 "unknown PAM implementation {val:?}. \
35 valid LIBPAMSYS_IMPLs are {:?}, \
36 {TARGET_DEFAULT:?} to use the OS default, \
37 or unset to detect",
38 PamImpl::items()
39 )
40 })),
41 };
42 let pam_impl = match detection {
43 Detect::Auto => LibPam::probe_detect(),
44 Detect::TargetDefault => LibPam::os_default(),
45 Detect::Specified(other) => other,
21 }; 46 };
22 let impl_str = format!("{pam_impl:?}"); 47 let impl_str = format!("{pam_impl:?}");
23 println!("{}", generate_cfg(&impl_str)); 48 println!("{}", generate_cfg(&impl_str));
24 // We set this environment variable to substitute into docstrings. 49 // We set this environment variable to substitute into docstrings.
25 println!("cargo:rustc-env=LIBPAMSYS_IMPL={impl_str}"); 50 println!("cargo:rustc-env=LIBPAMSYS_IMPL={impl_str}");
46 } 71 }
47 72
48 struct LibPam(NonNull<c_void>); 73 struct LibPam(NonNull<c_void>);
49 74
50 impl LibPam { 75 impl LibPam {
51 fn detect() -> PamImpl { 76 /// Look at the currently-installed LibPAM, or use [`Self::os_default`]
77 /// if absent.
78 fn probe_detect() -> PamImpl {
52 if let Some(lib) = Self::open() { 79 if let Some(lib) = Self::open() {
53 if lib.has("pam_syslog") { 80 if lib.has("pam_syslog") {
54 return PamImpl::LinuxPam; 81 return PamImpl::LinuxPam;
55 } else if lib.has("_openpam_log") { 82 } else if lib.has("_openpam_log") {
56 return PamImpl::OpenPam; 83 return PamImpl::OpenPam;
57 } else if lib.has("__pam_get_authtok") { 84 } else if lib.has("__pam_get_authtok") {
58 return PamImpl::Sun; 85 return PamImpl::Sun;
59 } 86 }
60 } 87 }
88 Self::os_default()
89 }
90
91 /// Guess the PAM implementation based on the current OS.
92 fn os_default() -> PamImpl {
61 if cfg!(target_os = "linux") { 93 if cfg!(target_os = "linux") {
62 PamImpl::LinuxPam 94 PamImpl::LinuxPam
63 } else if cfg!(any( 95 } else if cfg!(any(
64 target_os = "macos", 96 target_os = "macos",
65 target_os = "freebsd", 97 target_os = "freebsd",
74 PamImpl::XSso 106 PamImpl::XSso
75 } 107 }
76 } 108 }
77 109
78 fn open() -> Option<Self> { 110 fn open() -> Option<Self> {
79 NonNull::new(unsafe { libc::dlopen(b"libpam.so\0".as_ptr().cast(), libc::RTLD_LAZY) }) 111 let dlopen = |s: &[u8]| unsafe { libc::dlopen(s.as_ptr().cast(), libc::RTLD_LAZY) };
112 NonNull::new(dlopen(b"libpam.so\0"))
113 .or_else(|| NonNull::new(dlopen(b"libpam.dylib\0")))
80 .map(Self) 114 .map(Self)
81 } 115 }
82 116
83 fn has(&self, name: &str) -> bool { 117 fn has(&self, name: &str) -> bool {
84 let name = CString::new(name).unwrap(); 118 let name = CString::new(name).unwrap();