]> git.ipfire.org Git - thirdparty/snapper.git/commitdiff
- redesigned target snapshot detection in snbk 1062/head
authorArvin Schnell <aschnell@suse.de>
Mon, 13 Oct 2025 12:35:17 +0000 (14:35 +0200)
committerArvin Schnell <aschnell@suse.de>
Mon, 13 Oct 2025 12:35:17 +0000 (14:35 +0200)
14 files changed:
client/snbk/BackupConfig.cc
client/snbk/BackupConfig.h
client/snbk/CmdBtrfs.cc
client/snbk/CmdBtrfs.h
client/snbk/CmdFindmnt.cc [deleted file]
client/snbk/CmdFindmnt.h [deleted file]
client/snbk/CmdLs.cc [moved from client/snbk/CmdRealpath.cc with 66% similarity]
client/snbk/CmdLs.h [moved from client/snbk/CmdRealpath.h with 64% similarity]
client/snbk/Makefile.am
client/snbk/TheBigThing.cc
client/snbk/cmd-list-configs.cc
configure.ac
doc/snapper-backup-configs.xml.in
package/snapper.changes

index 7a81933389480dd273941c51952f09f4563ae910..661b50416a1544c6675af95763df9968fc5b66aa 100644 (file)
@@ -75,9 +75,8 @@ namespace snapper
        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-ls-bin", target_ls_bin);
        get_child_value(json_file.get_root(), "target-mkdir-bin", target_mkdir_bin);
-       get_child_value(json_file.get_root(), "target-realpath-bin", target_realpath_bin);
        get_child_value(json_file.get_root(), "target-rm-bin", target_rm_bin);
        get_child_value(json_file.get_root(), "target-rmdir-bin", target_rmdir_bin);
     }
index 935c6d6194ff033d06ef0567474f64dc0c9ca280..f92c3d37841a96401ad71627884354f03587426a 100644 (file)
@@ -75,9 +75,8 @@ namespace snapper
        vector<string> receive_options;
 
        string target_btrfs_bin = BTRFS_BIN;
-       string target_findmnt_bin = FINDMNT_BIN;
+       string target_ls_bin = LS_BIN;
        string target_mkdir_bin = MKDIR_BIN;
-       string target_realpath_bin = REALPATH_BIN;
        string target_rm_bin = RM_BIN;
        string target_rmdir_bin = RMDIR_BIN;
 
index 37db965f04b1f46320ca7544209a6fb3ad5aa797..89f680f28ffb3d4929408375d526bb8a3158a93b 100644 (file)
@@ -22,9 +22,7 @@
 
 
 #include <sys/utsname.h>
-#include <cstring>
 #include <regex>
-#include <boost/algorithm/string.hpp>
 
 #include "snapper/SnapperTmpl.h"
 #include "snapper/SystemCmd.h"
@@ -40,124 +38,6 @@ namespace snapper
     using namespace std;
 
 
