all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Dietmar Maurer <dietmar@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH proxmox-backup 2/2] add helpers to write configuration files
Date: Fri, 16 Jul 2021 10:28:33 +0200	[thread overview]
Message-ID: <20210716082834.2354163-3-dietmar@proxmox.com> (raw)
In-Reply-To: <20210716082834.2354163-1-dietmar@proxmox.com>

---
 src/backup/mod.rs                  | 41 ++++++++++++++++++++++++++++++
 src/config/acl.rs                  | 14 +---------
 src/config/acme/plugin.rs          | 16 +-----------
 src/config/datastore.rs            | 19 +-------------
 src/config/domains.rs              | 19 +-------------
 src/config/drive.rs                | 18 +------------
 src/config/media_pool.rs           | 19 +-------------
 src/config/mod.rs                  | 10 ++------
 src/config/node.rs                 | 10 +-------
 src/config/remote.rs               | 16 +-----------
 src/config/sync.rs                 | 16 +-----------
 src/config/tape_encryption_keys.rs | 33 +++---------------------
 src/config/tape_job.rs             | 16 +-----------
 src/config/user.rs                 | 14 +---------
 src/config/verify.rs               | 17 +------------
 15 files changed, 58 insertions(+), 220 deletions(-)

diff --git a/src/backup/mod.rs b/src/backup/mod.rs
index 1db61cf5..3337f3a6 100644
--- a/src/backup/mod.rs
+++ b/src/backup/mod.rs
@@ -134,3 +134,44 @@ pub fn open_backup_lockfile<P: AsRef<std::path::Path>>(
     let file = proxmox::tools::fs::open_file_locked(&path, timeout, exclusive, options)?;
     Ok(BackupLockGuard(file))
 }
+
+/// Atomically write data to file owned by "root:backup" with permission "0640"
+///
+/// Only the superuser can write those files, but group 'backup' can read them.
+pub fn replace_backup_config<P: AsRef<std::path::Path>>(
+    path: P,
+    data: &[u8],
+) -> Result<(), Error> {
+    let backup_user = backup_user()?;
+    let mode = nix::sys::stat::Mode::from_bits_truncate(0o0640);
+    // set the correct owner/group/permissions while saving file
+    // owner(rw) = root, group(r)= backup
+    let options = proxmox::tools::fs::CreateOptions::new()
+        .perm(mode)
+        .owner(nix::unistd::ROOT)
+        .group(backup_user.gid);
+
+    proxmox::tools::fs::replace_file(path, data, options)?;
+
+    Ok(())
+}
+
+/// Atomically write data to file owned by "root:root" with permission "0600"
+///
+/// Only the superuser can read and write those files.
+pub fn replace_secret_config<P: AsRef<std::path::Path>>(
+    path: P,
+    data: &[u8],
+) -> Result<(), Error> {
+    let mode = nix::sys::stat::Mode::from_bits_truncate(0o0600);
+    // set the correct owner/group/permissions while saving file
+    // owner(rw) = root, group(r)= root
+    let options = proxmox::tools::fs::CreateOptions::new()
+        .perm(mode)
+        .owner(nix::unistd::ROOT)
+        .group(nix::unistd::Gid::from_raw(0));
+
+    proxmox::tools::fs::replace_file(path, data, options)?;
+
+    Ok(())
+}
diff --git a/src/config/acl.rs b/src/config/acl.rs
index b4b3510f..b7badb79 100644
--- a/src/config/acl.rs
+++ b/src/config/acl.rs
@@ -13,7 +13,6 @@ use serde::de::{value, IntoDeserializer};
 
 use proxmox::api::{api, schema::*};
 use proxmox::constnamedbitmap;
-use proxmox::tools::{fs::replace_file, fs::CreateOptions};
 
 use crate::api2::types::{Authid, Userid};
 
@@ -912,18 +911,7 @@ pub fn save_config(acl: &AclTree) -> Result<(), Error> {
 
     acl.write_config(&mut raw)?;
 
-    let backup_user = crate::backup::backup_user()?;
-    let mode = nix::sys::stat::Mode::from_bits_truncate(0o0640);
-    // set the correct owner/group/permissions while saving file
-    // owner(rw) = root, group(r)= backup
-    let options = CreateOptions::new()
-        .perm(mode)
-        .owner(nix::unistd::ROOT)
-        .group(backup_user.gid);
-
-    replace_file(ACL_CFG_FILENAME, &raw, options)?;
-
-    Ok(())
+    crate::backup::replace_backup_config(ACL_CFG_FILENAME, &raw)
 }
 
 #[cfg(test)]
