]> git.ipfire.org Git - thirdparty/snapper.git/commitdiff
- support sending compressed data in snbk 1060/head
authorArvin Schnell <aschnell@suse.de>
Tue, 7 Oct 2025 12:58:15 +0000 (14:58 +0200)
committerArvin Schnell <aschnell@suse.de>
Tue, 7 Oct 2025 12:58:20 +0000 (14:58 +0200)
client/snbk/BackupConfig.cc
client/snbk/BackupConfig.h
client/snbk/CmdBtrfs.cc
client/snbk/CmdBtrfs.h
client/snbk/JsonFile.cc
client/snbk/JsonFile.h
client/snbk/TheBigThing.cc
client/snbk/TheBigThing.h
doc/snapper-backup-configs.xml.in
package/snapper.changes
scripts/snbk-btrfs

index 8ed3a35b156eedc32f31e68b6be97906633b23c1..7a81933389480dd273941c51952f09f4563ae910 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024 SUSE LLC
+ * Copyright (c) [2024-2025] SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -70,6 +70,10 @@ namespace snapper
            get_child_value(json_file.get_root(), "ssh-identity", ssh_identity);
        }
 
+       get_child_value(json_file.get_root(), "send-compressed-data", send_compressed_data);
+       get_child_nodes(json_file.get_root(), "send-options", send_options);
+       get_child_nodes(json_file.get_root(), "receive-options", receive_options);
+
        get_child_value(json_file.get_root(), "target-btrfs-bin", target_btrfs_bin);
        get_child_value(json_file.get_root(), "target-findmnt-bin", target_findmnt_bin);
        get_child_value(json_file.get_root(), "target-mkdir-bin", target_mkdir_bin);
index 39763a880368e8e1b0fafe1b017fc59611d4cf51..935c6d6194ff033d06ef0567474f64dc0c9ca280 100644 (file)
@@ -70,6 +70,10 @@ namespace snapper
        Shell get_source_shell() const;
        Shell get_target_shell() const;
 
+       bool send_compressed_data = true;
+       vector<string> send_options;
+       vector<string> receive_options;
+
        string target_btrfs_bin = BTRFS_BIN;
        string target_findmnt_bin = FINDMNT_BIN;
        string target_mkdir_bin = MKDIR_BIN;
index f7614593bb7820460a8260a777734954fecf8dd4..37db965f04b1f46320ca7544209a6fb3ad5aa797 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) [2004-2015] Novell, Inc.
- * Copyright (c) [2017-2024] SUSE LLC
+ * Copyright (c) [2017-2025] SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -21,6 +21,7 @@
  */
 
 
+#include <sys/utsname.h>
 #include <cstring>
 #include <regex>
 #include <boost/algorithm/string.hpp>
@@ -259,4 +260,88 @@ namespace snapper
        return s;
     }
 
+
+    void
+    CmdBtrfsVersion::query_version()
+    {
+       if (did_set_version)
+           return;
+
+       SystemCmd::Args cmd_args = { btrfs_bin, "--version" };
+       SystemCmd cmd(shellify(shell, cmd_args));
+
+       if (cmd.retcode() != 0)
+       {
+           y2err("command '" << cmd.cmd() << "' failed: " << cmd.retcode());
+           for (const string& tmp : cmd.get_stdout())
+               y2err(tmp);
+           for (const string& tmp : cmd.get_stderr())
+               y2err(tmp);
+
+           SN_THROW(Exception("'btrfs --version' failed"));
+       }
+
+       parse_version(cmd.get_stdout()[0]);
+    }
+
+
+    void
+    CmdBtrfsVersion::parse_version(const string& version)
+    {
+       // example versions: "5.14 " (yes, with a trailing space), "6.0", "6.0.2"
+       const regex version_rx("btrfs-progs v([0-9]+)\\.([0-9]+)(\\.([0-9]+))?( )*", regex::extended);
+
+       smatch match;
+
+       if (!regex_match(version, match, version_rx))
+           SN_THROW(Exception("failed to parse btrfs version '" + version + "'"));
+
+       major = stoi(match[1]);
+       minor = stoi(match[2]);
+       patchlevel = match[4].length() == 0 ? 0 : stoi(match[4]);
+
+       y2mil("major:" << major << " minor:" << minor << " patchlevel:" << patchlevel);
+
+       did_set_version = true;
+    }
+
+
+    int
+    CmdBtrfsVersion::supported_proto()
+    {
+       query_version();
+
+       if (major >= 6)
+           return 2;
+
+       return 1;
+    }
+
+
+    int
+    Uname::supported_proto()
+    {
+       const regex release_rx("^([0-9]+)\\.([0-9]+).*", regex::extended);
+
+       struct utsname buffer;
+
+       if (uname(&buffer) < 0)
+           SN_THROW(Exception("syscall uname failed"));
+
+       cmatch match;
+
+       if (!regex_match(buffer.release, match, release_rx))
+           SN_THROW(Exception("failed to parse uname release '" + string(buffer.release) + "'"));
+
+       int major = stoi(match[1]);
+       int minor = stoi(match[2]);
+
+       y2mil("major:" << major << " minor:" << minor);
+
+       if (major >= 6)
+           return 2;
+
+       return 1;
+    }
+
 }