-    CmdBtrfsSubvolumeList::CmdBtrfsSubvolumeList(const string& btrfs_bin, const Shell& shell, const string& mount_point)
-    {
-       SystemCmd::Args cmd_args = { btrfs_bin, "subvolume", "list", "-a", "-puqR", "--", mount_point };
-       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 subvolume list' failed"));
-       }
-
-       parse(cmd.get_stdout());
-    }
-
-
-    void
-    CmdBtrfsSubvolumeList::parse(const vector<string>& lines)
-    {
-       for (const string& line : lines)
-       {
-           Entry entry;
-
-           string::size_type pos1 = line.find("ID ");
-           if (pos1 == string::npos)
-               SN_THROW(Exception("could not find 'id' in 'btrfs subvolume list' output"));
-           line.substr(pos1 + strlen("ID ")) >> entry.id;
-
-           string::size_type pos2 = line.find(" parent ");
-           if (pos2 == string::npos)
-               SN_THROW(Exception("could not find 'parent' in 'btrfs subvolume list' output"));
-           line.substr(pos2 + strlen(" parent ")) >> entry.parent_id;
-
-           // Subvolume can already be deleted, in which case parent is "0"
-           // (and path "DELETED"). That is a temporary state.
-           if (entry.parent_id == 0)
-               continue;
-
-           string::size_type pos3 = line.find(" path ");
-           if (pos3 == string::npos)
-               SN_THROW(Exception("could not find 'path' in 'btrfs subvolume list' output"));
-           entry.path = line.substr(pos3 + strlen(" path "));
-           if (boost::starts_with(entry.path, "<FS_TREE>/"))
-               entry.path.erase(0, strlen("<FS_TREE>/"));
-
-           string::size_type pos4 = line.find(" uuid ");
-           if (pos4 == string::npos)
-               SN_THROW(Exception("could not find 'uuid' in 'btrfs subvolume list' output"));
-           line.substr(pos4 + strlen(" uuid ")) >> entry.uuid;
-
-           string::size_type pos5 = line.find(" parent_uuid ");
-           if (pos5 == string::npos)
-               SN_THROW(Exception("could not find 'parent_uuid' in 'btrfs subvolume list' output"));
-           line.substr(pos5 + strlen(" parent_uuid ")) >> entry.parent_uuid;
-           if (entry.parent_uuid == "-")
-               entry.parent_uuid = "";
-
-           string::size_type pos6 = line.find(" received_uuid ");
-           if (pos6 == string::npos)
-               SN_THROW(Exception("could not find 'received_uuid' in 'btrfs subvolume list' output"));
-           line.substr(pos6 + strlen(" received_uuid ")) >> entry.received_uuid;
-           if (entry.received_uuid == "-")
-               entry.received_uuid = "";
-
-           data.push_back(entry);
-       }
-
-       // No way to get read-only flag. Only showing read-only snapshots does not help.
-
-       y2mil(*this);
-    }
-
-
-    CmdBtrfsSubvolumeList::const_iterator
-    CmdBtrfsSubvolumeList::find_entry_by_path(const string& path) const
-    {
-       for (const_iterator it = data.begin(); it != data.end(); ++it)
-       {
-           if (it->path == path)
-               return it;
-       }
-
-       return data.end();
-    }
-
-
-    std::ostream&
-    operator<<(std::ostream& s, const CmdBtrfsSubvolumeList& cmd_btrfs_subvolume_list)
-    {
-       for (const CmdBtrfsSubvolumeList::Entry& entry : cmd_btrfs_subvolume_list)
-           s << entry;
-
-       return s;
-    }
-
-
-    std::ostream&
-    operator<<(std::ostream& s, const CmdBtrfsSubvolumeList::Entry& entry)
-    {
-       s << "id:" << entry.id << " parent-id:" << entry.parent_id
-         << " path:" << entry.path << " uuid:" << entry.uuid;
-
-       if (!entry.parent_uuid.empty())
-           s << " parent-uuid:" << entry.parent_uuid;
-
-       if (!entry.received_uuid.empty())
-           s << " received-uuid:" << entry.received_uuid;
-
-       s  << '\n';
-
-       return s;
-    }
-
-
     CmdBtrfsSubvolumeShow::CmdBtrfsSubvolumeShow(const string& btrfs_bin, const Shell& shell, const string& mount_point)
     {
        SystemCmd::Args cmd_args = { btrfs_bin, "subvolume", "show", "--", mount_point };
index 61e0243e1bdf7416256dab6139ba3b263e618a45..4a94a7d9e3134c3ff44a92762253edd1eaf49fdd 100644 (file)
@@ -35,56 +35,6 @@ namespace snapper
     using std::vector;
 
 
-    /**
-     * Class to probe for btrfs subvolumes: Call "btrfs subvolume list
-     * <mount-point>".
-     */
-    class CmdBtrfsSubvolumeList
-    {
-    public:
-
-       static const long top_level_id = 5;
-       static const long unknown_id = -1;
-
-       CmdBtrfsSubvolumeList(const string& btrfs_bin, const Shell& shell, const string& mount_point);
-
-       /**
-        * Entry for every subvolume (unfortunately except the top-level).
-        *
-        * Caution: parent_id and parent_uuid are something completely
-        * different - not just different ways to specify the
-        * "parent".
-        */
-       struct Entry
-       {
-           long id = unknown_id;
-           long parent_id = unknown_id;
-           string path;
-           string uuid;
-           string parent_uuid;
-           string received_uuid;
-       };
-
-       typedef vector<Entry>::value_type value_type;
-       typedef vector<Entry>::const_iterator const_iterator;
-
-       const_iterator begin() const { return data.begin(); }
-       const_iterator end() const { return data.end(); }
-
-       const_iterator find_entry_by_path(const string& path) const;
-
-       friend std::ostream& operator<<(std::ostream& s, const CmdBtrfsSubvolumeList& cmd_btrfs_subvolume_list);
-       friend std::ostream& operator<<(std::ostream& s, const Entry& entry);
-
-    private:
-
-       void parse(const vector<string>& lines);
-
-       vector<Entry> data;
-
-    };
-
-
     /**
      * Class to probe for btrfs subvolume information: Call "btrfs subvolume
      * show <mount-point>".
diff --git a/client/snbk/CmdFindmnt.cc b/client/snbk/CmdFindmnt.cc
deleted file mode 100644 (file)
index ea603ce..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (c) 2024 SUSE LLC
- *
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as published
- * by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, contact Novell, Inc.
- *
- * To contact Novell about this file by physical or electronic mail, you may
- * find current contact information at www.novell.com.
- */
-
-
-#include "CmdFindmnt.h"
-#include "JsonFile.h"
-
-#include "snapper/SystemCmd.h"
-#include "snapper/SnapperDefines.h"
-#include "snapper/Exception.h"
-#include "snapper/LoggerImpl.h"
-
-
-namespace snapper
-{
-
-    CmdFindmnt::CmdFindmnt(const string& findmnt_bin, const Shell& shell, const string& path)
-       : path(path)
-    {
-       SystemCmd::Args cmd_args = { findmnt_bin, "--json", "--target", path };
-       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("'findmnt' failed"));
-       }
-
-       parse_json(cmd.get_stdout());
-    }
-
-
-    void
-    CmdFindmnt::parse_json(const vector<string>& lines)
-    {
-       JsonFile json_file(lines);
-
-       vector<json_object*> tmp1;
-
-       if (!get_child_nodes(json_file.get_root(), "filesystems", tmp1))
-           SN_THROW(Exception("\"filesystems\" not found in json output of 'findmnt'"));
-
-       for (json_object* tmp2 : tmp1)
-       {
-           if (!get_child_value(tmp2, "source", source))
-               SN_THROW(Exception("\"source\" not found or invalid"));
-
-           if (!get_child_value(tmp2, "target", target))
-               SN_THROW(Exception("\"target\" not found or invalid"));
-       }
-
-       y2mil(*this);
-    }
-
-
-    std::ostream&
-    operator<<(std::ostream& s, const CmdFindmnt& cmd_findmnt)
-    {
-       s << "path:" << cmd_findmnt.path << " source:" << cmd_findmnt.source
-         << " target:" << cmd_findmnt.target;
-
-       return s;
-    }
-
-}
diff --git a/client/snbk/CmdFindmnt.h b/client/snbk/CmdFindmnt.h
deleted file mode 100644 (file)
index 9a25141..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2024 SUSE LLC
- *
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as published
- * by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, contact Novell, Inc.
- *
- * To contact Novell about this file by physical or electronic mail, you may
- * find current contact information at www.novell.com.
- */
-
-
-#ifndef SNAPPER_CMD_FINDMNT_H
-#define SNAPPER_CMD_FINDMNT_H
-
-
-#include "Shell.h"
-
-
-namespace snapper
-{
-
-    using std::string;
-    using std::vector;
-
-
-    /**
-     * Class to probe for mount points: Call "findmnt --target <path>".
-     */
-    class CmdFindmnt
-    {
-    public:
-
-       CmdFindmnt(const string& findmnt_bin, const Shell& shell, const string& path);
-
-       const string& get_source() const { return source; }
-       const string& get_target() const { return target; }
-
-       friend std::ostream& operator<<(std::ostream& s, const CmdFindmnt& cmd_findmnt);
-
-    private:
-
-       void parse_json(const vector<string>& lines);
-
-       const string path;
-
-       string source;
-       string target;
-
-    };
-
-}
-
-#endif
similarity index 66%
rename from client/snbk/CmdRealpath.cc
rename to client/snbk/CmdLs.cc
index 991e7b98762b179b204dad02e3cb6d3886a58f3d..05eaa00bc041b023d225d983dc917847e7641daf 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2024 SUSE LLC
+ * Copyright (c) [2004-2015] Novell, Inc.
+ * Copyright (c) [2016-2025] SUSE LLC
  *
  * All Rights Reserved.
  *
  */
 
 
