pub(crate) fn init_logger(log_file: Option<&std::path::Path>, redirect_stderr: bool) {
let mut builder = env_logger::Builder::from_default_env();
if let Some(path) = log_file {
let mut opts = std::fs::OpenOptions::new();
opts.create(true).append(true);
#[cfg(unix)]
{
use std::os::unix::fs::OpenOptionsExt;
opts.mode(0o600);
opts.custom_flags(libc::O_NOFOLLOW);
}
match opts.open(path) {
Ok(file) => {
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let perms = std::fs::Permissions::from_mode(0o600);
if let Err(e) = file.set_permissions(perms) {
eprintln!(
"Warning: could not set permissions on log file {}: {e}",
path.display()
);
}
}
if redirect_stderr {
redirect_stderr_to_file(&file);
}
builder.target(env_logger::Target::Pipe(Box::new(file)));
}
Err(e) => {
eprintln!("Warning: could not open log file {}: {e}", path.display());
eprintln!(" Falling back to stderr.");
}
}
}
builder.init();
}
#[cfg(unix)]
fn redirect_stderr_to_file(file: &std::fs::File) {
use std::os::unix::io::AsRawFd;
let fd = file.as_raw_fd();
let ret = unsafe { libc::dup2(fd, libc::STDERR_FILENO) };
if ret == -1 {
eprintln!(
"Warning: failed to redirect stderr to log file: {}",
std::io::Error::last_os_error()
);
}
}
#[cfg(windows)]
fn redirect_stderr_to_file(file: &std::fs::File) {
use std::os::windows::io::AsRawHandle;
let mut dup_handle: windows_sys::Win32::Foundation::HANDLE = std::ptr::null_mut();
let cur_proc = unsafe { windows_sys::Win32::System::Threading::GetCurrentProcess() };
let ok = unsafe {
windows_sys::Win32::Foundation::DuplicateHandle(
cur_proc,
file.as_raw_handle() as _,
cur_proc,
&mut dup_handle,
0,
0, windows_sys::Win32::Foundation::DUPLICATE_SAME_ACCESS,
)
};
if ok == 0 {
eprintln!(
"Warning: failed to duplicate handle for stderr redirect: {}",
std::io::Error::last_os_error()
);
return;
}
const O_WRONLY: libc::c_int = 0x0001;
let new_fd =
unsafe { libc::open_osfhandle(dup_handle as libc::intptr_t, O_WRONLY | libc::O_APPEND) };
if new_fd == -1 {
eprintln!("Warning: failed to convert handle for stderr redirect");
unsafe {
windows_sys::Win32::Foundation::CloseHandle(dup_handle);
}
return;
}
if unsafe { libc::dup2(new_fd, 2) } == -1 {
eprintln!(
"Warning: failed to redirect stderr to log file: {}",
std::io::Error::last_os_error()
);
}
unsafe {
libc::close(new_fd);
}
}