diff --git a/src/config/acme/plugin.rs b/src/config/acme/plugin.rs
index fde800e2..a4322fdd 100644
--- a/src/config/acme/plugin.rs
+++ b/src/config/acme/plugin.rs
@@ -9,8 +9,6 @@ use proxmox::api::{
     section_config::{SectionConfig, SectionConfigData, SectionConfigPlugin},
 };
 
-use proxmox::tools::{fs::replace_file, fs::CreateOptions};
-
 use crate::api2::types::PROXMOX_SAFE_ID_FORMAT;
 use crate::backup::{open_backup_lockfile, BackupLockGuard};
 
@@ -168,19 +166,7 @@ pub fn config() -> Result<(PluginData, [u8; 32]), Error> {
 pub fn save_config(config: &PluginData) -> Result<(), Error> {
     super::make_acme_dir()?;
     let raw = CONFIG.write(ACME_PLUGIN_CFG_FILENAME, &config.data)?;
-
-    let backup_user = crate::backup::backup_user()?;
-    let mode = nix::sys::stat::Mode::from_bits_truncate(0o0640);
-    // set the correct owner/group/permissions while saving file
-    // owner(rw) = root, group(r)= backup
-    let options = CreateOptions::new()
-        .perm(mode)
-        .owner(nix::unistd::ROOT)
-        .group(backup_user.gid);
-
-    replace_file(ACME_PLUGIN_CFG_FILENAME, raw.as_bytes(), options)?;
-
-    Ok(())
+    crate::backup::replace_backup_config(ACME_PLUGIN_CFG_FILENAME, raw.as_bytes())
 }
 
 pub struct PluginData {
diff --git a/src/config/datastore.rs b/src/config/datastore.rs
index 9e37073d..46d28feb 100644
--- a/src/config/datastore.rs
+++ b/src/config/datastore.rs
@@ -13,11 +13,6 @@ use proxmox::api::{
     }
 };
 
-use proxmox::tools::fs::{
-    replace_file,
-    CreateOptions,
-};
-
 use crate::api2::types::*;
 use crate::backup::{open_backup_lockfile, BackupLockGuard};
 
@@ -154,19 +149,7 @@ pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
 
 pub fn save_config(config: &SectionConfigData) -> Result<(), Error> {
     let raw = CONFIG.write(DATASTORE_CFG_FILENAME, &config)?;
-
-    let backup_user = crate::backup::backup_user()?;
-    let mode = nix::sys::stat::Mode::from_bits_truncate(0o0640);
-    // set the correct owner/group/permissions while saving file
-    // owner(rw) = root, group(r)= backup
-    let options = CreateOptions::new()
-        .perm(mode)
-        .owner(nix::unistd::ROOT)
-        .group(backup_user.gid);
-
-    replace_file(DATASTORE_CFG_FILENAME, raw.as_bytes(), options)?;
-
-    Ok(())
+    crate::backup::replace_backup_config(DATASTORE_CFG_FILENAME, raw.as_bytes())
 }
 
 // shell completion helper
diff --git a/src/config/domains.rs b/src/config/domains.rs
index 9f513a44..0d695777 100644
--- a/src/config/domains.rs
+++ b/src/config/domains.rs
@@ -13,11 +13,6 @@ use proxmox::api::{
     }
 };
 
-use proxmox::tools::fs::{
-    replace_file,
-    CreateOptions,
-};
-
 use crate::api2::types::*;
 use crate::backup::{open_backup_lockfile, BackupLockGuard};
 
@@ -126,19 +121,7 @@ pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
 
 pub fn save_config(config: &SectionConfigData) -> Result<(), Error> {
     let raw = CONFIG.write(DOMAINS_CFG_FILENAME, &config)?;
-
-    let backup_user = crate::backup::backup_user()?;
-    let mode = nix::sys::stat::Mode::from_bits_truncate(0o0640);
-    // set the correct owner/group/permissions while saving file
-    // owner(rw) = root, group(r)= backup
-    let options = CreateOptions::new()
-        .perm(mode)
-        .owner(nix::unistd::ROOT)
-        .group(backup_user.gid);
-
-    replace_file(DOMAINS_CFG_FILENAME, raw.as_bytes(), options)?;
-
-    Ok(())
+    crate::backup::replace_backup_config(DOMAINS_CFG_FILENAME, raw.as_bytes())
 }
 
 // shell completion helper