-#include "CmdRealpath.h"
-
+#include "snapper/SnapperTmpl.h"
 #include "snapper/SystemCmd.h"
-#include "snapper/SnapperDefines.h"
 #include "snapper/Exception.h"
 #include "snapper/LoggerImpl.h"
+#include "CmdLs.h"
 
 
 namespace snapper
 {
 
-    CmdRealpath::CmdRealpath(const string& realpath_bin, const Shell& shell, const string& path)
+    CmdLs::CmdLs(const string& ls_bin, const Shell& shell, const string& path)
        : path(path)
     {
-       SystemCmd::Args cmd_args = { realpath_bin, "--canonicalize-existing", "--", path };
+       SystemCmd::Args cmd_args = { ls_bin, "-1", "--sort=none", path };
        SystemCmd cmd(shellify(shell, cmd_args));
 
        if (cmd.retcode() != 0)
@@ -45,29 +45,26 @@ namespace snapper
            for (const string& tmp : cmd.get_stderr())
                y2err(tmp);
 
-           SN_THROW(Exception("'realpath' failed"));
+           SN_THROW(Exception("'ls' failed"));
        }
 
        parse(cmd.get_stdout());
+
+       y2mil(*this);
     }
 
 
     void
-    CmdRealpath::parse(const vector<string>& lines)
+    CmdLs::parse(const vector<string>& lines)
     {
-       if (lines.size() != 1)
-           SN_THROW(Exception("failed to parse output of 'realpath'"));
-
-       realpath = lines[0];
-
-       y2mil(*this);
+       entries = lines;
     }
 
 
     std::ostream&