index 86a7e558a0d452a47963e1925da0da6f8235d5bf..61e0243e1bdf7416256dab6139ba3b263e618a45 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) [2004-2015] Novell, Inc.
- * Copyright (c) [2017-2024] SUSE LLC
+ * Copyright (c) [2017-2025] SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -116,6 +116,45 @@ namespace snapper
 
     };
 
+
+    /**
+     * Lazy query of btrfs command version.
+     */
+    class CmdBtrfsVersion
+    {
+    public:
+
+       CmdBtrfsVersion(const string& btrfs_bin, const Shell& shell)
+           : btrfs_bin(btrfs_bin), shell(shell)
+       {}
+
+       int supported_proto();
+
+    private:
+
+       void query_version();
+       void parse_version(const string& version);
+
+       const string btrfs_bin;
+       const Shell shell;
+
+       bool did_set_version = false;
+
+       int major = 0;
+       int minor = 0;
+       int patchlevel = 0;
+
+    };
+
+
+    class Uname
+    {
+    public:
+
+       static int supported_proto();
+
+    };
+
 }
 
 #endif
index 26f776f2f1305b36dd5e0dbd3c1874116084cba1..0a40d6dfae962202e7bee2d1a4ff2f67300ad133 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 
-#include <stdio.h>
+#include <cstdio>
 #include <sys/stat.h>
 #include <functional>
 #include <memory>
@@ -187,6 +187,28 @@ namespace snapper
     }
 
 
+    bool
+    get_child_nodes(json_object* parent, const char* name, vector<string>& values)
+    {
+       vector<json_object*> children;
+
+       if (!get_child_nodes(parent, name, children))
+           return false;
+
+       values.clear();
+
+       for (json_object* child : children)
+       {
+           if (!json_object_is_type(child, json_type_string))
+               return false;
+
+           values.push_back(json_object_get_string(child));
+       }
+
+       return true;
+    }
+
+
     bool
     get_child_nodes(json_object* parent, const char* name, vector<json_object*>& children)
     {
index 23eab9cf3b9562f4ea3b567ba9224d6a7a404ad5..d2340f983d3151afae4a37382248cb25514743ad 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2017-2024] SUSE LLC
+ * Copyright (c) [2017-2025] SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -68,6 +68,9 @@ namespace snapper
     get_child_value(json_object* parent, const char* name, Type& value);
 
 
+    bool
+    get_child_nodes(json_object* parent, const char* name, vector<string>& values);
+
     bool
     get_child_nodes(json_object* parent, const char* name, vector<json_object*>& children);
 
index 0ccc62060971653571f54698a2f4dffc155f6adc..3c57fed0ba7d1b37267244c9ab2452f519f17715 100644 (file)
@@ -57,7 +57,7 @@ namespace snapper
 
 
     void
