diff --git a/Cargo.toml b/Cargo.toml index a1ba5216..70bb8b0f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ hyper-openssl = "0.7" lazy_static = "1.1" regex = "1.0" libc = "0.2" -nix = "0.13" +nix = "0.14" shellwords = "1.0" uuid = { version = "0.7", features = ["v4"] } chrono = "0.4" # Date and time library for Rust diff --git a/src/api2/admin/datastore.rs b/src/api2/admin/datastore.rs index 9befcaae..c313ee82 100644 --- a/src/api2/admin/datastore.rs +++ b/src/api2/admin/datastore.rs @@ -12,6 +12,8 @@ use chrono::{DateTime, Datelike, TimeZone, Local}; use std::path::PathBuf; use std::sync::Arc; +use proxmox::tools::{try_block, fs::file_set_contents}; + use crate::config::datastore; use crate::backup::*; @@ -510,7 +512,7 @@ fn upload_backup_log( // always comput CRC at server side blob.set_crc(blob.compute_crc()); let raw_data = blob.raw_data(); - crate::tools::file_set_contents(&path, raw_data, None)?; + file_set_contents(&path, raw_data, None)?; Ok(()) }) .and_then(move |_| { diff --git a/src/api2/backup/environment.rs b/src/api2/backup/environment.rs index 3a0a4c53..dc8a0176 100644 --- a/src/api2/backup/environment.rs +++ b/src/api2/backup/environment.rs @@ -4,7 +4,10 @@ use std::collections::HashMap; use serde_json::Value; -use proxmox::tools; +use proxmox::tools::{ + digest_to_hex, + fs::file_set_contents, +}; use crate::api_schema::router::{RpcEnvironment, RpcEnvironmentType}; use crate::server::WorkerTask; @@ -298,8 +301,8 @@ impl BackupEnvironment { fn log_upload_stat(&self, archive_name: &str, csum: &[u8; 32], uuid: &[u8; 16], size: u64, chunk_count: u64, upload_stat: &UploadStatistic) { self.log(format!("Upload statistics for '{}'", archive_name)); - self.log(format!("UUID: {}", tools::digest_to_hex(uuid))); - self.log(format!("Checksum: {}", tools::digest_to_hex(csum))); + self.log(format!("UUID: {}", digest_to_hex(uuid))); + self.log(format!("Checksum: {}", digest_to_hex(csum))); self.log(format!("Size: {}", size)); self.log(format!("Chunk count: {}", chunk_count)); @@ -402,7 +405,7 @@ impl BackupEnvironment { blob.set_crc(blob.compute_crc()); let raw_data = blob.raw_data(); - crate::tools::file_set_contents(&path, raw_data, None)?; + file_set_contents(&path, raw_data, None)?; self.log(format!("add blob {:?} ({} bytes, comp: {})", path, orig_len, blob_len)); diff --git a/src/api2/node/dns.rs b/src/api2/node/dns.rs index 8f83ecb6..5f24da2b 100644 --- a/src/api2/node/dns.rs +++ b/src/api2/node/dns.rs @@ -1,7 +1,6 @@ use failure::*; - -use crate::tools; +use proxmox::tools::fs::{file_get_contents, file_set_contents}; use crate::api2::*; use crate::api_schema::*; //use crate::api_schema::router::*; @@ -23,7 +22,7 @@ fn read_etc_resolv_conf() -> Result { let mut nscount = 0; - let raw = tools::file_get_contents(RESOLV_CONF_FN)?; + let raw = file_get_contents(RESOLV_CONF_FN)?; result["digest"] = Value::from(proxmox::tools::digest_to_hex(&sha::sha256(&raw))); @@ -63,13 +62,13 @@ fn update_dns( let _guard = MUTEX.lock(); - let search = tools::required_string_param(¶m, "search")?; + let search = crate::tools::required_string_param(¶m, "search")?; - let raw = tools::file_get_contents(RESOLV_CONF_FN)?; + let raw = file_get_contents(RESOLV_CONF_FN)?; let old_digest = proxmox::tools::digest_to_hex(&sha::sha256(&raw)); if let Some(digest) = param["digest"].as_str() { - tools::assert_if_modified(&old_digest, &digest)?; + crate::tools::assert_if_modified(&old_digest, &digest)?; } let old_data = String::from_utf8(raw)?; @@ -92,7 +91,7 @@ fn update_dns( data.push('\n'); } - tools::file_set_contents(RESOLV_CONF_FN, data.as_bytes(), None)?; + file_set_contents(RESOLV_CONF_FN, data.as_bytes(), None)?; Ok(Value::Null) } diff --git a/src/api2/node/time.rs b/src/api2/node/time.rs index 8d850d58..dcbe9235 100644 --- a/src/api2/node/time.rs +++ b/src/api2/node/time.rs @@ -1,6 +1,6 @@ use failure::*; +use proxmox::tools::fs::{file_read_firstline, file_set_contents}; -use crate::tools; use crate::api_schema::*; use crate::api_schema::router::*; use crate::api2::types::*; @@ -11,7 +11,7 @@ use chrono::prelude::*; fn read_etc_localtime() -> Result { // use /etc/timezone - if let Ok(line) = tools::file_read_firstline("/etc/timezone") { + if let Ok(line) = file_read_firstline("/etc/timezone") { return Ok(line.trim().to_owned()); } @@ -56,7 +56,7 @@ fn set_timezone( _rpcenv: &mut dyn RpcEnvironment, ) -> Result { - let timezone = tools::required_string_param(¶m, "timezone")?; + let timezone = crate::tools::required_string_param(¶m, "timezone")?; let path = std::path::PathBuf::from(format!("/usr/share/zoneinfo/{}", timezone)); @@ -64,7 +64,7 @@ fn set_timezone( bail!("No such timezone."); } - tools::file_set_contents("/etc/timezone", timezone.as_bytes(), None)?; + file_set_contents("/etc/timezone", timezone.as_bytes(), None)?; let _ = std::fs::remove_file("/etc/localtime"); diff --git a/src/auth_helpers.rs b/src/auth_helpers.rs index 1ae86e04..3db79d28 100644 --- a/src/auth_helpers.rs +++ b/src/auth_helpers.rs @@ -1,5 +1,3 @@ -use crate::tools; - use failure::*; use lazy_static::lazy_static; @@ -9,6 +7,11 @@ use openssl::sha; use std::path::PathBuf; +use proxmox::tools::{ + try_block, + fs::{file_get_contents, file_set_contents, file_set_contents_full}, +}; + fn compute_csrf_secret_digest( timestamp: i64, secret: &[u8], @@ -94,11 +97,11 @@ pub fn generate_csrf_key() -> Result<(), Error> { use nix::sys::stat::Mode; - let (_, backup_gid) = tools::getpwnam_ugid("backup")?; + let (_, backup_gid) = crate::tools::getpwnam_ugid("backup")?; let uid = Some(nix::unistd::ROOT); let gid = Some(nix::unistd::Gid::from_raw(backup_gid)); - tools::file_set_contents_full( + file_set_contents_full( &path, &pem, Some(Mode::from_bits_truncate(0o0640)), uid, gid)?; Ok(()) @@ -119,13 +122,13 @@ pub fn generate_auth_key() -> Result<(), Error> { use nix::sys::stat::Mode; - tools::file_set_contents( + file_set_contents( &priv_path, &priv_pem, Some(Mode::from_bits_truncate(0o0600)))?; let public_pem = rsa.public_key_to_pem()?; - tools::file_set_contents(&public_path, &public_pem, None)?; + file_set_contents(&public_path, &public_pem, None)?; Ok(()) } @@ -134,7 +137,7 @@ pub fn csrf_secret() -> &'static [u8] { lazy_static! { static ref SECRET: Vec = - tools::file_get_contents(configdir!("/csrf.key")).unwrap(); + file_get_contents(configdir!("/csrf.key")).unwrap(); } &SECRET @@ -142,7 +145,7 @@ pub fn csrf_secret() -> &'static [u8] { fn load_private_auth_key() -> Result, Error> { - let pem = tools::file_get_contents(configdir!("/authkey.key"))?; + let pem = file_get_contents(configdir!("/authkey.key"))?; let rsa = Rsa::private_key_from_pem(&pem)?; let key = PKey::from_rsa(rsa)?; @@ -160,7 +163,7 @@ pub fn private_auth_key() -> &'static PKey { fn load_public_auth_key() -> Result, Error> { - let pem = tools::file_get_contents(configdir!("/authkey.pub"))?; + let pem = file_get_contents(configdir!("/authkey.pub"))?; let rsa = Rsa::public_key_from_pem(&pem)?; let key = PKey::from_rsa(rsa)?; diff --git a/src/backup/key_derivation.rs b/src/backup/key_derivation.rs index 4f7036fa..40f7e0ae 100644 --- a/src/backup/key_derivation.rs +++ b/src/backup/key_derivation.rs @@ -3,6 +3,11 @@ use failure::*; use serde::{Deserialize, Serialize}; use chrono::{Local, TimeZone, DateTime}; +use proxmox::tools::{ + try_block, + fs::{file_get_contents, file_set_contents}, +}; + #[derive(Deserialize, Serialize, Debug)] pub enum KeyDerivationConfig { Scrypt { @@ -79,7 +84,7 @@ pub fn store_key_config( try_block!({ if replace { let mode = nix::sys::stat::Mode::S_IRUSR | nix::sys::stat::Mode::S_IWUSR; - crate::tools::file_set_contents(&path, data.as_bytes(), Some(mode))?; + file_set_contents(&path, data.as_bytes(), Some(mode))?; } else { use std::os::unix::fs::OpenOptionsExt; @@ -145,7 +150,7 @@ pub fn encrypt_key_with_passphrase( pub fn load_and_decrtypt_key(path: &std::path::Path, passphrase: fn() -> Result, Error>) -> Result<([u8;32], DateTime), Error> { - let raw = crate::tools::file_get_contents(&path)?; + let raw = file_get_contents(&path)?; let data = String::from_utf8(raw)?; let key_config: KeyConfig = serde_json::from_str(&data)?; diff --git a/src/backup/read_chunk.rs b/src/backup/read_chunk.rs index 807a40cd..081a0824 100644 --- a/src/backup/read_chunk.rs +++ b/src/backup/read_chunk.rs @@ -31,7 +31,7 @@ impl ReadChunk for LocalChunkReader { println!("READ CHUNK {}", digest_str); let (path, _) = self.store.chunk_path(digest); - let raw_data = crate::tools::file_get_contents(&path)?; + let raw_data = proxmox::tools::fs::file_get_contents(&path)?; let chunk = DataChunk::from_raw(raw_data, *digest)?; chunk.verify_crc()?; diff --git a/src/bin/proxmox-backup-api.rs b/src/bin/proxmox-backup-api.rs index 2bba229e..7c4ccfd9 100644 --- a/src/bin/proxmox-backup-api.rs +++ b/src/bin/proxmox-backup-api.rs @@ -1,5 +1,4 @@ //use proxmox_backup::tools; -use proxmox_backup::try_block; use proxmox_backup::api_schema::router::*; use proxmox_backup::api_schema::config::*; use proxmox_backup::server::rest::*; @@ -10,6 +9,7 @@ use proxmox_backup::config; use failure::*; use lazy_static::lazy_static; +use proxmox::tools::try_block; use futures::*; use futures::future::Future; diff --git a/src/bin/proxmox-backup-client.rs b/src/bin/proxmox-backup-client.rs index 71f72a2d..077188a1 100644 --- a/src/bin/proxmox-backup-client.rs +++ b/src/bin/proxmox-backup-client.rs @@ -7,6 +7,7 @@ use chrono::{Local, Utc, TimeZone}; use std::path::{Path, PathBuf}; use std::collections::{HashSet, HashMap}; use std::io::Write; +use proxmox::tools::fs::{file_get_contents, file_get_json, file_set_contents, image_size}; use proxmox_backup::tools; use proxmox_backup::cli::*; @@ -86,7 +87,7 @@ fn record_repository(repo: &BackupRepository) { _ => return, }; - let mut data = tools::file_get_json(&path, None).unwrap_or(json!({})); + let mut data = file_get_json(&path, None).unwrap_or(json!({})); let repo = repo.to_string(); @@ -118,7 +119,7 @@ fn record_repository(repo: &BackupRepository) { let new_data = json!(map); - let _ = tools::file_set_contents(path, new_data.to_string().as_bytes(), None); + let _ = file_set_contents(path, new_data.to_string().as_bytes(), None); } fn complete_repository(_arg: &str, _param: &HashMap) -> Vec { @@ -136,7 +137,7 @@ fn complete_repository(_arg: &str, _param: &HashMap) -> Vec return result, }; - let data = tools::file_get_json(&path, None).unwrap_or(json!({})); + let data = file_get_json(&path, None).unwrap_or(json!({})); if let Some(map) = data.as_object() { for (repo, _count) in map { @@ -521,7 +522,7 @@ fn create_backup( bail!("got unexpected file type (expected file or block device)"); } - let size = tools::image_size(&PathBuf::from(filename))?; + let size = image_size(&PathBuf::from(filename))?; if size == 0 { bail!("got zero-sized file '{}'", filename); } @@ -567,7 +568,7 @@ fn create_backup( let path = master_pubkey_path()?; if path.exists() { - let pem_data = proxmox_backup::tools::file_get_contents(&path)?; + let pem_data = file_get_contents(&path)?; let rsa = openssl::rsa::Rsa::public_key_from_pem(&pem_data)?; let enc_key = crypt_config.generate_rsa_encoded_key(rsa, created)?; (Some(Arc::new(crypt_config)), Some(enc_key)) @@ -632,7 +633,7 @@ fn create_backup( // openssl rsautl -decrypt -inkey master-private.pem -in rsa-encrypted.key -out t /* let mut buffer2 = vec![0u8; rsa.size() as usize]; - let pem_data = proxmox_backup::tools::file_get_contents("master-private.pem")?; + let pem_data = file_get_contents("master-private.pem")?; let rsa = openssl::rsa::Rsa::private_key_from_pem(&pem_data)?; let len = rsa.private_decrypt(&buffer, &mut buffer2, openssl::rsa::Padding::PKCS1)?; println!("TEST {} {:?}", len, buffer2); @@ -777,7 +778,7 @@ fn restore( }; if let Some(target) = target { - crate::tools::file_set_contents(target, &raw_data, None)?; + file_set_contents(target, &raw_data, None)?; } else { let stdout = std::io::stdout(); let mut writer = stdout.lock(); @@ -878,7 +879,7 @@ fn upload_log( } }; - let data = crate::tools::file_get_contents(logfile)?; + let data = file_get_contents(logfile)?; let blob = if let Some(ref crypt_config) = crypt_config { DataBlob::encode(&data, Some(crypt_config), true)? @@ -1200,7 +1201,7 @@ fn key_import_master_pubkey( let path = tools::required_string_param(¶m, "path")?; let path = PathBuf::from(path); - let pem_data = proxmox_backup::tools::file_get_contents(&path)?; + let pem_data = file_get_contents(&path)?; if let Err(err) = openssl::pkey::PKey::public_key_from_pem(&pem_data) { bail!("Unable to decode PEM data - {}", err); @@ -1208,7 +1209,7 @@ fn key_import_master_pubkey( let target_path = master_pubkey_path()?; - proxmox_backup::tools::file_set_contents(&target_path, &pem_data, None)?; + file_set_contents(&target_path, &pem_data, None)?; println!("Imported public master key to {:?}", target_path); @@ -1243,14 +1244,14 @@ fn key_create_master_key( let pub_key: Vec = pkey.public_key_to_pem()?; let filename_pub = "master-public.pem"; println!("Writing public master key to {}", filename_pub); - proxmox_backup::tools::file_set_contents(filename_pub, pub_key.as_slice(), None)?; + file_set_contents(filename_pub, pub_key.as_slice(), None)?; let cipher = openssl::symm::Cipher::aes_256_cbc(); let priv_key: Vec = pkey.private_key_to_pem_pkcs8_passphrase(cipher, new_pw.as_bytes())?; let filename_priv = "master-private.pem"; println!("Writing private master key to {}", filename_priv); - proxmox_backup::tools::file_set_contents(filename_priv, priv_key.as_slice(), None)?; + file_set_contents(filename_priv, priv_key.as_slice(), None)?; Ok(Value::Null) } diff --git a/src/bin/proxmox-backup-proxy.rs b/src/bin/proxmox-backup-proxy.rs index fe9e628a..c4492f13 100644 --- a/src/bin/proxmox-backup-proxy.rs +++ b/src/bin/proxmox-backup-proxy.rs @@ -1,4 +1,3 @@ -use proxmox_backup::try_block; use proxmox_backup::configdir; use proxmox_backup::server; use proxmox_backup::tools::daemon; @@ -8,6 +7,7 @@ use proxmox_backup::server::rest::*; use proxmox_backup::auth_helpers::*; use failure::*; +use proxmox::tools::try_block; use lazy_static::lazy_static; use futures::*; diff --git a/src/client/http_client.rs b/src/client/http_client.rs index fa3680ab..741fbfac 100644 --- a/src/client/http_client.rs +++ b/src/client/http_client.rs @@ -21,6 +21,11 @@ use openssl::ssl::{SslConnector, SslMethod}; use serde_json::{json, Value}; use url::percent_encoding::{percent_encode, DEFAULT_ENCODE_SET}; +use proxmox::tools::{ + digest_to_hex, + fs::{file_get_json, file_set_contents}, +}; + use crate::tools::{self, BroadcastFuture, tty}; use crate::tools::futures::{cancellable, Canceller}; use super::pipe_to_stream::*; @@ -51,7 +56,7 @@ fn store_ticket_info(server: &str, username: &str, ticket: &str, token: &str) -> let mode = nix::sys::stat::Mode::from_bits_truncate(0o0600); - let mut data = tools::file_get_json(&path, Some(json!({})))?; + let mut data = file_get_json(&path, Some(json!({})))?; let now = Utc::now().timestamp(); @@ -73,7 +78,7 @@ fn store_ticket_info(server: &str, username: &str, ticket: &str, token: &str) -> } } - tools::file_set_contents(path, new_data.to_string().as_bytes(), Some(mode))?; + file_set_contents(path, new_data.to_string().as_bytes(), Some(mode))?; Ok(()) } @@ -90,7 +95,7 @@ fn load_ticket_info(server: &str, username: &str) -> Option<(String, String)> { _ => return None, }; - let data = match tools::file_get_json(&path, None) { + let data = match file_get_json(&path, None) { Ok(v) => v, _ => return None, }; @@ -536,7 +541,7 @@ impl BackupReader { output: W, ) -> impl Future { let path = "chunk"; - let param = json!({ "digest": proxmox::tools::digest_to_hex(digest) }); + let param = json!({ "digest": digest_to_hex(digest) }); self.h2.download(path, Some(param), output) } @@ -781,7 +786,7 @@ impl BackupClient { let mut offset_list = vec![]; for (offset, digest) in chunk_list { //println!("append chunk {} (offset {})", proxmox::tools::digest_to_hex(&digest), offset); - digest_list.push(proxmox::tools::digest_to_hex(&digest)); + digest_list.push(digest_to_hex(&digest)); offset_list.push(offset); } println!("append chunks list len ({})", digest_list.len()); @@ -842,7 +847,7 @@ impl BackupClient { DigestListDecoder::new(body.map_err(Error::from)) .for_each(move |chunk| { let _ = release_capacity.release_capacity(chunk.len()); - println!("GOT DOWNLOAD {}", proxmox::tools::digest_to_hex(&chunk)); + println!("GOT DOWNLOAD {}", digest_to_hex(&chunk)); known_chunks.lock().unwrap().insert(chunk); Ok(()) }) @@ -904,7 +909,7 @@ impl BackupClient { if let MergedChunkInfo::New(chunk_info) = merged_chunk_info { let offset = chunk_info.offset; let digest = *chunk_info.chunk.digest(); - let digest_str = proxmox::tools::digest_to_hex(&digest); + let digest_str = digest_to_hex(&digest); let upload_queue = upload_queue.clone(); println!("upload new chunk {} ({} bytes, offset {})", digest_str, diff --git a/src/config.rs b/src/config.rs index b0442a1d..3f896452 100644 --- a/src/config.rs +++ b/src/config.rs @@ -7,7 +7,8 @@ use failure::*; pub mod datastore; -use crate::tools; +use proxmox::tools::try_block; + use crate::buildcfg; /// Check configuration directory permissions @@ -18,7 +19,7 @@ use crate::buildcfg; pub fn check_configdir_permissions() -> Result<(), Error> { let cfgdir = buildcfg::CONFIGDIR; - let (backup_uid, backup_gid) = tools::getpwnam_ugid("backup")?; + let (backup_uid, backup_gid) = crate::tools::getpwnam_ugid("backup")?; try_block!({ let stat = nix::sys::stat::stat(cfgdir)?; @@ -43,7 +44,7 @@ pub fn create_configdir() -> Result<(), Error> { use nix::sys::stat::Mode; let cfgdir = buildcfg::CONFIGDIR; - let (backup_uid, backup_gid) = tools::getpwnam_ugid("backup")?; + let (backup_uid, backup_gid) = crate::tools::getpwnam_ugid("backup")?; match nix::unistd::mkdir(cfgdir, Mode::from_bits_truncate(0o700)) { Ok(()) => {}, diff --git a/src/config/datastore.rs b/src/config/datastore.rs index a4329ab8..fac1847b 100644 --- a/src/config/datastore.rs +++ b/src/config/datastore.rs @@ -5,7 +5,8 @@ use std::io::Read; use std::collections::HashMap; //use std::sync::Arc; -use crate::tools; +use proxmox::tools::{try_block, fs::file_set_contents}; + use crate::api_schema::*; use crate::section_config::*; @@ -61,7 +62,7 @@ pub fn save_config(config: &SectionConfigData) -> Result<(), Error> { let raw = CONFIG.write(DATASTORE_CFG_FILENAME, &config)?; - tools::file_set_contents(DATASTORE_CFG_FILENAME, raw.as_bytes(), None)?; + file_set_contents(DATASTORE_CFG_FILENAME, raw.as_bytes(), None)?; Ok(()) } diff --git a/src/section_config.rs b/src/section_config.rs index 71429d2e..6c3ea7db 100644 --- a/src/section_config.rs +++ b/src/section_config.rs @@ -7,6 +7,9 @@ use std::collections::VecDeque; use serde_json::{json, Value}; use std::sync::Arc; + +use proxmox::tools::try_block; + use crate::api_schema::*; pub struct SectionConfigPlugin { diff --git a/src/server/command_socket.rs b/src/server/command_socket.rs index 2f1af86d..b230211c 100644 --- a/src/server/command_socket.rs +++ b/src/server/command_socket.rs @@ -14,6 +14,8 @@ use std::sync::Arc; use std::os::unix::io::AsRawFd; use nix::sys::socket; +use proxmox::tools::try_block; + /// Listens on a Unix Socket to handle simple command asynchronously pub fn create_control_socket(path: P, f: F) -> Result, Error> where P: Into, diff --git a/src/server/worker_task.rs b/src/server/worker_task.rs index 49572a7d..df1e71e0 100644 --- a/src/server/worker_task.rs +++ b/src/server/worker_task.rs @@ -13,9 +13,14 @@ use std::panic::UnwindSafe; use serde_json::{json, Value}; +use proxmox::tools::{ + try_block, + fs::{create_dir_chown, file_set_contents_full}, +}; + use super::UPID; -use crate::tools::{self, FileLogger}; +use crate::tools::FileLogger; macro_rules! PROXMOX_BACKUP_VAR_RUN_DIR_M { () => ("/var/run/proxmox-backup") } macro_rules! PROXMOX_BACKUP_LOG_DIR_M { () => ("/var/log/proxmox-backup") } @@ -31,7 +36,7 @@ lazy_static! { static ref WORKER_TASK_LIST: Mutex>> = Mutex::new(HashMap::new()); static ref MY_PID: i32 = unsafe { libc::getpid() }; - static ref MY_PID_PSTART: u64 = tools::procfs::read_proc_pid_stat(*MY_PID).unwrap().starttime; + static ref MY_PID_PSTART: u64 = crate::tools::procfs::read_proc_pid_stat(*MY_PID).unwrap().starttime; } /// Test if the task is still running @@ -44,7 +49,7 @@ pub fn worker_is_active(upid: &UPID) -> bool { false } } else { - match tools::procfs::check_process_running_pstart(upid.pid, upid.pstart) { + match crate::tools::procfs::check_process_running_pstart(upid.pid, upid.pstart) { Some(_) => true, _ => false, } @@ -136,13 +141,13 @@ fn parse_worker_status_line(line: &str) -> Result<(String, UPID, Option<(i64, St pub fn create_task_log_dirs() -> Result<(), Error> { try_block!({ - let (backup_uid, backup_gid) = tools::getpwnam_ugid("backup")?; + let (backup_uid, backup_gid) = crate::tools::getpwnam_ugid("backup")?; let uid = Some(nix::unistd::Uid::from_raw(backup_uid)); let gid = Some(nix::unistd::Gid::from_raw(backup_gid)); - tools::create_dir_chown(PROXMOX_BACKUP_LOG_DIR, None, uid, gid)?; - tools::create_dir_chown(PROXMOX_BACKUP_TASK_DIR, None, uid, gid)?; - tools::create_dir_chown(PROXMOX_BACKUP_VAR_RUN_DIR, None, uid, gid)?; + create_dir_chown(PROXMOX_BACKUP_LOG_DIR, None, uid, gid)?; + create_dir_chown(PROXMOX_BACKUP_TASK_DIR, None, uid, gid)?; + create_dir_chown(PROXMOX_BACKUP_VAR_RUN_DIR, None, uid, gid)?; Ok(()) }).map_err(|err: Error| format_err!("unable to create task log dir - {}", err))?; @@ -204,11 +209,11 @@ pub struct TaskListInfo { // Returns a sorted list of known tasks, fn update_active_workers(new_upid: Option<&UPID>) -> Result, Error> { - let (backup_uid, backup_gid) = tools::getpwnam_ugid("backup")?; + let (backup_uid, backup_gid) = crate::tools::getpwnam_ugid("backup")?; let uid = Some(nix::unistd::Uid::from_raw(backup_uid)); let gid = Some(nix::unistd::Gid::from_raw(backup_gid)); - let lock = tools::open_file_locked(PROXMOX_BACKUP_TASK_LOCK_FN, std::time::Duration::new(10, 0))?; + let lock = crate::tools::open_file_locked(PROXMOX_BACKUP_TASK_LOCK_FN, std::time::Duration::new(10, 0))?; nix::unistd::chown(PROXMOX_BACKUP_TASK_LOCK_FN, uid, gid)?; let reader = match File::open(PROXMOX_BACKUP_ACTIVE_TASK_FN) { @@ -303,7 +308,7 @@ fn update_active_workers(new_upid: Option<&UPID>) -> Result, E } } - tools::file_set_contents_full(PROXMOX_BACKUP_ACTIVE_TASK_FN, raw.as_bytes(), None, uid, gid)?; + file_set_contents_full(PROXMOX_BACKUP_ACTIVE_TASK_FN, raw.as_bytes(), None, uid, gid)?; drop(lock); @@ -363,11 +368,11 @@ impl WorkerTask { path.push(format!("{:02X}", upid.pstart % 256)); - let (backup_uid, backup_gid) = tools::getpwnam_ugid("backup")?; + let (backup_uid, backup_gid) = crate::tools::getpwnam_ugid("backup")?; let uid = Some(nix::unistd::Uid::from_raw(backup_uid)); let gid = Some(nix::unistd::Gid::from_raw(backup_gid)); - tools::create_dir_chown(&path, None, uid, gid)?; + create_dir_chown(&path, None, uid, gid)?; path.push(upid.to_string()); diff --git a/src/tools.rs b/src/tools.rs index 0efe5bd7..520d0d19 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -2,14 +2,9 @@ //! //! This is a collection of small and useful tools. use failure::*; -use nix::unistd; -use nix::sys::stat; -use nix::{convert_ioctl_res, request_code_read, ioc}; - use lazy_static::lazy_static; use std::fs::{File, OpenOptions}; -use std::io::Write; use std::path::Path; use std::io::Read; use std::io::ErrorKind; @@ -50,28 +45,6 @@ pub use file_logger::*; mod broadcast_future; pub use broadcast_future::*; -/// Macro to write error-handling blocks (like perl eval {}) -/// -/// #### Example: -/// ``` -/// # #[macro_use] extern crate proxmox_backup; -/// # use failure::*; -/// # let some_condition = false; -/// let result = try_block!({ -/// if (some_condition) { -/// bail!("some error"); -/// } -/// Ok(()) -/// }) -/// .map_err(|e| format_err!("my try block returned an error - {}", e)); -/// ``` - -#[macro_export] -macro_rules! try_block { - { $($token:tt)* } => {{ (|| -> Result<_,_> { $($token)* })() }} -} - - /// The `BufferedRead` trait provides a single function /// `buffered_read`. It returns a reference to an internal buffer. The /// purpose of this traid is to avoid unnecessary data copies. @@ -108,123 +81,6 @@ pub fn map_struct_mut(buffer: &mut [u8]) -> Result<&mut T, Error> { Ok(unsafe { &mut * (buffer.as_ptr() as *mut T) }) } -pub fn file_read_firstline>(path: P) -> Result { - - let path = path.as_ref(); - - try_block!({ - let file = std::fs::File::open(path)?; - - use std::io::{BufRead, BufReader}; - - let mut reader = BufReader::new(file); - - let mut line = String::new(); - - let _ = reader.read_line(&mut line)?; - - Ok(line) - }).map_err(|err: Error| format_err!("unable to read {:?} - {}", path, err)) -} - -pub fn file_get_contents>(path: P) -> Result, Error> { - - let path = path.as_ref(); - - try_block!({ - std::fs::read(path) - }).map_err(|err| format_err!("unable to read {:?} - {}", path, err)) -} - -pub fn file_get_json>(path: P, default: Option) -> Result { - - let path = path.as_ref(); - - let raw = match std::fs::read(path) { - Ok(v) => v, - Err(err) => { - if err.kind() == std::io::ErrorKind::NotFound { - if let Some(v) = default { - return Ok(v); - } - } - bail!("unable to read json {:?} - {}", path, err); - } - }; - - try_block!({ - let data = String::from_utf8(raw)?; - let json = serde_json::from_str(&data)?; - Ok(json) - }).map_err(|err: Error| format_err!("unable to parse json from {:?} - {}", path, err)) -} - -/// Atomically write a file -/// -/// We first create a temporary file, which is then renamed. -pub fn file_set_contents>( - path: P, - data: &[u8], - perm: Option, -) -> Result<(), Error> { - file_set_contents_full(path, data, perm, None, None) -} - -/// Atomically write a file with owner and group -pub fn file_set_contents_full>( - path: P, - data: &[u8], - perm: Option, - owner: Option, - group: Option, -) -> Result<(), Error> { - - let path = path.as_ref(); - - // Note: we use mkstemp heŕe, because this worka with different - // processes, threads, and even tokio tasks. - let mut template = path.to_owned(); - template.set_extension("tmp_XXXXXX"); - let (fd, tmp_path) = match unistd::mkstemp(&template) { - Ok((fd, path)) => (fd, path), - Err(err) => bail!("mkstemp {:?} failed: {}", template, err), - }; - - let tmp_path = tmp_path.as_path(); - - let mode : stat::Mode = perm.unwrap_or(stat::Mode::from( - stat::Mode::S_IRUSR | stat::Mode::S_IWUSR | - stat::Mode::S_IRGRP | stat::Mode::S_IROTH - )); - - if perm != None { - if let Err(err) = stat::fchmod(fd, mode) { - let _ = unistd::unlink(tmp_path); - bail!("fchmod {:?} failed: {}", tmp_path, err); - } - } - - if owner != None || group != None { - if let Err(err) = fchown(fd, owner, group) { - let _ = unistd::unlink(tmp_path); - bail!("fchown {:?} failed: {}", tmp_path, err); - } - } - - let mut file = unsafe { File::from_raw_fd(fd) }; - - if let Err(err) = file.write_all(data) { - let _ = unistd::unlink(tmp_path); - bail!("write failed: {}", err); - } - - if let Err(err) = std::fs::rename(tmp_path, path) { - let _ = unistd::unlink(tmp_path); - bail!("Atomic rename failed for file {:?} - {}", path, err); - } - - Ok(()) -} /// Create a file lock using fntl. This function allows you to specify /// a timeout if you want to avoid infinite blocking. @@ -362,52 +218,6 @@ pub fn getpwnam_ugid(username: &str) -> Result<(libc::uid_t,libc::gid_t), Error> Ok((info.pw_uid, info.pw_gid)) } -/// Creates directory at the provided path with specified ownership -/// -/// Simply returns if the directory already exists. -pub fn create_dir_chown>( - path: P, - perm: Option, - owner: Option, - group: Option, -) -> Result<(), nix::Error> -{ - let mode : stat::Mode = perm.unwrap_or(stat::Mode::from_bits_truncate(0o770)); - - let path = path.as_ref(); - - match nix::unistd::mkdir(path, mode) { - Ok(()) => {}, - Err(nix::Error::Sys(nix::errno::Errno::EEXIST)) => { - return Ok(()); - }, - err => return err, - } - - unistd::chown(path, owner, group)?; - - Ok(()) -} - -/// Change ownership of an open file handle -pub fn fchown( - fd: RawFd, - owner: Option, - group: Option -) -> Result<(), Error> { - - // According to the POSIX specification, -1 is used to indicate that owner and group - // are not to be changed. Since uid_t and gid_t are unsigned types, we have to wrap - // around to get -1 (copied fron nix crate). - let uid = owner.map(Into::into).unwrap_or((0 as libc::uid_t).wrapping_sub(1)); - let gid = group.map(Into::into).unwrap_or((0 as libc::gid_t).wrapping_sub(1)); - - let res = unsafe { libc::fchown(fd, uid, gid) }; - nix::errno::Errno::result(res)?; - - Ok(()) -} - // Returns the hosts node name (UTS node name) pub fn nodename() -> &'static str { @@ -561,7 +371,7 @@ pub fn get_hardware_address() -> Result { static FILENAME: &str = "/etc/ssh/ssh_host_rsa_key.pub"; - let contents = file_get_contents(FILENAME)?; + let contents = proxmox::tools::fs::file_get_contents(FILENAME)?; let digest = md5::compute(contents); Ok(format!("{:0x}", digest)) @@ -716,31 +526,3 @@ impl AsAny for T { fn as_any(&self) -> &dyn Any { self } } - -// /usr/include/linux/fs.h: #define BLKGETSIZE64 _IOR(0x12,114,size_t) -// return device size in bytes (u64 *arg) -nix::ioctl_read!(blkgetsize64, 0x12, 114, u64); - -/// Return file or block device size -pub fn image_size(path: &Path) -> Result { - - use std::os::unix::fs::FileTypeExt; - - let file = std::fs::File::open(path)?; - let metadata = file.metadata()?; - let file_type = metadata.file_type(); - - if file_type.is_block_device() { - let mut size : u64 = 0; - let res = unsafe { blkgetsize64(file.as_raw_fd(), &mut size) }; - - if let Err(err) = res { - bail!("blkgetsize64 failed for {:?} - {}", path, err); - } - Ok(size) - } else if file_type.is_file() { - Ok(metadata.len()) - } else { - bail!("image size failed - got unexpected file type {:?}", file_type); - } -} diff --git a/src/tools/fs.rs b/src/tools/fs.rs index a51d50ce..9eb48c6b 100644 --- a/src/tools/fs.rs +++ b/src/tools/fs.rs @@ -220,8 +220,6 @@ where } } -use nix::{convert_ioctl_res, request_code_read, request_code_write, ioc}; - // /usr/include/linux/fs.h: #define FS_IOC_GETFLAGS _IOR('f', 1, long) // read Linux file system attributes (see man chattr) nix::ioctl_read!(read_attr_fd, b'f', 1, usize); diff --git a/src/tools/procfs.rs b/src/tools/procfs.rs index 1846c655..655a4897 100644 --- a/src/tools/procfs.rs +++ b/src/tools/procfs.rs @@ -6,7 +6,7 @@ use std::io::{BufRead, BufReader}; use std::collections::HashSet; use std::process; use std::net::{Ipv4Addr, Ipv6Addr}; -use crate::tools; +use proxmox::tools::fs::file_read_firstline; use lazy_static::lazy_static; use regex::Regex; use libc; @@ -32,7 +32,7 @@ pub struct ProcFsPidStat { pub fn read_proc_pid_stat(pid: libc::pid_t) -> Result { - let statstr = tools::file_read_firstline(format!("/proc/{}/stat", pid))?; + let statstr = file_read_firstline(format!("/proc/{}/stat", pid))?; lazy_static! { static ref REGEX: Regex = Regex::new(concat!( @@ -89,7 +89,7 @@ pub fn check_process_running_pstart(pid: libc::pid_t, pstart: u64) -> Option Result<(f64, f64), Error> { let path = "/proc/uptime"; - let line = tools::file_read_firstline(&path)?; + let line = file_read_firstline(&path)?; let mut values = line.split_whitespace().map(|v| v.parse::()); match (values.next(), values.next()) { @@ -152,7 +152,7 @@ pub fn read_meminfo() -> Result { meminfo.swapused = meminfo.swaptotal - meminfo.swapfree; - let spages_line = tools::file_read_firstline("/sys/kernel/mm/ksm/pages_sharing")?; + let spages_line = file_read_firstline("/sys/kernel/mm/ksm/pages_sharing")?; meminfo.memshared = spages_line.trim_end().parse::()? * 4096; Ok(meminfo) @@ -221,7 +221,7 @@ pub struct ProcFsMemUsage { pub fn read_memory_usage() -> Result { let path = format!("/proc/{}/statm", process::id()); - let line = tools::file_read_firstline(&path)?; + let line = file_read_firstline(&path)?; let mut values = line.split_whitespace().map(|v| v.parse::()); let ps = 4096; diff --git a/src/tools/tty.rs b/src/tools/tty.rs index bbcc8e9e..70cae76f 100644 --- a/src/tools/tty.rs +++ b/src/tools/tty.rs @@ -5,7 +5,7 @@ use std::os::unix::io::AsRawFd; use failure::*; -use crate::try_block; +use proxmox::tools::try_block; /// Returns whether the current stdin is a tty . pub fn stdin_isatty() -> bool {