diff --git a/src/config/drive.rs b/src/config/drive.rs
index 9c20051f..f86582ac 100644
--- a/src/config/drive.rs
+++ b/src/config/drive.rs
@@ -25,10 +25,6 @@ use proxmox::{
             SectionConfigPlugin,
         },
     },
-    tools::fs::{
-        replace_file,
-        CreateOptions,
-    },
 };
 
 use crate::{
@@ -97,19 +93,7 @@ pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
 /// Save the configuration file
 pub fn save_config(config: &SectionConfigData) -> Result<(), Error> {
     let raw = CONFIG.write(DRIVE_CFG_FILENAME, &config)?;
-
-    let backup_user = crate::backup::backup_user()?;
-    let mode = nix::sys::stat::Mode::from_bits_truncate(0o0640);
-    // set the correct owner/group/permissions while saving file
-    // owner(rw) = root, group(r)= backup
-    let options = CreateOptions::new()
-        .perm(mode)
-        .owner(nix::unistd::ROOT)
-        .group(backup_user.gid);
-
-    replace_file(DRIVE_CFG_FILENAME, raw.as_bytes(), options)?;
-
-    Ok(())
+    crate::backup::replace_backup_config(DRIVE_CFG_FILENAME, raw.as_bytes())
 }
 
 /// Check if the specified drive name exists in the config.
diff --git a/src/config/media_pool.rs b/src/config/media_pool.rs
index e50992d8..d9828e0f 100644
--- a/src/config/media_pool.rs
+++ b/src/config/media_pool.rs
@@ -20,10 +20,6 @@ use proxmox::{
             SectionConfigPlugin,
         }
     },
