Mercurial > crates > nonstick
comparison libpam-sys/build.rs @ 108:e97534be35e3
Make some proc macros for doing cfg-like stuff for PAM impls.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Sat, 28 Jun 2025 00:34:45 -0400 |
parents | 49d9e2b5c189 |
children |
comparison
equal
deleted
inserted
replaced
107:49c6633f6fd2 | 108:e97534be35e3 |
---|---|
1 use bindgen::MacroTypeVariation; | |
2 use std::error::Error; | |
3 use std::fmt::{Debug, Display, Formatter}; | |
4 use std::path::PathBuf; | |
5 use std::{env, fs}; | |
6 | |
7 enum PamImpl { | |
8 Illumos, | |
9 LinuxPam, | |
10 OpenPam, | |
11 } | |
12 | |
13 #[derive(Debug)] | |
14 struct InvalidEnum(String); | |
15 | |
16 impl Display for InvalidEnum { | |
17 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | |
18 write!(f, "invalid PAM impl {:?}", self.0) | |
19 } | |
20 } | |
21 | |
22 impl Error for InvalidEnum {} | |
23 | |
24 impl TryFrom<&str> for PamImpl { | |
25 type Error = InvalidEnum; | |
26 fn try_from(value: &str) -> Result<Self, Self::Error> { | |
27 Ok(match value { | |
28 "illumos" => Self::Illumos, | |
29 "linux-pam" => Self::LinuxPam, | |
30 "openpam" => Self::OpenPam, | |
31 other => return Err(InvalidEnum(other.to_owned())), | |
32 }) | |
33 } | |
34 } | |
35 | |
36 impl Debug for PamImpl { | |
37 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | |
38 Debug::fmt( | |
39 match self { | |
40 Self::Illumos => "illumos", | |
41 Self::LinuxPam => "linux-pam", | |
42 Self::OpenPam => "openpam", | |
43 }, | |
44 f, | |
45 ) | |
46 } | |
47 } | |
48 | |
49 fn main() { | 1 fn main() { |
50 println!("cargo:rustc-link-lib=pam"); | 2 println!("cargo:rustc-link-lib=pam"); |
51 let out_file = PathBuf::from(env::var("OUT_DIR").unwrap()).join("constants.rs"); | |
52 let pam_impl = do_detection(); | |
53 | |
54 if cfg!(feature = "use-system-headers") { | |
55 let builder = bindgen::Builder::default() | |
56 .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) | |
57 .blocklist_function(".*") | |
58 .blocklist_type(".*") | |
59 .allowlist_var(".*") | |
60 .default_macro_constant_type(MacroTypeVariation::Unsigned); | |
61 | |
62 let builder = match pam_impl { | |
63 PamImpl::Illumos => builder.header_contents( | |
64 "illumos.h", | |
65 "\ | |
66 #include <security/pam_appl.h> | |
67 #include <security/pam_modules.h> | |
68 ", | |
69 ), | |
70 PamImpl::LinuxPam => builder.header_contents( | |
71 "linux-pam.h", | |
72 "\ | |
73 #include <security/_pam_types.h> | |
74 #include <security/pam_appl.h> | |
75 #include <security/pam_ext.h> | |
76 #include <security/pam_modules.h> | |
77 ", | |
78 ), | |
79 PamImpl::OpenPam => builder.header_contents( | |
80 "openpam.h", | |
81 "\ | |
82 #include <security/pam_types.h> | |
83 #include <security/openpam.h> | |
84 #include <security/pam_appl.h> | |
85 #include <security/pam_constants.h> | |
86 ", | |
87 ), | |
88 }; | |
89 let bindings = builder.generate().unwrap(); | |
90 bindings.write_to_file(out_file).unwrap(); | |
91 } else { | |
92 // Just write empty data to the file to avoid conditional compilation | |
93 // shenanigans. | |
94 fs::write(out_file, "").unwrap(); | |
95 } | |
96 } | 3 } |
97 | |
98 fn do_detection() -> PamImpl { | |
99 println!(r#"cargo:rustc-check-cfg=cfg(pam_impl, values("illumos", "linux-pam", "openpam"))"#); | |
100 let pam_impl = _detect_internal(); | |
101 println!("cargo:rustc-cfg=pam_impl={pam_impl:?}"); | |
102 pam_impl | |
103 } | |
104 | |
105 fn _detect_internal() -> PamImpl { | |
106 if let Some(pam_impl) = option_env!("LIBPAMSYS_PAM_IMPL") { | |
107 pam_impl.try_into().unwrap() | |
108 } else if cfg!(feature = "use-system-headers") { | |
109 // Detect which impl it is from system headers. | |
110 if header_exists("security/_pam_types.h") { | |
111 PamImpl::LinuxPam | |
112 } else if header_exists("security/openpam.h") { | |
113 PamImpl::OpenPam | |
114 } else if header_exists("security/pam_appl.h") { | |
115 PamImpl::Illumos | |
116 } else { | |
117 panic!("could not detect PAM implementation") | |
118 } | |
119 } else { | |
120 // Otherwise, guess what PAM impl we're using based on the OS. | |
121 if cfg!(target_os = "linux") { | |
122 PamImpl::LinuxPam | |
123 } else if cfg!(any( | |
124 target_os = "macos", | |
125 target_os = "freebsd", | |
126 target_os = "netbsd", | |
127 target_os = "dragonfly", | |
128 target_os = "openbsd" | |
129 )) { | |
130 PamImpl::OpenPam | |
131 } else { | |
132 PamImpl::Illumos | |
133 } | |
134 } | |
135 } | |
136 | |
137 fn header_exists(header: &str) -> bool { | |
138 bindgen::Builder::default() | |
139 .blocklist_item(".*") | |
140 .header_contents("header.h", &format!("#include <{header}>")) | |
141 .generate() | |
142 .is_ok() | |
143 } |