-    operator<<(std::ostream& s, const CmdRealpath& cmd_realpath)
+    operator<<(std::ostream& s, const CmdLs& cms_ls)
     {
-       s << "path:" << cmd_realpath.path << " realpath:" << cmd_realpath.realpath;
+       s << "path:" << cms_ls.path << " entries:" << cms_ls.entries << '\n';
 
        return s;
     }
similarity index 64%
rename from client/snbk/CmdRealpath.h
rename to client/snbk/CmdLs.h
index c69afb6249b9d7df2c2bf2e4f2113c65c1a17b57..d69c15cabcf056c7e01806b897f26a230ef023b0 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2024 SUSE LLC
+ * Copyright (c) [2004-2015] Novell, Inc.
+ * Copyright (c) [2016-2025] SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -20,8 +21,8 @@
  */
 
 
-#ifndef SNAPPER_CMD_REALPATH_H
-#define SNAPPER_CMD_REALPATH_H
+#ifndef SNAPPER_CMD_LS_H
+#define SNAPPER_CMD_LS_H
 
 
 #include "Shell.h"
 
 namespace snapper
 {
-
     using std::string;
     using std::vector;
 
 
     /**
-     * Class to probe realpath: Call "realpath <path>".
+     * A sequence of file names found in a pathname.
      */
-    class CmdRealpath
+    class CmdLs
     {
     public:
 
-       CmdRealpath(const string& realpath_bin, const Shell& shell, const string& path);
+       CmdLs(const string& ls_bin, const Shell& shell, const string& path);
+
+       typedef vector<string>::const_iterator const_iterator;
 
-       const string& get_realpath() const { return realpath; }
+       const_iterator begin() const { return entries.begin(); }
+       const_iterator end() const { return entries.end(); }
 
-       friend std::ostream& operator<<(std::ostream& s, const CmdRealpath& cmd_realpath);
+       friend std::ostream& operator<<(std::ostream& s, const CmdLs& cmd_ls);
 
     private:
 
@@ -53,7 +56,7 @@ namespace snapper
 
        const string path;
 
-       string realpath;
+       vector<string> entries;
 
     };
 
index a1c245b5b804118c34775a39ffb4dc62b2c156b6..4a0f06ad48d9ee9e13a55e36708cef9b20e4b719 100644 (file)
@@ -19,8 +19,7 @@ snbk_SOURCES =                                                \
        GlobalOptions.cc        GlobalOptions.h         \
        Shell.cc                Shell.h                 \
        CmdBtrfs.cc             CmdBtrfs.h              \
-       CmdFindmnt.cc           CmdFindmnt.h            \
-       CmdRealpath.cc          CmdRealpath.h           \
+       CmdLs.cc                CmdLs.h                 \
        JsonFile.cc             JsonFile.h
 
 snbk_LDADD =                           \
index 3c57fed0ba7d1b37267244c9ab2452f519f17715..1bcf90034883e2ef3f7fe7890cd687dcffe4d9c2 100644 (file)
@@ -34,8 +34,7 @@
 #include "../utils/text.h"
 
 #include "CmdBtrfs.h"
-#include "CmdFindmnt.h"
-#include "CmdRealpath.h"
+#include "CmdLs.h"
 #include "BackupConfig.h"
 #include "TheBigThing.h"
 
@@ -71,10 +70,10 @@ namespace snapper
 
        const string num_string = to_string(num);
 
-       // Create directory on target.
+       // Create directory on target. No failure if it already exists (option --parents).
 
-       SystemCmd::Args cmd1_args = { backup_config.target_mkdir_bin, "--", backup_config.target_path + "/" +
-           num_string };
+       SystemCmd::Args cmd1_args = { backup_config.target_mkdir_bin, "--parents", "--", backup_config.target_path +
+           "/" + num_string };
        SystemCmd cmd1(shellify(backup_config.get_target_shell(), cmd1_args));
        if (cmd1.retcode() != 0)
        {
@@ -320,112 +319,94 @@ namespace snapper
        if (verbose)
            cout << _("Probing target snapshots.") << endl;
 
-       // In case the target-path is a symbolic link (or includes things like "/../") we
-       // need a lookup for the realpath first.
-
-       CmdRealpath cmd_realpath(backup_config.target_realpath_bin, shell_target, backup_config.target_path);
-       const string target_path = cmd_realpath.get_realpath();
-
-       CmdFindmnt cmd_findmnt(backup_config.target_findmnt_bin, shell_target, target_path);
-       const string mount_point = cmd_findmnt.get_target();
-
-       if (target_path.size() < mount_point.size())
-           SN_THROW(Exception("unsupported target-path setup"));
+       /* Using 'btrfs subvolume list' instead of 'ls' is much more complicated. */
 
-       if (!boost::starts_with(target_path, mount_point))
-           SN_THROW(Exception("unsupported target-path setup"));
-
-       CmdBtrfsSubvolumeList target_snapshots(backup_config.target_btrfs_bin, shell_target, mount_point);
-
-       string start;
-       if (target_path != mount_point)
-           start = target_path.substr(mount_point.size() + 1) + "/";
-
-       static const regex subvol_regex("\\[(.*?)\\]");
-       smatch subvol;
-       if (regex_search(cmd_findmnt.get_source(), subvol, subvol_regex))
-               start = subvol[1].str().substr(1) + "/" + start;
+       CmdLs cmd_ls(backup_config.target_ls_bin, shell_target, backup_config.target_path);
 
        if (verbose)
            cout << _("Probing extra information for target snapshots.") << endl;
 
-       static const regex num_regex("([0-9]+)/snapshot", regex::extended);
+       static const regex num_regex("[0-9]+", regex::extended);
 
-       for (const CmdBtrfsSubvolumeList::Entry& target_snapshot : target_snapshots)
+       for (const string& num_string : cmd_ls)
        {
-           if (!boost::starts_with(target_snapshot.path, start))
-               continue;
-
-           string path = target_snapshot.path.substr(start.size());
-
-           smatch match;
-
-           if (!regex_match(path, match, num_regex))
+           if (!regex_match(num_string, num_regex))
            {
-               string error = sformat(_("Invalid subvolume path '%s' on target."), path.c_str());
+               string error = sformat(_("Invalid subvolume path '%s' on target."), num_string.c_str());
                SN_THROW(Exception(error));
            }
 
-           unsigned int num = stoi(match[1]);
+           unsigned int num = stoi(num_string);
+           vector<TheBigThing>::iterator it = find(num);
 
            // Query additional information (receive-uuid, read-only) from btrfs.
 
-           CmdBtrfsSubvolumeShow y(backup_config.target_btrfs_bin, shell_target, target_path + "/" + path);
-
-           bool is_read_only = y.is_read_only();
-           if (!is_read_only)
+           try
            {
-               y2deb(num << " not read-only, maybe interrupted transfer");
-           }
+               CmdBtrfsSubvolumeShow extra(backup_config.target_btrfs_bin, shell_target, backup_config.target_path +
+                                           "/" + num_string + "/" SNAPSHOT_NAME);
 
-           vector<TheBigThing>::iterator it = find(num);
-           if (it != end())
-           {
-               // Wrong receive-uuid can happen when a snapshots is transferred, then removed
-               // and a new one with the same number is generated.
+               bool is_read_only = extra.is_read_only();
+               if (!is_read_only)
+               {
+                   y2deb(num << " not read-only, maybe interrupted transfer");
+               }
 
-               // When a snapshot is restored using btrfs send and receive the received
-               // uuid of the source is identical to the received uuid of the target -
-               // not the uuid of the target. In that case the target is also valid.
+               if (it != end())
+               {
+                   // Wrong receive-uuid can happen when a snapshots is transferred, then removed
+                   // and a new one with the same number is generated.
 
-               bool correct_uuid = false;
+                   // When a snapshot is restored using btrfs send and receive the received
+                   // uuid of the source is identical to the received uuid of the target -
+                   // not the uuid of the target. In that case the target is also valid.
 
-               if (!y.get_received_uuid().empty())
-               {
-                   if (it->source_uuid == y.get_received_uuid())
-                       correct_uuid = true;
-                   else if (it->source_received_uuid == y.get_received_uuid())
-                       correct_uuid = true;
+                   bool correct_uuid = false;
 
-                   if (!correct_uuid)
+                   if (!extra.get_received_uuid().empty())
                    {
-                       y2deb(num << " wrong uuid, maybe snapshot number reuse");
+                       if (it->source_uuid == extra.get_received_uuid())
+                           correct_uuid = true;
+                       else if (it->source_received_uuid == extra.get_received_uuid())
+                           correct_uuid = true;
+
+                       if (!correct_uuid)
+                       {
+                           y2deb(num << " wrong uuid, maybe snapshot number reuse");
+                       }
                    }
-               }
 
-               if (correct_uuid && is_read_only)
-                   it->target_state = TheBigThing::TargetState::VALID;
+                   if (correct_uuid && is_read_only)
+                       it->target_state = TheBigThing::TargetState::VALID;
+                   else
+                       it->target_state = TheBigThing::TargetState::INVALID;
+               }
                else
-                   it->target_state = TheBigThing::TargetState::INVALID;
-           }
-           else
-           {
-               TheBigThing the_big_thing(num);
+               {
+                   TheBigThing the_big_thing(num);
 
-               // Cannot check received-uuid so assume valid.
+                   // Cannot check received-uuid so assume valid.
 
-               if (is_read_only)
-                   the_big_thing.target_state = TheBigThing::TargetState::VALID;
-               else
-                   the_big_thing.target_state = TheBigThing::TargetState::INVALID;
+                   if (is_read_only)
+                       the_big_thing.target_state = TheBigThing::TargetState::VALID;
+                   else
+                       the_big_thing.target_state = TheBigThing::TargetState::INVALID;
 
-               it = the_big_things.insert(the_big_things.end(), the_big_thing);
+                   it = the_big_things.insert(the_big_things.end(), the_big_thing);
+               }
+
+               it->target_uuid = extra.get_uuid();
+               it->target_parent_uuid = extra.get_parent_uuid();
+               it->target_received_uuid = extra.get_received_uuid();
+               it->target_creation_time = extra.get_creation_time();
            }
+           catch (const Exception& e)
+           {
+               SN_CAUGHT(e);
 
-           it->target_uuid = y.get_uuid();
-           it->target_parent_uuid = y.get_parent_uuid();
-           it->target_received_uuid = y.get_received_uuid();
-           it->target_creation_time = y.get_creation_time();
+               // target_state is plain and simply missing or the snapshot is not even in
+               // the list.
+           }
        }
     }
 
index b2e9d69b5de8210aca55984e0bae042be22d4692..9106ee83cc75b4dedd342426d4cc7e4dbf465c6f 100644 (file)
@@ -54,8 +54,8 @@ namespace snapper
        enum class Column
        {
            NAME, CONFIG, TARGET_MODE, AUTOMATIC, SOURCE_PATH, TARGET_PATH, SSH_HOST,
-           SSH_USER, SSH_PORT, SSH_IDENTITY, TARGET_BTRFS_BIN, TARGET_FINDMNT_BIN,
-           TARGET_MKDIR_BIN, TARGET_REALPATH_BIN, TARGET_RM_BIN, TARGET_RMDIR_BIN
+           SSH_USER, SSH_PORT, SSH_IDENTITY, TARGET_BTRFS_BIN, TARGET_LS_BIN,
+           TARGET_MKDIR_BIN, TARGET_RM_BIN, TARGET_RMDIR_BIN
        };
 
 
@@ -97,15 +97,12 @@ namespace snapper
                case Column::TARGET_BTRFS_BIN:
                    return Cell(_("Target btrfs bin"));
 
-               case Column::TARGET_FINDMNT_BIN:
-                   return Cell(_("Target findmnt Bin"));
+               case Column::TARGET_LS_BIN:
+                   return Cell(_("Target ls Bin"));
 
                case Column::TARGET_MKDIR_BIN:
                    return Cell(_("Target mkdir bin"));
 
-               case Column::TARGET_REALPATH_BIN:
-                   return Cell(_("Target realpath bin"));
-
                case Column::TARGET_RM_BIN:
                    return Cell(_("Target rm bin"));
 
@@ -164,15 +161,12 @@ namespace snapper
                case Column::TARGET_BTRFS_BIN:
                    return backup_config.target_btrfs_bin;
 
-               case Column::TARGET_FINDMNT_BIN:
-                   return backup_config.target_findmnt_bin;
+               case Column::TARGET_LS_BIN:
+                   return backup_config.target_ls_bin;
 
                case Column::TARGET_MKDIR_BIN:
                    return backup_config.target_mkdir_bin;
 
-               case Column::TARGET_REALPATH_BIN:
-                   return backup_config.target_realpath_bin;
-
                case Column::TARGET_RM_BIN:
                    return backup_config.target_rm_bin;
 
@@ -302,8 +296,8 @@ namespace snapper
        const vector<Column> all_columns = { Column::NAME, Column::CONFIG, Column::TARGET_MODE,
            Column::AUTOMATIC, Column::SOURCE_PATH, Column::TARGET_PATH, Column::SSH_HOST,
            Column::SSH_USER, Column::SSH_PORT, Column::SSH_IDENTITY, Column::TARGET_BTRFS_BIN,
-           Column::TARGET_FINDMNT_BIN, Column::TARGET_MKDIR_BIN, Column::TARGET_REALPATH_BIN,
-           Column::TARGET_RM_BIN, Column::TARGET_RMDIR_BIN
+           Column::TARGET_LS_BIN, Column::TARGET_MKDIR_BIN, Column::TARGET_RM_BIN,
+           Column::TARGET_RMDIR_BIN
        };
 
        switch (global_options.output_format())
@@ -327,8 +321,8 @@ namespace snapper
 
     const vector<string> EnumInfo<Column>::names({
        "name", "config", "target-mode", "automatic", "source-path", "target-path", "ssh-host",
-       "ssh-user", "ssh-port", "ssh-identity", "target-btrfs-bin", "target-findmnt-bin",
-       "target-mkdir-bin", "target-realpath-bin", "target-rm-bin", "target-rmdir-bin"
+       "ssh-user", "ssh-port", "ssh-identity", "target-btrfs-bin", "target-ls-bin",
+       "target-mkdir-bin", "target-rm-bin", "target-rmdir-bin"
     });
 
 }