-    TheBigThing::transfer(const BackupConfig& backup_config, const TheBigThings& the_big_things,
+    TheBigThing::transfer(const BackupConfig& backup_config, TheBigThings& the_big_things,
                          bool quiet)
     {
        if (!quiet)
@@ -137,16 +137,29 @@ namespace snapper
 
        // Copy snapshot to target.
 
+       const int proto = std::min({
+           Uname::supported_proto(),
+           the_big_things.source_btrfs_version.supported_proto(),
+           the_big_things.target_btrfs_version.supported_proto()
+       });
+
        TheBigThings::const_iterator it1 = the_big_things.find_send_parent(*this);
 
        SystemCmd::Args cmd3a_args = { BTRFS_BIN, "send" };
+       if (proto >= 2)
+           cmd3a_args << "--proto" << to_string(proto);
+       if (backup_config.send_compressed_data && proto >= 2)
+           cmd3a_args << "--compressed-data";
+       cmd3a_args << backup_config.send_options;
+
        if (it1 != the_big_things.end())
            cmd3a_args << "-p" << backup_config.source_path + "/" SNAPSHOTS_NAME "/" +
                to_string(it1->num) + "/" SNAPSHOT_NAME;
        cmd3a_args << "--" << backup_config.source_path + "/" SNAPSHOTS_NAME "/" + num_string + "/" SNAPSHOT_NAME;
 
-       SystemCmd::Args cmd3b_args = { backup_config.target_btrfs_bin, "receive", "--",
-           backup_config.target_path + "/" + num_string };
+       SystemCmd::Args cmd3b_args = { backup_config.target_btrfs_bin, "receive" };
+       cmd3b_args << backup_config.receive_options;
+       cmd3b_args << "--" << backup_config.target_path + "/" + num_string;
 
        y2deb("source: " << cmd3a_args.get_values());
        y2deb("target: " << cmd3b_args.get_values());
@@ -238,7 +251,9 @@ namespace snapper
 
 
     TheBigThings::TheBigThings(const BackupConfig& backup_config, ProxySnappers* snappers, bool verbose)
-       : snapper(snappers->getSnapper(backup_config.config)), locker(snapper)
+       : source_btrfs_version(BTRFS_BIN, backup_config.get_source_shell()),
+         target_btrfs_version(backup_config.target_btrfs_bin, backup_config.get_target_shell()),
+         snapper(snappers->getSnapper(backup_config.config)), locker(snapper)
     {
        if (backup_config.source_path != snapper->getConfig().getSubvolume())
        {
index 766d6af984283d8aa637ecd7d1739f63eb995592..6a961c07020e46f568a53e13ee919568571d3e36 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024 SUSE LLC
+ * Copyright (c) [2024-2025] SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -29,6 +29,8 @@
 #include "../proxy/proxy.h"
 #include "../proxy/locker.h"
 
+#include "CmdBtrfs.h"
+
 
 namespace snapper
 {
@@ -52,7 +54,7 @@ namespace snapper
 
        TheBigThing(unsigned int num) : num(num) {}
 
-       void transfer(const BackupConfig& backup_config, const TheBigThings& the_big_things, bool quiet);
+       void transfer(const BackupConfig& backup_config, TheBigThings& the_big_things, bool quiet);
 
        void remove(const BackupConfig& backup_config, bool quiet);
 
@@ -110,6 +112,9 @@ namespace snapper
         */
        const_iterator find_send_parent(const TheBigThing& the_big_thing) const;
 
+       CmdBtrfsVersion source_btrfs_version;
+       CmdBtrfsVersion target_btrfs_version;
+
     private:
 
        const ProxySnapper* snapper;
index adae5cd114f80f693dd9f57fd994685dc942502b..7a6e202f8929cdf939db3c3ab18d4e13ff3476cb 100644 (file)
@@ -2,13 +2,13 @@
 <refentry id='snapper-backup-configs5'>
 
   <refentryinfo>
-    <date>2025-04-09</date>
+    <date>2025-10-07</date>
   </refentryinfo>
 
   <refmeta>
     <refentrytitle>snapper-backup-configs</refentrytitle>
     <manvolnum>5</manvolnum>
-    <refmiscinfo class='date'>2025-04-09</refmiscinfo>
+    <refmiscinfo class='date'>2025-10-07</refmiscinfo>
     <refmiscinfo class='version'>@VERSION@</refmiscinfo>
     <refmiscinfo class='manual'>Filesystem Snapshot Management</refmiscinfo>
   </refmeta>
        </listitem>
       </varlistentry>
 
+      <varlistentry>
+       <term><option>send-compressed-data</option></term>
+       <listitem>
+         <para>Per default snbk will add the option --compressed-data iff
+         supported by the source and target system. This can be disable by
+         setting this value to false.</para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term><option>send-options</option></term>
+       <listitem>
+         <para>Extra options for the btrfs send command as an array
+         of strings. Optional.</para>
+         <para>Per default snbk automatically adds --proto and --compressed-data
+         iff supported by both the source and target.</para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term><option>receive-options</option></term>
+       <listitem>
+         <para>Extra options for the btrfs receive command as an
+         array of strings. Optional.</para>
+       </listitem>
+      </varlistentry>
+
       <varlistentry>
        <term><option>target-btrfs-bin</option></term>
        <listitem>
index 6a9d331b6e4de26c03eede19bdfb8f37479e9e8a..ee7331f590fec390d520801f8fca604a3e1205f8 100644 (file)
@@ -1,3 +1,9 @@
+-------------------------------------------------------------------
+Tue Oct 07 14:42:16 CEST 2025 - aschnell@suse.com
+
+- support sending compressed data in snbk
+  (gh#openSUSE/snapper#1059)
+
 -------------------------------------------------------------------
 Wed Sep 24 16:12:34 CEST 2025 - aschnell@suse.com
 
index 39e816a3aec885b04aa9a48090f948870d995295..1c175bf46aaf91a3d25917225eae0db95772e486 100755 (executable)
@@ -1,5 +1,9 @@
 #!/bin/bash
 
+if [ "$#" -eq 1 ] && [ "$1" == "--version" ]; then
+    exec sudo /usr/sbin/btrfs --version
+fi
+
 if [ "$#" -lt 3 ]; then
     echo "Usage: $0 <group> [subcommand] [options] -- /backup/..."
     exit 1