public inbox for pbs-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [pbs-devel] [PATCH proxmox-backup v2 0/3] pbs-client: feature #3923
@ 2022-08-18 11:06 Markus Frank
  2022-08-18 11:06 ` [pbs-devel] [PATCH proxmox-backup v2 1/3] pbs-client: added overwrite-existing-files to PxarExtractOptions Markus Frank
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Markus Frank @ 2022-08-18 11:06 UTC (permalink / raw)
  To: pbs-devel

These patches are for ignore-acl, ignore-xattr, ignore-ownership,
ignore-permission & overwrite-existing-files parameter in
proxmox-backup-client.

Markus Frank (3):
  pbs-client: added overwrite-existing-files to PxarExtractOptions.
  pbs-client: added options to skip xattr/acl/ownership/permissions
  proxmox-backup-client: added ignore-acl/xattr/ownership/permission &
    overwrite parameters

 pbs-client/src/catalog_shell.rs   |  4 +--
 pbs-client/src/pxar/extract.rs    | 28 ++++++++++++++++--
 pbs-client/src/pxar/flags.rs      |  6 ++++
 pbs-client/src/pxar/metadata.rs   | 40 ++++++++++++++++---------
 proxmox-backup-client/src/main.rs | 49 ++++++++++++++++++++++++++++++-
 pxar-bin/src/main.rs              |  7 +++++
 6 files changed, 114 insertions(+), 20 deletions(-)

-- 
2.30.2





^ permalink raw reply	[flat|nested] 5+ messages in thread

* [pbs-devel] [PATCH proxmox-backup v2 1/3] pbs-client: added overwrite-existing-files to PxarExtractOptions.
  2022-08-18 11:06 [pbs-devel] [PATCH proxmox-backup v2 0/3] pbs-client: feature #3923 Markus Frank
@ 2022-08-18 11:06 ` Markus Frank
  2022-08-18 11:06 ` [pbs-devel] [PATCH proxmox-backup v2 2/3] pbs-client: added options to skip xattr/acl/ownership/permissions Markus Frank
  2022-08-18 11:06 ` [pbs-devel] [PATCH proxmox-backup v2 3/3] proxmox-backup-client: added ignore-acl/xattr/ownership/permission & overwrite parameters Markus Frank
  2 siblings, 0 replies; 5+ messages in thread
From: Markus Frank @ 2022-08-18 11:06 UTC (permalink / raw)
  To: pbs-devel

If overwrite-existing-files is true, O_TRUNC is set (to clean the
leftovers) instead of O_EXCL and therefore overwrites the files and
does not error out.

Signed-off-by: Markus Frank <m.frank@proxmox.com>
---
v2: add O_TRUNC to oflags if overwrite_existing_files is true.

 pbs-client/src/catalog_shell.rs |  4 ++--
 pbs-client/src/pxar/extract.rs  | 28 +++++++++++++++++++++++++---
 pxar-bin/src/main.rs            |  7 +++++++
 3 files changed, 34 insertions(+), 5 deletions(-)

diff --git a/pbs-client/src/catalog_shell.rs b/pbs-client/src/catalog_shell.rs
index b11901ed..25e27b37 100644
--- a/pbs-client/src/catalog_shell.rs
+++ b/pbs-client/src/catalog_shell.rs
@@ -984,7 +984,7 @@ impl Shell {
             .clone();
 
         let extractor =
-            crate::pxar::extract::Extractor::new(rootdir, root_meta, true, Flags::DEFAULT);
+            crate::pxar::extract::Extractor::new(rootdir, root_meta, true, false, Flags::DEFAULT);
 
         let mut extractor = ExtractorState::new(
             &mut self.catalog,
@@ -1172,7 +1172,7 @@ impl<'a> ExtractorState<'a> {
                 let file_name = CString::new(entry.file_name().as_bytes())?;
                 let mut contents = entry.contents().await?;
                 self.extractor
-                    .async_extract_file(&file_name, entry.metadata(), *size, &mut contents)
+                    .async_extract_file(&file_name, entry.metadata(), *size, &mut contents, false)
                     .await
             }
             _ => {
diff --git a/pbs-client/src/pxar/extract.rs b/pbs-client/src/pxar/extract.rs
index 161d2cef..36600789 100644
--- a/pbs-client/src/pxar/extract.rs
+++ b/pbs-client/src/pxar/extract.rs
@@ -34,6 +34,7 @@ pub struct PxarExtractOptions<'a> {
     pub match_list: &'a [MatchEntry],
     pub extract_match_default: bool,
     pub allow_existing_dirs: bool,
+    pub overwrite_existing_files: bool,
     pub on_error: Option<ErrorHandler>,
 }
 
@@ -80,6 +81,7 @@ where
         dir,
         root.metadata().clone(),
         options.allow_existing_dirs,
+        options.overwrite_existing_files,
         feature_flags,
     );
 
@@ -198,6 +200,7 @@ where
                 &mut decoder.contents().ok_or_else(|| {
                     format_err!("found regular file entry without contents in archive")
                 })?,
+                extractor.overwrite_existing_files,
             ),
             (false, _) => Ok(()), // skip this
         }