index 0d78d0f80ec1e2d8ec8c4527105d6b3c8069c70e..a116203dab25e382f8c575850ff2343a4e2dde19 100644 (file)
@@ -31,15 +31,14 @@ AC_PATH_PROG([CHATTR_BIN], [chattr], [/usr/bin/chattr])
 AC_PATH_PROG([CHSNAP_BIN], [chsnap], [/sbin/chsnap])
 AC_PATH_PROG([CP_BIN], [cp], [/bin/cp])
 AC_PATH_PROG([DIFF_BIN], [diff], [/usr/bin/diff])
-AC_PATH_PROG([FINDMNT_BIN], [findmnt], [/usr/bin/findmnt])
 AC_PATH_PROG([LVCHANGE_BIN], [lvchange], [/sbin/lvchange])
 AC_PATH_PROG([LVCREATE_BIN], [lvcreate], [/sbin/lvcreate])
+AC_PATH_PROG([LS_BIN], [ls], [/usr/bin/ls])
 AC_PATH_PROG([LVM_BIN], [lvm], [/sbin/lvm])
 AC_PATH_PROG([LVREMOVE_BIN], [lvremove], [/sbin/lvremove])
 AC_PATH_PROG([LVRENAME_BIN], [lvrename], [/sbin/lvrename])
 AC_PATH_PROG([LVS_BIN], [lvs], [/sbin/lvs])
 AC_PATH_PROG([MKDIR_BIN], [mkdir], [/bin/mkdir])
