vfs_shadow_copy2: Use VFS interface to derive mount point
[samba4-gss.git] / rust / dbg / src / lib.rs
blob26c513e20299aca6a9a5f68678998f8a653253ae
1 /*
2    Unix SMB/CIFS implementation.
4    Parameter loading functions
6    Copyright (C) David Mulder 2024
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 pub mod ffi {
23     #![allow(non_upper_case_globals)]
24     #![allow(non_camel_case_types)]
25     #![allow(non_snake_case)]
26     #![allow(dead_code)]
27     #![allow(clippy::upper_case_acronyms)]
28     include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
31 pub const MAX_DEBUG_LEVEL: u32 = ffi::MAX_DEBUG_LEVEL;
32 pub const DBGLVL_ERR: u32 = ffi::DBGLVL_ERR;
33 pub const DBGLVL_WARNING: u32 = ffi::DBGLVL_WARNING;
34 pub const DBGLVL_NOTICE: u32 = ffi::DBGLVL_NOTICE;
35 pub const DBGLVL_INFO: u32 = ffi::DBGLVL_INFO;
36 pub const DBGLVL_DEBUG: u32 = ffi::DBGLVL_DEBUG;
38 pub const DEBUG_DEFAULT_STDERR: ffi::debug_logtype =
39     ffi::debug_logtype_DEBUG_DEFAULT_STDERR;
40 pub const DEBUG_DEFAULT_STDOUT: ffi::debug_logtype =
41     ffi::debug_logtype_DEBUG_DEFAULT_STDOUT;
42 pub const DEBUG_FILE: ffi::debug_logtype = ffi::debug_logtype_DEBUG_FILE;
43 pub const DEBUG_STDOUT: ffi::debug_logtype = ffi::debug_logtype_DEBUG_STDOUT;
44 pub const DEBUG_STDERR: ffi::debug_logtype = ffi::debug_logtype_DEBUG_STDERR;
45 pub const DEBUG_CALLBACK: ffi::debug_logtype =
46     ffi::debug_logtype_DEBUG_CALLBACK;
48 pub fn debug_set_logfile(name: &str) {
49     let name_cstr = chelps::wrap_string(name);
50     unsafe {
51         ffi::debug_set_logfile(name_cstr);
52         chelps::string_free(name_cstr);
53     }
56 pub fn setup_logging(prog_name: &str, new_logtype: ffi::debug_logtype) {
57     let prog_name_cstr = chelps::wrap_string(prog_name);
58     unsafe {
59         ffi::setup_logging(prog_name_cstr, new_logtype);
60         chelps::string_free(prog_name_cstr);
61     }
64 pub fn dbgflush() {
65     unsafe {
66         ffi::dbgflush();
67     }
70 #[macro_export]
71 macro_rules! debuglevel_set {
72     ($level:expr) => {{
73         unsafe {
74             $crate::ffi::debuglevel_set_class(
75                 $crate::ffi::DBGC_ALL as usize,
76                 $level as i32,
77             )
78         }
79     }};
82 #[macro_export]
83 macro_rules! DBG_PREFIX {
84     ($level:expr $(, $arg:expr)* $(,)?) => {{
85         if $level <= $crate::ffi::MAX_DEBUG_LEVEL {
86             let location = format!("{}:{}", file!(), line!());
87             let location_cstr = chelps::wrap_string(&location);
88             let function = chelps::function!();
89             let function_msg = format!("{}: ", function);
90             let function_cstr = chelps::wrap_string(&function);
91             let function_msg_cstr = chelps::wrap_string(&function_msg);
92             // Always append a newline to the debug, otherwise it won't flush
93             // to the log.
94             let msg = format!("{}\n", format!($($arg),*));
95             let msg_cstr = chelps::wrap_string(&msg);
96             unsafe {
97                 let _ = $crate::ffi::debuglevel_get_class($crate::ffi::DBGC_CLASS as usize) >= ($level as i32)
98                     && $crate::ffi::dbghdrclass($level as i32,
99                             $crate::ffi::DBGC_CLASS as i32,
100                             location_cstr,
101                             function_cstr)
102                     && $crate::ffi::dbgtext(function_msg_cstr)
103                     && $crate::ffi::dbgtext(msg_cstr);
104                 chelps::string_free(location_cstr);
105                 chelps::string_free(function_cstr);
106                 chelps::string_free(function_msg_cstr);
107                 chelps::string_free(msg_cstr);
108             }
109         }
110     }}
113 #[macro_export]
114 macro_rules! DBG_ERR {
115     ($msg:expr $(, $arg:expr)* $(,)?) => {{
116         $crate::DBG_PREFIX!($crate::ffi::DBGLVL_ERR, $msg, $($arg),*)
117     }}
120 #[macro_export]
121 macro_rules! DBG_WARNING {
122     ($msg:expr $(, $arg:expr)* $(,)?) => {{
123         $crate::DBG_PREFIX!($crate::ffi::DBGLVL_WARNING, $msg, $($arg),*)
124     }}
127 #[macro_export]
128 macro_rules! DBG_NOTICE {
129     ($msg:expr $(, $arg:expr)* $(,)?) => {{
130         $crate::DBG_PREFIX!($crate::ffi::DBGLVL_NOTICE, $msg, $($arg),*)
131     }}
134 #[macro_export]
135 macro_rules! DBG_INFO {
136     ($msg:expr $(, $arg:expr)* $(,)?) => {{
137         $crate::DBG_PREFIX!($crate::ffi::DBGLVL_INFO, $msg, $($arg),*)
138     }}
141 #[macro_export]
142 macro_rules! DBG_DEBUG {
143     ($msg:expr $(, $arg:expr)* $(,)?) => {{
144         $crate::DBG_PREFIX!($crate::ffi::DBGLVL_DEBUG, $msg, $($arg),*)
145     }}
148 #[cfg(test)]
149 mod tests {
150     use super::*;
151     use paste::paste;
152     use std::fs::File;
153     use std::io::Read;
154     use tempfile::NamedTempFile;
156     #[test]
157     fn test_debug_constants() {
158         assert_eq!(MAX_DEBUG_LEVEL, ffi::MAX_DEBUG_LEVEL);
159         assert_eq!(DBGLVL_ERR, ffi::DBGLVL_ERR);
160         assert_eq!(DBGLVL_WARNING, ffi::DBGLVL_WARNING);
161         assert_eq!(DBGLVL_NOTICE, ffi::DBGLVL_NOTICE);
162         assert_eq!(DBGLVL_INFO, ffi::DBGLVL_INFO);
163         assert_eq!(DBGLVL_DEBUG, ffi::DBGLVL_DEBUG);
165         assert_eq!(
166             DEBUG_DEFAULT_STDERR,
167             ffi::debug_logtype_DEBUG_DEFAULT_STDERR
168         );
169         assert_eq!(
170             DEBUG_DEFAULT_STDOUT,
171             ffi::debug_logtype_DEBUG_DEFAULT_STDOUT
172         );
173         assert_eq!(DEBUG_FILE, ffi::debug_logtype_DEBUG_FILE);
174         assert_eq!(DEBUG_STDOUT, ffi::debug_logtype_DEBUG_STDOUT);
175         assert_eq!(DEBUG_STDERR, ffi::debug_logtype_DEBUG_STDERR);
176         assert_eq!(DEBUG_CALLBACK, ffi::debug_logtype_DEBUG_CALLBACK);
177     }
179     macro_rules! test_dbg_macro {
180         ($level:ident) => {
181             paste! {
182                 #[test]
183                 fn [<test_dbg_ $level:lower _macro>]() {
184                     let logfile = NamedTempFile::new().expect("Failed to create temporary file");
185                     let logfile = logfile.path().to_str().unwrap();
186                     setup_logging("test_program", DEBUG_FILE);
187                     debug_set_logfile(logfile);
189                     let logfile_output = concat!("This is a ", stringify!($level), " message");
191                     debuglevel_set!([<DBGLVL_ $level:upper>]);
193                     [<DBG_ $level:upper>]!("{}\n", logfile_output);
194                     dbgflush();
196                     let mut file = File::open(logfile).expect("Failed to open logfile");
197                     let mut logfile_contents = String::new();
198                     file.read_to_string(&mut logfile_contents)
199                         .expect("Failed to read logfile");
200                     assert!(
201                         logfile_contents.contains(logfile_output),
202                         "Test data missing from logfile: {}",
203                         logfile_contents
204                     );
205                 }
206             }
207         };
208     }
210     test_dbg_macro!(DEBUG);
211     // Multiple re-inits of the debug env cause it to fail, so we can't
212     // reliably test all of these in one go.
213     //test_dbg_macro!(INFO);
214     //test_dbg_macro!(NOTICE);
215     //test_dbg_macro!(WARNING);
216     //test_dbg_macro!(ERR);