-    tools::fs::{
-        replace_file,
-        CreateOptions,
-    },
 };
 
 use crate::{
@@ -57,7 +53,6 @@ pub const MEDIA_POOL_CFG_FILENAME: &str = "/etc/proxmox-backup/media-pool.cfg";
 /// Lock file name (used to prevent concurrent access)
 pub const MEDIA_POOL_CFG_LOCKFILE: &str = "/etc/proxmox-backup/.media-pool.lck";
 
-
 /// Get exclusive lock
 pub fn lock() -> Result<BackupLockGuard, Error> {
     open_backup_lockfile(MEDIA_POOL_CFG_LOCKFILE, None, true)
@@ -77,19 +72,7 @@ pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
 /// Save the configuration file
 pub fn save_config(config: &SectionConfigData) -> Result<(), Error> {
     let raw = CONFIG.write(MEDIA_POOL_CFG_FILENAME, &config)?;
-
-    let backup_user = crate::backup::backup_user()?;
-    let mode = nix::sys::stat::Mode::from_bits_truncate(0o0640);
-    // set the correct owner/group/permissions while saving file
-    // owner(rw) = root, group(r)= backup
-    let options = CreateOptions::new()
-        .perm(mode)
-        .owner(nix::unistd::ROOT)
-        .group(backup_user.gid);
-
-    replace_file(MEDIA_POOL_CFG_FILENAME, raw.as_bytes(), options)?;
-
-    Ok(())
+    crate::backup::replace_backup_config(MEDIA_POOL_CFG_FILENAME, raw.as_bytes())
 }
 
 // shell completion helper
diff --git a/src/config/mod.rs b/src/config/mod.rs
index 014d184f..d820ee37 100644
--- a/src/config/mod.rs
+++ b/src/config/mod.rs
@@ -10,7 +10,6 @@ use openssl::rsa::{Rsa};
 use openssl::x509::{X509Builder};
 use openssl::pkey::PKey;
 
-use proxmox::tools::fs::{CreateOptions, replace_file};
 use proxmox::try_block;
 
 use pbs_buildcfg::{self, configdir};
@@ -194,18 +193,13 @@ pub fn update_self_signed_cert(force: bool) -> Result<(), Error> {
 }
 
 pub(crate) fn set_proxy_certificate(cert_pem: &[u8], key_pem: &[u8]) -> Result<(), Error> {
-    let backup_user = crate::backup::backup_user()?;
-    let options = CreateOptions::new()
-        .perm(Mode::from_bits_truncate(0o0640))
-        .owner(nix::unistd::ROOT)
-        .group(backup_user.gid);
     let key_path = PathBuf::from(configdir!("/proxy.key"));
     let cert_path = PathBuf::from(configdir!("/proxy.pem"));
 
     create_configdir()?;
-    replace_file(&key_path, &key_pem, options.clone())
+    crate::backup::replace_backup_config(&key_path, key_pem)
         .map_err(|err| format_err!("error writing certificate private key - {}", err))?;
-    replace_file(&cert_path, &cert_pem, options)
+    crate::backup::replace_backup_config(&cert_path, &cert_pem)
         .map_err(|err| format_err!("error writing certificate file - {}", err))?;
 
     Ok(())
diff --git a/src/config/node.rs b/src/config/node.rs
index dc3eeeb0..0c1c9938 100644
--- a/src/config/node.rs
+++ b/src/config/node.rs
@@ -6,7 +6,6 @@ use serde::{Deserialize, Serialize};
 
 use proxmox::api::api;
 use proxmox::api::schema::{ApiStringFormat, Updater};
-use proxmox::tools::fs::{replace_file, CreateOptions};
 
 use proxmox_http::ProxyConfig;
 
@@ -41,14 +40,7 @@ pub fn save_config(config: &NodeConfig) -> Result<(), Error> {
     config.validate()?;
 
     let raw = crate::tools::config::to_bytes(config, &NodeConfig::API_SCHEMA)?;
-
-    let backup_user = crate::backup::backup_user()?;
-    let options = CreateOptions::new()
-        .perm(Mode::from_bits_truncate(0o0640))
-        .owner(nix::unistd::ROOT)
-        .group(backup_user.gid);
-
-    replace_file(CONF_FILE, &raw, options)
+    crate::backup::replace_backup_config(CONF_FILE, &raw)
 }
 
 #[api(
diff --git a/src/config/remote.rs b/src/config/remote.rs
index 0ef70677..86fe7b6e 100644
--- a/src/config/remote.rs
+++ b/src/config/remote.rs
@@ -13,8 +13,6 @@ use proxmox::api::{
     }
 };
 
-use proxmox::tools::{fs::replace_file, fs::CreateOptions};
-
 use crate::api2::types::*;
 
 lazy_static! {
@@ -102,19 +100,7 @@ pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
 
 pub fn save_config(config: &SectionConfigData) -> Result<(), Error> {
     let raw = CONFIG.write(REMOTE_CFG_FILENAME, &config)?;
-
-    let backup_user = crate::backup::backup_user()?;
-    let mode = nix::sys::stat::Mode::from_bits_truncate(0o0640);
-    // set the correct owner/group/permissions while saving file
-    // owner(rw) = root, group(r)= backup
-    let options = CreateOptions::new()
-        .perm(mode)
-        .owner(nix::unistd::ROOT)
-        .group(backup_user.gid);
-
-    replace_file(REMOTE_CFG_FILENAME, raw.as_bytes(), options)?;
-
-    Ok(())
+    crate::backup::replace_backup_config(REMOTE_CFG_FILENAME, raw.as_bytes())
 }
 
 // shell completion helper
diff --git a/src/config/sync.rs b/src/config/sync.rs
index 2fd3a2c1..5d5b2060 100644
--- a/src/config/sync.rs
+++ b/src/config/sync.rs
@@ -13,8 +13,6 @@ use proxmox::api::{
     }
 };
 
-use proxmox::tools::{fs::replace_file, fs::CreateOptions};
-
 use crate::api2::types::*;
 
 lazy_static! {
@@ -120,19 +118,7 @@ pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
 
 pub fn save_config(config: &SectionConfigData) -> Result<(), Error> {
     let raw = CONFIG.write(SYNC_CFG_FILENAME, &config)?;
-
-    let backup_user = crate::backup::backup_user()?;
-    let mode = nix::sys::stat::Mode::from_bits_truncate(0o0640);
-    // set the correct owner/group/permissions while saving file
-    // owner(rw) = root, group(r)= backup
-    let options = CreateOptions::new()
-        .perm(mode)
-        .owner(nix::unistd::ROOT)
-        .group(backup_user.gid);
-
-    replace_file(SYNC_CFG_FILENAME, raw.as_bytes(), options)?;
-
-    Ok(())
+    crate::backup::replace_backup_config(SYNC_CFG_FILENAME, raw.as_bytes())
 }
 
 // shell completion helper
diff --git a/src/config/tape_encryption_keys.rs b/src/config/tape_encryption_keys.rs
index 5ee0ac1f..6d4e91b9 100644
--- a/src/config/tape_encryption_keys.rs
+++ b/src/config/tape_encryption_keys.rs
@@ -15,11 +15,7 @@ use std::collections::HashMap;
 use anyhow::{bail, Error};
 use serde::{Deserialize, Serialize};
 
-use proxmox::tools::fs::{
-    file_read_optional_string,
-    replace_file,
-    CreateOptions,
-};
+use proxmox::tools::fs::file_read_optional_string;
 
 use crate::{
     backup::{
@@ -143,18 +139,7 @@ pub fn save_keys(map: HashMap<Fingerprint, EncryptionKeyInfo>) -> Result<(), Err
     }
 
     let raw = serde_json::to_string_pretty(&list)?;
-
-    let mode = nix::sys::stat::Mode::from_bits_truncate(0o0600);
-    // set the correct owner/group/permissions while saving file
-    // owner(rw) = root, group(r)= root
-    let options = CreateOptions::new()
-        .perm(mode)
-        .owner(nix::unistd::ROOT)
-        .group(nix::unistd::Gid::from_raw(0));
-
-    replace_file(TAPE_KEYS_FILENAME, raw.as_bytes(), options)?;
-
-    Ok(())
+    crate::backup::replace_secret_config(TAPE_KEYS_FILENAME, raw.as_bytes())
 }
 
 /// Store tape encryption key configurations (password protected keys)
@@ -167,19 +152,7 @@ pub fn save_key_configs(map: HashMap<Fingerprint, KeyConfig>) -> Result<(), Erro
     }
 
     let raw = serde_json::to_string_pretty(&list)?;
-
-    let backup_user = crate::backup::backup_user()?;
-    let mode = nix::sys::stat::Mode::from_bits_truncate(0o0640);
-    // set the correct owner/group/permissions while saving file
-    // owner(rw) = root, group(r)= backup
-    let options = CreateOptions::new()
-        .perm(mode)
-        .owner(nix::unistd::ROOT)
-        .group(backup_user.gid);
-
-    replace_file(TAPE_KEY_CONFIG_FILENAME, raw.as_bytes(), options)?;
-
-    Ok(())
+    crate::backup::replace_backup_config(TAPE_KEY_CONFIG_FILENAME, raw.as_bytes())
 }
 
 /// Insert a new key
diff --git a/src/config/tape_job.rs b/src/config/tape_job.rs
index a5901e86..f09200fc 100644
--- a/src/config/tape_job.rs
+++ b/src/config/tape_job.rs
@@ -13,8 +13,6 @@ use proxmox::api::{
     }
 };
 