-AC_PATH_PROG([REALPATH_BIN], [realpath], [/usr/bin/realpath])
 AC_PATH_PROG([RM_BIN], [rm], [/bin/rm])
 AC_PATH_PROG([RMDIR_BIN], [rmdir], [/bin/rmdir])
 AC_PATH_PROG([TOUCH_BIN], [touch], [/usr/bin/touch])
@@ -49,15 +48,14 @@ AC_DEFINE_UNQUOTED([CHATTR_BIN], ["$CHATTR_BIN"], [Path of chattr program.])
 AC_DEFINE_UNQUOTED([CHSNAP_BIN], ["$CHSNAP_BIN"], [Path of chsnap program.])
 AC_DEFINE_UNQUOTED([CP_BIN], ["$CP_BIN"], [Path of cp program.])
 AC_DEFINE_UNQUOTED([DIFF_BIN], ["$DIFF_BIN"], [Path of diff program.])
-AC_DEFINE_UNQUOTED([FINDMNT_BIN], ["$FINDMNT_BIN"], [Path of findmnt program.])
 AC_DEFINE_UNQUOTED([LVCHANGE_BIN], ["$LVCHANGE_BIN"], [Path of lvchange program.])
 AC_DEFINE_UNQUOTED([LVCREATE_BIN], ["$LVCREATE_BIN"], [Path of lvcreate program.])