@@ -215,6 +218,7 @@ where
 pub struct Extractor {
     feature_flags: Flags,
     allow_existing_dirs: bool,
+    overwrite_existing_files: bool,
     dir_stack: PxarDirStack,
 
     /// For better error output we need to track the current path in the Extractor state.
@@ -231,11 +235,13 @@ impl Extractor {
         root_dir: Dir,
         metadata: Metadata,
         allow_existing_dirs: bool,
+        overwrite_existing_files: bool,
         feature_flags: Flags,
     ) -> Self {
         Self {
             dir_stack: PxarDirStack::new(root_dir, metadata),
             allow_existing_dirs,
+            overwrite_existing_files,
             feature_flags,
             current_path: Arc::new(Mutex::new(OsString::new())),
             on_error: Box::new(Err),
@@ -392,14 +398,21 @@ impl Extractor {
         metadata: &Metadata,
         size: u64,
         contents: &mut dyn io::Read,
+        overwrite_existing_files: bool,
     ) -> Result<(), Error> {
         let parent = self.parent_fd()?;
+        let mut oflags = OFlag::O_CREAT | OFlag::O_WRONLY | OFlag::O_CLOEXEC;
+        if overwrite_existing_files {
+            oflags = oflags | OFlag::O_TRUNC;
+        } else {
+            oflags = oflags | OFlag::O_EXCL;
+        }
         let mut file = unsafe {
             std::fs::File::from_raw_fd(
                 nix::fcntl::openat(
                     parent,
                     file_name,
-                    OFlag::O_CREAT | OFlag::O_EXCL | OFlag::O_WRONLY | OFlag::O_CLOEXEC,
+                    oflags,
                     Mode::from_bits(0o600).unwrap(),
                 )
                 .map_err(|err| format_err!("failed to create file {:?}: {}", file_name, err))?,
@@ -448,14 +461,21 @@ impl Extractor {
         metadata: &Metadata,
         size: u64,
         contents: &mut T,
+        overwrite_existing_files: bool,
     ) -> Result<(), Error> {
         let parent = self.parent_fd()?;
+        let mut oflags = OFlag::O_CREAT | OFlag::O_WRONLY | OFlag::O_CLOEXEC;
+        if overwrite_existing_files {
+            oflags = oflags | OFlag::O_TRUNC;
+        } else {
+            oflags = oflags | OFlag::O_EXCL;
+        }
         let mut file = tokio::fs::File::from_std(unsafe {
             std::fs::File::from_raw_fd(
                 nix::fcntl::openat(
                     parent,
                     file_name,
-                    OFlag::O_CREAT | OFlag::O_EXCL | OFlag::O_WRONLY | OFlag::O_CLOEXEC,
+                    oflags,
                     Mode::from_bits(0o600).unwrap(),
                 )
                 .map_err(|err| format_err!("failed to create file {:?}: {}", file_name, err))?,
@@ -818,7 +838,7 @@ where
         )
     })?;
 
-    Ok(Extractor::new(dir, metadata, false, Flags::DEFAULT))
+    Ok(Extractor::new(dir, metadata, false, false, Flags::DEFAULT))
 }
 
 pub async fn extract_sub_dir<T, DEST, PATH>(
@@ -951,6 +971,7 @@ where
                     &mut file.contents().await.map_err(|_| {
                         format_err!("found regular file entry without contents in archive")
                     })?,
+                    extractor.overwrite_existing_files,
                 )
                 .await?
         }
@@ -998,6 +1019,7 @@ where
                             &mut decoder.contents().ok_or_else(|| {
                                 format_err!("found regular file entry without contents in archive")
                             })?,
+                            extractor.overwrite_existing_files,
                         )
                         .await?
                 }
diff --git a/pxar-bin/src/main.rs b/pxar-bin/src/main.rs
index 3714eb03..1dd34deb 100644
--- a/pxar-bin/src/main.rs
+++ b/pxar-bin/src/main.rs
@@ -75,6 +75,11 @@ fn extract_archive_from_reader<R: std::io::Read>(
                 optional: true,
                 default: false,
             },
+            "overwrite_existing_files": {
+                description: "overwrite already existing files",
+                optional: true,
+                default: false,
+            },
             "files-from": {
                 description: "File containing match pattern for files to restore.",
                 optional: true,
@@ -112,6 +117,7 @@ fn extract_archive(
     no_fcaps: bool,
     no_acls: bool,
     allow_existing_dirs: bool,
+    overwrite_existing_files: bool,
     files_from: Option<String>,
     no_device_nodes: bool,
     no_fifos: bool,
@@ -179,6 +185,7 @@ fn extract_archive(
     let options = PxarExtractOptions {
         match_list: &match_list,
         allow_existing_dirs,
+        overwrite_existing_files,
         extract_match_default,
         on_error,
     };
-- 
2.30.2





^ permalink raw reply	[flat|nested] 5+ messages in thread

* [pbs-devel] [PATCH proxmox-backup v2 2/3] pbs-client: added options to skip xattr/acl/ownership/permissions
  2022-08-18 11:06 [pbs-devel] [PATCH proxmox-backup v2 0/3] pbs-client: feature #3923 Markus Frank
  2022-08-18 11:06 ` [pbs-devel] [PATCH proxmox-backup v2 1/3] pbs-client: added overwrite-existing-files to PxarExtractOptions Markus Frank
@ 2022-08-18 11:06 ` Markus Frank
  2022-08-18 11:06 ` [pbs-devel] [PATCH proxmox-backup v2 3/3] proxmox-backup-client: added ignore-acl/xattr/ownership/permission & overwrite parameters Markus Frank
  2 siblings, 0 replies; 5+ messages in thread
From: Markus Frank @ 2022-08-18 11:06 UTC (permalink / raw)
  To: pbs-devel

Also added WITH_OWNER and WITH_PERMISSION to Default-Flags,
because otherwise it would be needed to activly set these flags and most
filesystems that support XATTR and ACL also support
POSIX-Permissions & Ownership.

Signed-off-by: Markus Frank <m.frank@proxmox.com>
---
v2: 
* created new WITH_OWNER Flag and use WITH_PERMISSIONS for skipping chmod
* removed redundant if 

 pbs-client/src/pxar/flags.rs    |  6 +++++
 pbs-client/src/pxar/metadata.rs | 40 +++++++++++++++++++++------------
 2 files changed, 32 insertions(+), 14 deletions(-)

diff --git a/pbs-client/src/pxar/flags.rs b/pbs-client/src/pxar/flags.rs
index d46c8af3..b3280de7 100644
--- a/pbs-client/src/pxar/flags.rs
+++ b/pbs-client/src/pxar/flags.rs
@@ -71,6 +71,9 @@ bitflags! {
         /// Preserve XFS/ext4/ZFS project quota ID
         const WITH_QUOTA_PROJID                = 0x0001_0000_0000;
 
+        /// UNIX OWNERSHIP
+        const WITH_OWNER                       = 0x0002_0000_0000;
+
         /// Support ".pxarexclude" files
         const EXCLUDE_FILE                     = 0x1000_0000_0000_0000;
         /// Exclude submounts
@@ -105,6 +108,7 @@ bitflags! {
             Flags::WITH_2SEC_TIME.bits() |
             Flags::WITH_READ_ONLY.bits() |
             Flags::WITH_PERMISSIONS.bits() |
+            Flags::WITH_OWNER.bits() |
             Flags::WITH_SYMLINKS.bits() |
             Flags::WITH_DEVICE_NODES.bits() |
             Flags::WITH_FIFOS.bits() |
@@ -135,6 +139,8 @@ bitflags! {
             Flags::WITH_FLAG_PROJINHERIT.bits() |
             Flags::WITH_SUBVOLUME.bits() |
             Flags::WITH_SUBVOLUME_RO.bits() |
+            Flags::WITH_PERMISSIONS.bits() |
+            Flags::WITH_OWNER.bits() |
             Flags::WITH_XATTRS.bits() |
             Flags::WITH_ACL.bits() |
             Flags::WITH_SELINUX.bits() |
diff --git a/pbs-client/src/pxar/metadata.rs b/pbs-client/src/pxar/metadata.rs
index 22bc5f9d..be1911a7 100644
--- a/pbs-client/src/pxar/metadata.rs
+++ b/pbs-client/src/pxar/metadata.rs
@@ -100,19 +100,7 @@ pub fn apply(
     on_error: &mut (dyn FnMut(Error) -> Result<(), Error> + Send),
 ) -> Result<(), Error> {
     let c_proc_path = CString::new(format!("/proc/self/fd/{}", fd)).unwrap();
-
-    unsafe {
-        // UID and GID first, as this fails if we lose access anyway.
-        c_result!(libc::chown(
-            c_proc_path.as_ptr(),
-            metadata.stat.uid,
-            metadata.stat.gid
-        ))
-        .map(drop)
-        .or_else(allow_notsupp)
-        .map_err(|err| format_err!("failed to set ownership: {}", err))
-        .or_else(&mut *on_error)?;
-    }
+    apply_ownership(flags, c_proc_path.as_ptr(), metadata, &mut *on_error)?;
 
     let mut skip_xattrs = false;
     apply_xattrs(flags, c_proc_path.as_ptr(), metadata, &mut skip_xattrs)
@@ -125,7 +113,7 @@ pub fn apply(
 
     // Finally mode and time. We may lose access with mode, but the changing the mode also
     // affects times.
-    if !metadata.is_symlink() {
+    if !metadata.is_symlink() && flags.contains(Flags::WITH_PERMISSIONS) {
         c_result!(unsafe {
             libc::chmod(c_proc_path.as_ptr(), perms_from_metadata(metadata)?.bits())
         })
@@ -162,6 +150,30 @@ pub fn apply(
     Ok(())
 }
 
+pub fn apply_ownership(
+    flags: Flags,
+    c_proc_path: *const libc::c_char,
+    metadata: &Metadata,
+    on_error: &mut (dyn FnMut(Error) -> Result<(), Error> + Send),
+) -> Result<(), Error> {
+    if !flags.contains(Flags::WITH_OWNER) {
+        return Ok(());
+    }
+    unsafe {
+        // UID and GID first, as this fails if we lose access anyway.
+        c_result!(libc::chown(
+            c_proc_path,
+            metadata.stat.uid,
+            metadata.stat.gid
+        ))
+        .map(drop)
+        .or_else(allow_notsupp)
+        .map_err(|err| format_err!("failed to set ownership: {}", err))
+        .or_else(&mut *on_error)?;
+    }
+    Ok(())
+}
+
 fn add_fcaps(
     flags: Flags,
     c_proc_path: *const libc::c_char,
-- 
2.30.2





^ permalink raw reply	[flat|nested] 5+ messages in thread

* [pbs-devel] [PATCH proxmox-backup v2 3/3] proxmox-backup-client: added ignore-acl/xattr/ownership/permission & overwrite parameters
  2022-08-18 11:06 [pbs-devel] [PATCH proxmox-backup v2 0/3] pbs-client: feature #3923 Markus Frank
  2022-08-18 11:06 ` [pbs-devel] [PATCH proxmox-backup v2 1/3] pbs-client: added overwrite-existing-files to PxarExtractOptions Markus Frank
  2022-08-18 11:06 ` [pbs-devel] [PATCH proxmox-backup v2 2/3] pbs-client: added options to skip xattr/acl/ownership/permissions Markus Frank
@ 2022-08-18 11:06 ` Markus Frank
  2022-08-18 12:03   ` Wolfgang Bumiller
  2 siblings, 1 reply; 5+ messages in thread
From: Markus Frank @ 2022-08-18 11:06 UTC (permalink / raw)
  To: pbs-devel

If ignore-acl/ignore-xattr/ignore-ownership/ignore-permission is set,
the corresponding flag gets removed.

overwrite-existing-files is saved as an PxarExtractOption like
allow-existing-dirs.

Signed-off-by: Markus Frank <m.frank@proxmox.com>
---
v2: added ignore-permission

 proxmox-backup-client/src/main.rs | 49 ++++++++++++++++++++++++++++++-
 1 file changed, 48 insertions(+), 1 deletion(-)

diff --git a/proxmox-backup-client/src/main.rs b/proxmox-backup-client/src/main.rs
index 4bb9aa5e..dc038864 100644
--- a/proxmox-backup-client/src/main.rs
+++ b/proxmox-backup-client/src/main.rs
@@ -1201,6 +1201,31 @@ We do not extract '.pxar' archives when writing to standard output.
                 type: CryptMode,
                 optional: true,
             },
+            "ignore-acl": {
+                type: Boolean,
+                description: "ignore acl settings",
+                optional: true,
+            },
+            "ignore-xattr": {
+                type: Boolean,
+                description: "ignore xattr settings",
+                optional: true,
+            },
+            "ignore-ownership": {
+                type: Boolean,
+                description: "ignore owner settings (no chown)",
+                optional: true,
+            },
+            "ignore-permission": {
+                type: Boolean,
+                description: "ignore permission settings (no chmod)",
+                optional: true,
+            },
+            "overwrite-existing-files": {
+                type: Boolean,
+                description: "overwrite already existing files",
+                optional: true,
+            },
         }
     }
 )]
@@ -1210,6 +1235,12 @@ async fn restore(param: Value) -> Result<Value, Error> {
 
     let allow_existing_dirs = param["allow-existing-dirs"].as_bool().unwrap_or(false);
 
+    let ignore_acls = param["ignore-acl"].as_bool().unwrap_or(false);
+    let ignore_xattr = param["ignore-xattr"].as_bool().unwrap_or(false);
+    let ignore_ownership = param["ignore-ownership"].as_bool().unwrap_or(false);
+    let ignore_permission = param["ignore-permission"].as_bool().unwrap_or(false);
+    let overwrite_existing_files = param["overwrite-existing-files"].as_bool().unwrap_or(false);
+
     let archive_name = json::required_string_param(&param, "archive-name")?;
 
     let rate = match param["rate"].as_str() {
@@ -1331,14 +1362,30 @@ async fn restore(param: Value) -> Result<Value, Error> {
             match_list: &[],
             extract_match_default: true,
             allow_existing_dirs,
+            overwrite_existing_files,
             on_error: None,
         };
 
+        let mut feature_flags = pbs_client::pxar::Flags::DEFAULT;
+
+        if ignore_acls {
+            feature_flags.remove(pbs_client::pxar::Flags::WITH_ACL);
+        }
+        if ignore_xattr {
+            feature_flags.remove(pbs_client::pxar::Flags::WITH_XATTRS);
+        }
+        if ignore_ownership {
+            feature_flags.remove(pbs_client::pxar::Flags::WITH_OWNER);
+        }
+        if ignore_permission {
+            feature_flags.remove(pbs_client::pxar::Flags::WITH_PERMISSIONS);
+        }
+
         if let Some(target) = target {
             pbs_client::pxar::extract_archive(
                 pxar::decoder::Decoder::from_std(reader)?,
                 Path::new(target),
-                pbs_client::pxar::Flags::DEFAULT,
+                feature_flags,
                 |path| {
                     log::debug!("{:?}", path);
                 },
-- 
2.30.2





^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [pbs-devel] [PATCH proxmox-backup v2 3/3] proxmox-backup-client: added ignore-acl/xattr/ownership/permission & overwrite parameters
  2022-08-18 11:06 ` [pbs-devel] [PATCH proxmox-backup v2 3/3] proxmox-backup-client: added ignore-acl/xattr/ownership/permission & overwrite parameters Markus Frank
@ 2022-08-18 12:03   ` Wolfgang Bumiller
  0 siblings, 0 replies; 5+ messages in thread
From: Wolfgang Bumiller @ 2022-08-18 12:03 UTC (permalink / raw)
  To: Markus Frank; +Cc: pbs-devel

Sorry for missing this in the v1 revie, but I think it's better to have
the parameters as actual function paramters, and the api description
contain the `default` values.

Also, I think most of these should use plural form ;-)

On Thu, Aug 18, 2022 at 01:06:54PM +0200, Markus Frank wrote:
> If ignore-acl/ignore-xattr/ignore-ownership/ignore-permission is set,
> the corresponding flag gets removed.
> 
> overwrite-existing-files is saved as an PxarExtractOption like
> allow-existing-dirs.
> 
> Signed-off-by: Markus Frank <m.frank@proxmox.com>
> ---
> v2: added ignore-permission
> 
>  proxmox-backup-client/src/main.rs | 49 ++++++++++++++++++++++++++++++-
>  1 file changed, 48 insertions(+), 1 deletion(-)
> 
> diff --git a/proxmox-backup-client/src/main.rs b/proxmox-backup-client/src/main.rs
> index 4bb9aa5e..dc038864 100644
> --- a/proxmox-backup-client/src/main.rs
> +++ b/proxmox-backup-client/src/main.rs
> @@ -1201,6 +1201,31 @@ We do not extract '.pxar' archives when writing to standard output.
>                  type: CryptMode,
>                  optional: true,
>              },
> +            "ignore-acl": {

acl -> acls

> +                type: Boolean,
> +                description: "ignore acl settings",
> +                optional: true,

Add `default: false,`

> +            },
> +            "ignore-xattr": {

xattr -> xattrs

> +                type: Boolean,
> +                description: "ignore xattr settings",
> +                optional: true,

Add `default: false,`

> +            },
> +            "ignore-ownership": {
> +                type: Boolean,
> +                description: "ignore owner settings (no chown)",
> +                optional: true,

Add `default: false,`

> +            },
> +            "ignore-permission": {

permission -> permissions

> +                type: Boolean,
> +                description: "ignore permission settings (no chmod)",
> +                optional: true,

Add `default: false,`

> +            },
> +            "overwrite-existing-files": {

I think 'overwrite' could be enough actually.
(eg. tar has `--overwrite`)

> +                type: Boolean,
> +                description: "overwrite already existing files",
> +                optional: true,
> +            },
>          }
>      }
>  )]
> @@ -1210,6 +1235,12 @@ async fn restore(param: Value) -> Result<Value, Error> {

^ You can just place `bool` parameters in the `fn()` signature and
they'll be filled with the `default` values automatically by the api
macro (just use underscores in place of the minuses).
The `param: Value` parameter will then only contain the remaining
arguments.

(Most of the required parameters could actually be changed this way, but
not necessarily in the same patch series...)

>  
>      let allow_existing_dirs = param["allow-existing-dirs"].as_bool().unwrap_or(false);
>  
> +    let ignore_acls = param["ignore-acl"].as_bool().unwrap_or(false);
> +    let ignore_xattr = param["ignore-xattr"].as_bool().unwrap_or(false);
> +    let ignore_ownership = param["ignore-ownership"].as_bool().unwrap_or(false);
> +    let ignore_permission = param["ignore-permission"].as_bool().unwrap_or(false);
> +    let overwrite_existing_files = param["overwrite-existing-files"].as_bool().unwrap_or(false);

^ then this entire block can be dropped




^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2022-08-18 12:03 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-18 11:06 [pbs-devel] [PATCH proxmox-backup v2 0/3] pbs-client: feature #3923 Markus Frank
2022-08-18 11:06 ` [pbs-devel] [PATCH proxmox-backup v2 1/3] pbs-client: added overwrite-existing-files to PxarExtractOptions Markus Frank
2022-08-18 11:06 ` [pbs-devel] [PATCH proxmox-backup v2 2/3] pbs-client: added options to skip xattr/acl/ownership/permissions Markus Frank
2022-08-18 11:06 ` [pbs-devel] [PATCH proxmox-backup v2 3/3] proxmox-backup-client: added ignore-acl/xattr/ownership/permission & overwrite parameters Markus Frank
2022-08-18 12:03   ` Wolfgang Bumiller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal