use std::path::Path; use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; use std::mem::MaybeUninit; use anyhow::{bail, Error}; use once_cell::sync::OnceCell; use nix::sys::stat::Mode; use proxmox::tools::fs::{create_path, CreateOptions}; // openssl::sha::sha256(b"Proxmox Backup ConfigVersionCache v1.0")[0..8]; pub const PROXMOX_BACKUP_CONFIG_VERSION_CACHE_MAGIC_1_0: [u8; 8] = [25, 198, 168, 230, 154, 132, 143, 131]; const FILE_PATH: &str = pbs_buildcfg::rundir!("/shmem/config-versions"); use proxmox_shared_memory::*; #[derive(Debug)] #[repr(C)] struct ConfigVersionCacheData { magic: [u8; 8], // User (user.cfg) cache generation/version. user_cache_generation: AtomicUsize, // Traffic control (traffic-control.cfg) generation/version. traffic_control_generation: AtomicUsize, // Add further atomics here (and reduce padding size) padding: [u8; 4096 - 3*8], } impl Init for ConfigVersionCacheData { fn initialize(this: &mut MaybeUninit) { unsafe { let me = &mut *this.as_mut_ptr(); me.magic = PROXMOX_BACKUP_CONFIG_VERSION_CACHE_MAGIC_1_0; } } fn check_type_magic(this: &MaybeUninit) -> Result<(), Error> { unsafe { let me = &*this.as_ptr(); if me.magic != PROXMOX_BACKUP_CONFIG_VERSION_CACHE_MAGIC_1_0 { bail!("ConfigVersionCache: wrong magic number"); } Ok(()) } } } pub struct ConfigVersionCache { shmem: SharedMemory } static INSTANCE: OnceCell> = OnceCell::new(); impl ConfigVersionCache { /// Open the memory based communication channel singleton. pub fn new() -> Result, Error> { INSTANCE.get_or_try_init(Self::open).map(Arc::clone) } // Actual work of `new`: fn open() -> Result, Error> { let user = crate::backup_user()?; let dir_opts = CreateOptions::new() .perm(Mode::from_bits_truncate(0o770)) .owner(user.uid) .group(user.gid); let file_path = Path::new(FILE_PATH); let dir_path = file_path.parent().unwrap(); create_path( dir_path, Some(dir_opts.clone()), Some(dir_opts))?; let file_opts = CreateOptions::new() .perm(Mode::from_bits_truncate(0o660)) .owner(user.uid) .group(user.gid); let shmem: SharedMemory = SharedMemory::open(file_path, file_opts)?; Ok(Arc::new(Self { shmem })) } /// Returns the user cache generation number. pub fn user_cache_generation(&self) -> usize { self.shmem.data() .user_cache_generation.load(Ordering::Acquire) } /// Increase the user cache generation number. pub fn increase_user_cache_generation(&self) { self.shmem.data() .user_cache_generation .fetch_add(1, Ordering::AcqRel); } /// Returns the traffic control generation number. pub fn traffic_control_generation(&self) -> usize { self.shmem.data() .traffic_control_generation.load(Ordering::Acquire) } /// Increase the traffic control generation number. pub fn increase_traffic_control_generation(&self) { self.shmem.data() .traffic_control_generation .fetch_add(1, Ordering::AcqRel); } }