+AC_DEFINE_UNQUOTED([LS_BIN], ["$LS_BIN"], [Path of ls program.])
 AC_DEFINE_UNQUOTED([LVM_BIN], ["$LVM_BIN"], [Path of lvm program.])
 AC_DEFINE_UNQUOTED([LVREMOVE_BIN], ["$LVREMOVE_BIN"], [Path of lvremove program.])
 AC_DEFINE_UNQUOTED([LVRENAME_BIN], ["$LVRENAME_BIN"], [Path of lvrename program.])
 AC_DEFINE_UNQUOTED([LVS_BIN], ["$LVS_BIN"], [Path of lvs program.])
 AC_DEFINE_UNQUOTED([MKDIR_BIN], ["$MKDIR_BIN"], [Path of mkdir program.])
-AC_DEFINE_UNQUOTED([REALPATH_BIN], ["$REALPATH_BIN"], [Path of realpath program.])
 AC_DEFINE_UNQUOTED([RM_BIN], ["$RM_BIN"], [Path of rm program.])
 AC_DEFINE_UNQUOTED([RMDIR_BIN], ["$RMDIR_BIN"], [Path of rmdir program.])
 AC_DEFINE_UNQUOTED([TOUCH_BIN], ["$TOUCH_BIN"], [Path of touch program.])