-use proxmox::tools::{fs::replace_file, fs::CreateOptions};
-
 use crate::api2::types::{
     Userid,
     JOB_ID_SCHEMA,
@@ -159,19 +157,7 @@ pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
 
 pub fn save_config(config: &SectionConfigData) -> Result<(), Error> {
     let raw = CONFIG.write(TAPE_JOB_CFG_FILENAME, &config)?;
-
-    let backup_user = crate::backup::backup_user()?;
-    let mode = nix::sys::stat::Mode::from_bits_truncate(0o0640);
-    // set the correct owner/group/permissions while saving file
-    // owner(rw) = root, group(r)= backup
-    let options = CreateOptions::new()
-        .perm(mode)
-        .owner(nix::unistd::ROOT)
-        .group(backup_user.gid);
-
-    replace_file(TAPE_JOB_CFG_FILENAME, raw.as_bytes(), options)?;
-
-    Ok(())
+    crate::backup::replace_backup_config(TAPE_JOB_CFG_FILENAME, raw.as_bytes())
 }
 
 // shell completion helper
diff --git a/src/config/user.rs b/src/config/user.rs
index bdec5fc1..8d367ade 100644
--- a/src/config/user.rs
+++ b/src/config/user.rs
@@ -15,8 +15,6 @@ use proxmox::api::{
     }
 };
 
