Mercurial > crates > nonstick
comparison libpam-sys/build.rs @ 106:49d9e2b5c189
An irresponsible mix of implementing libpam-sys and other stuff.
| author | Paul Fisher <paul@pfish.zone> |
|---|---|
| date | Thu, 26 Jun 2025 22:41:28 -0400 |
| parents | |
| children | e97534be35e3 |
comparison
equal
deleted
inserted
replaced
| 105:13b4d2a19674 | 106:49d9e2b5c189 |
|---|---|
| 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() { | |
| 50 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 } | |
| 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 } |