index 7a6e202f8929cdf939db3c3ab18d4e13ff3476cb..8e17f5e2a3b2fae78180ce96c6316adc176405e1 100644 (file)
@@ -2,13 +2,13 @@
 <refentry id='snapper-backup-configs5'>
 
   <refentryinfo>
-    <date>2025-10-07</date>
+    <date>2025-10-13</date>
   </refentryinfo>
 
   <refmeta>
     <refentrytitle>snapper-backup-configs</refentrytitle>
     <manvolnum>5</manvolnum>
-    <refmiscinfo class='date'>2025-10-07</refmiscinfo>
+    <refmiscinfo class='date'>2025-10-13</refmiscinfo>
     <refmiscinfo class='version'>@VERSION@</refmiscinfo>
     <refmiscinfo class='manual'>Filesystem Snapshot Management</refmiscinfo>
   </refmeta>
       </varlistentry>
 
       <varlistentry>
-       <term><option>target-findmnt-bin</option></term>
+       <term><option>target-ls-bin</option></term>
        <listitem>
-         <para>Location of the findmnt binary on the target. Can also
+         <para>Location of the ls binary on the target. Can also
          be used to install wrapper scripts. Optional.</para>
        </listitem>
       </varlistentry>
        </listitem>
       </varlistentry>
 
-      <varlistentry>
-       <term><option>target-realpath-bin</option></term>
-       <listitem>
-         <para>Location of the realpath binary on the target. Can also
-         be used to install wrapper scripts. Optional.</para>
-       </listitem>
-      </varlistentry>
-
       <varlistentry>
        <term><option>target-rm-bin</option></term>
        <listitem>
index ee7331f590fec390d520801f8fca604a3e1205f8..33aa71f369a0f40103fed1c6657132cc560b3d39 100644 (file)
@@ -1,3 +1,9 @@
+-------------------------------------------------------------------
+Mon Oct 13 08:43:43 CEST 2025 - aschnell@suse.com
+
+- redesigned target snapshot detection in snbk
+  (gh#openSUSE/snapper#1061)
+
 -------------------------------------------------------------------
 Tue Oct 07 14:42:16 CEST 2025 - aschnell@suse.com