-use proxmox::tools::{fs::replace_file, fs::CreateOptions};
-
 use crate::api2::types::*;
 use crate::tools::Memcom;
 
@@ -259,17 +257,7 @@ pub fn cached_config() -> Result<Arc<SectionConfigData>, Error> {
 
 pub fn save_config(config: &SectionConfigData) -> Result<(), Error> {
     let raw = CONFIG.write(USER_CFG_FILENAME, &config)?;
-
-    let backup_user = crate::backup::backup_user()?;
-    let mode = nix::sys::stat::Mode::from_bits_truncate(0o0640);
-    // set the correct owner/group/permissions while saving file
-    // owner(rw) = root, group(r)= backup
-    let options = CreateOptions::new()
-        .perm(mode)
-        .owner(nix::unistd::ROOT)
-        .group(backup_user.gid);
-
-    replace_file(USER_CFG_FILENAME, raw.as_bytes(), options)?;
+    crate::backup::replace_backup_config(USER_CFG_FILENAME, raw.as_bytes())?;
 
     // increase user cache generation
     // We use this in CachedUserInfo
diff --git a/src/config/verify.rs b/src/config/verify.rs
index 549f9801..9001fffc 100644
--- a/src/config/verify.rs
+++ b/src/config/verify.rs
@@ -13,8 +13,6 @@ use proxmox::api::{
     }
 };
 
-use proxmox::tools::{fs::replace_file, fs::CreateOptions};
-
 use crate::api2::types::*;
 
 lazy_static! {
@@ -118,20 +116,7 @@ pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
 
 pub fn save_config(config: &SectionConfigData) -> Result<(), Error> {
     let raw = CONFIG.write(VERIFICATION_CFG_FILENAME, &config)?;
-
-    let backup_user = crate::backup::backup_user()?;
-    let mode = nix::sys::stat::Mode::from_bits_truncate(0o0640);
-    // set the correct owner/group/permissions while saving file
-    // owner(rw) = root, group(r)= backup
-
-    let options = CreateOptions::new()
-        .perm(mode)
-        .owner(nix::unistd::ROOT)
-        .group(backup_user.gid);
-
-    replace_file(VERIFICATION_CFG_FILENAME, raw.as_bytes(), options)?;
-
-    Ok(())
+    crate::backup::replace_backup_config(VERIFICATION_CFG_FILENAME, raw.as_bytes())
 }
 
 // shell completion helper
-- 
2.30.2




  parent reply	other threads:[~2021-07-16  8:28 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-07-16  8:28 [pbs-devel] [PATCH proxmox 1/2] new helper atomic_open_or_create_file() Dietmar Maurer
2021-07-16  8:28 ` [pbs-devel] [PATCH proxmox-backup 1/2] use new atomic_open_or_create_file Dietmar Maurer
     [not found]   ` <<20210716082834.2354163-2-dietmar@proxmox.com>
2021-07-19 10:45     ` Fabian Grünbichler
2021-07-16  8:28 ` Dietmar Maurer [this message]
2021-07-16  8:28 ` [pbs-devel] [PATCH proxmox 2/2] open_file_locked: add options parameter (CreateOptions) Dietmar Maurer
     [not found]   ` <<20210716082834.2354163-4-dietmar@proxmox.com>
2021-07-19 10:44     ` Fabian Grünbichler
     [not found] ` <<20210716082834.2354163-1-dietmar@proxmox.com>
2021-07-19 10:44   ` [pbs-devel] [PATCH proxmox 1/2] new helper atomic_open_or_create_file() Fabian Grünbichler
2021-07-20 11:51 [pbs-devel] [PATCH proxmox-apt] depend on proxmox 0.12.0, bump version to 0.5.1-1 Dietmar Maurer
2021-07-20 11:51 ` [pbs-devel] [PATCH proxmox-backup 2/2] add helpers to write configuration files Dietmar Maurer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210716082834.2354163-3-dietmar@proxmox.com \
    --to=dietmar@proxmox.com \
    --cc=pbs-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal