]> git.ipfire.org Git - thirdparty/snapper.git/commitdiff
Merge branch 'master' into dbus
authorArvin Schnell <aschnell@suse.de>
Wed, 29 Aug 2012 15:55:59 +0000 (17:55 +0200)
committerArvin Schnell <aschnell@suse.de>
Wed, 29 Aug 2012 15:55:59 +0000 (17:55 +0200)
13 files changed:
1  2 
configure.in
doc/snapper.8.in
snapper.spec.in
snapper/AppUtil.cc
snapper/AppUtil.h
snapper/File.cc
snapper/Filesystem.cc
snapper/Filesystem.h
snapper/Logger.cc
snapper/Makefile.am
snapper/Snapper.cc
snapper/Snapshot.cc
tools/Makefile.am

diff --cc configure.in
Simple merge
Simple merge
diff --cc snapper.spec.in
index a46663d00fd1faf8d2e28a2b91fba02458be1c33,3d582653350dccb88ef2fe48519cad4c984685da..cb05ad1a50277643577645b0c017650fa9c64c18
@@@ -62,7 -61,7 +62,7 @@@ autoheade
  automake --add-missing --copy
  autoconf
  
- ./configure --libdir=%{_libdir} --prefix=%{prefix} --mandir=%{_mandir} --disable-silent-rules
 -./configure --libdir=%{_libdir} --prefix=%{prefix} --mandir=%{_mandir} --docdir=%{prefix}/share/doc/packages/snapper --disable-silent-rules
++./configure --libdir=%{_libdir} --prefix=%{prefix} --mandir=%{_mandir} --docdir=%{prefix}/share/doc/packages/snapper --disable-ext4 --disable-silent-rules
  make %{?jobs:-j%jobs}
  
  %install
index 5c1d276ff9cc7dc93881168f2da1f1db55ffc13b,146d9e4b42ced8c024a2bdac8e43faf0bc83df64..638487d293ccbc9eebec8ee4ae8c1121d50a40f3
@@@ -199,22 -208,42 +208,58 @@@ namespace snappe
      }
  
  
+     bool
+     getMtabData(const string& mount_point, bool& found, MtabData& mtab_data)
+     {
+       FILE* f = setmntent("/etc/mtab", "r");
+       if (!f)
+       {
+           y2err("setmntent failed");
+           return false;
+       }
+       found = false;
+       struct mntent* m;
+       while ((m = getmntent(f)))
+       {
+           if (strcmp(m->mnt_type, "rootfs") == 0)
+               continue;
+           if (m->mnt_dir == mount_point)
+           {
+               found = true;
+               mtab_data.device = m->mnt_fsname;
+               mtab_data.dir = m->mnt_dir;
+               mtab_data.type = m->mnt_type;
+               boost::split(mtab_data.options, m->mnt_opts, boost::is_any_of(","),
+                            boost::token_compress_on);
+               break;
+           }
+       }
+       endmntent(f);
+       return true;
+     }
 +    string
 +    stringerror(int errnum)
 +    {
 +#if (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE
 +      char buf1[100];
 +      if (strerror_r(errno, buf1, sizeof(buf1)-1) == 0)
 +          return string(buf1);
 +      return string("strerror failed");
 +#else
 +      char buf1[100];
 +      const char* buf2 = strerror_r(errno, buf1, sizeof(buf1)-1);
 +      return string(buf2);
 +#endif
 +    }
 +
 +
      string
      sformat(const string& format, ...)
      {
index 4bca1e7cba662293e1c734121438077103949803,14433eda9ff381c0c396480d3ed2e17581de6c31..fb6280017c14b5489f57394fbbf3db46ac968c5c
@@@ -55,8 -59,17 +58,20 @@@ namespace snappe
  
      string realpath(const string& path);
  
 +    string stringerror(int errnum);
 +
++
+     struct MtabData
+     {
+       string device;
+       string dir;
+       string type;
+       vector<string> options;
+     };
+     bool getMtabData(const string& mount_point, bool& found, MtabData& mtab_data);
      template<class StreamType>
      void classic(StreamType& stream)
      {
diff --cc snapper/File.cc
index a970a8029d2489a84e0007b7307caa36d738b69d,bd8317b549c63dfca771ad2493abeda332c7e02b..9fc1ed676ab60c409644bdbb8ed6cfef93c28ffc
  #include "snapper/AppUtil.h"
  #include "snapper/Enum.h"
  #include "snapper/SnapperTmpl.h"
--#include "snapper/SystemCmd.h"
  #include "snapper/SnapperDefines.h"
  #include "snapper/Compare.h"
 -#include "snapper/AsciiFile.h"
  #include "snapper/Exception.h"
  
  
index f8b0ec66d9aee5f300b47e9d432a29352129db4a,2aabfded08729057f32e7dd51a0c18bb7496cf09..12bd2298b3fe1f1ebf4c210dad99e70db520124e
  #include <sys/types.h>
  #include <errno.h>
  #include <unistd.h>
 +#include <mntent.h>
 +#include <fcntl.h>
 +#include <sys/ioctl.h>
 +#include <asm/types.h>
+ #include <boost/algorithm/string.hpp>
  
  #include "snapper/Log.h"
  #include "snapper/Filesystem.h"
  #include "snapper/SnapperTmpl.h"
  #include "snapper/SystemCmd.h"
  #include "snapper/SnapperDefines.h"
+ #include "snapper/Regex.h"
+ #include "config.h"
  
  
 +#define BTRFS_IOCTL_MAGIC 0x94
 +#define BTRFS_PATH_NAME_MAX 4087
 +#define BTRFS_SUBVOL_NAME_MAX 4039
 +#define BTRFS_SUBVOL_RDONLY (1ULL << 1)
 +
 +#define BTRFS_IOC_SUBVOL_CREATE _IOW(BTRFS_IOCTL_MAGIC, 14, struct btrfs_ioctl_vol_args)
 +#define BTRFS_IOC_SNAP_DESTROY _IOW(BTRFS_IOCTL_MAGIC, 15, struct btrfs_ioctl_vol_args)
 +#define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, struct btrfs_ioctl_vol_args_v2)
 +
 +struct btrfs_ioctl_vol_args
 +{
 +    __s64 fd;
 +    char name[BTRFS_PATH_NAME_MAX + 1];
 +};
 +
 +struct btrfs_ioctl_vol_args_v2
 +{
 +    __s64 fd;
 +    __u64 transid;
 +    __u64 flags;
 +    __u64 unused[4];
 +    char name[BTRFS_SUBVOL_NAME_MAX + 1];
 +};
 +
 +
  namespace snapper
  {
  
      }
  
  
 +    SDir
 +    Filesystem::openSubvolumeDir() const
 +    {
 +      SDir subvolume_dir(subvolume);
 +
 +      return subvolume_dir;
 +    }
 +
 +
 +    SDir
 +    Filesystem::openInfoDir(unsigned int num) const
 +    {
 +      SDir infos_dir = openInfosDir();
 +      SDir info_dir(infos_dir, decString(num));
 +
 +      return info_dir;
 +    }
 +
 +
+ #ifdef ENABLE_BTRFS
+     Filesystem*
+     Btrfs::create(const string& fstype, const string& subvolume)
+     {
+       if (fstype == "btrfs")
+           return new Btrfs(subvolume);
+       return NULL;
+     }
      Btrfs::Btrfs(const string& subvolume)
        : Filesystem(subvolume)
      {
      bool
      Btrfs::checkSnapshot(unsigned int num) const
      {
 -      return checkDir(snapshotDir(num));
 +      try
 +      {
 +          SDir info_dir = openInfoDir(num);
 +
 +          struct stat stat;
 +          int r = info_dir.stat("snapshot", &stat, AT_SYMLINK_NOFOLLOW);
 +          // check st_ino == 256 is copied from btrfsprogs
 +          return r == 0 && stat.st_ino == 256 && S_ISDIR(stat.st_mode);
 +      }
 +      catch (const IOErrorException& e)
 +      {
 +          return false;
 +      }
 +    }
 +
 +
 +    bool
 +    Btrfs::create_subvolume(int fddst, const string& name) const
 +    {
 +      struct btrfs_ioctl_vol_args args;
 +      memset(&args, 0, sizeof(args));
 +
 +      strncpy(args.name, name.c_str(), BTRFS_PATH_NAME_MAX);
 +
 +        return ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE, &args) == 0;
 +    }
 +
 +
 +    bool
 +    Btrfs::create_snapshot(int fd, int fddst, const string& name) const
 +    {
 +      struct btrfs_ioctl_vol_args_v2 args;
 +      memset(&args, 0, sizeof(args));
 +
 +      args.fd = fd;
 +      args.flags |= BTRFS_SUBVOL_RDONLY;
 +      strncpy(args.name, name.c_str(), BTRFS_SUBVOL_NAME_MAX);
 +
 +      return ioctl(fddst, BTRFS_IOC_SNAP_CREATE_V2, &args) == 0;
 +    }
 +
 +
 +    bool
 +    Btrfs::delete_subvolume(int fd, const string& name) const
 +    {
 +      struct btrfs_ioctl_vol_args args;
 +      memset(&args, 0, sizeof(args));
 +
 +      strncpy(args.name, name.c_str(), BTRFS_PATH_NAME_MAX);
 +
 +      return ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args) == 0;
      }
+     // ENABLE_BTRFS
+ #endif
++
+ #ifdef ENABLE_EXT4
+     Filesystem*
+     Ext4::create(const string& fstype, const string& subvolume)
+     {
+       if (fstype == "ext4")
+           return new Ext4(subvolume);
+       return NULL;
+     }
  
  
      Ext4::Ext4(const string& subvolume)
      {
        return checkNormalFile(snapshotFile(num));
      }
+     // ENABLE_EXT4
+ #endif
++
+ #ifdef ENABLE_LVM
+     Filesystem*
+     Lvm::create(const string& fstype, const string& subvolume)
+     {
+       if (fstype == "lvm")
+           return new Lvm(subvolume, "auto");
+       Regex rx("^lvm\\(([_a-z0-9]+)\\)$");
+       if (rx.match(fstype))
+           return new Lvm(subvolume, rx.cap(1));
+       return NULL;
+     }
+     Lvm::Lvm(const string& subvolume, const string& mount_type)
+       : Filesystem(subvolume), mount_type(mount_type)
+     {
+       if (access(LVCREATE, X_OK) != 0)
+       {
+           throw ProgramNotInstalledException(LVCREATE " not installed");
+       }
+       bool found = false;
+       MtabData mtab_data;
+       if (!getMtabData(subvolume, found, mtab_data))
+           throw InvalidConfigException();
+       if (!found)
+       {
+           y2err("filesystem not mounted");
+           throw InvalidConfigException();
+       }
+       if (!detectLvmNames(mtab_data))
+           throw InvalidConfigException();
+       mount_options = mtab_data.options;
+       mount_options.erase(remove(mount_options.begin(), mount_options.end(), "rw"),
+                           mount_options.end());
+       mount_options.push_back("noatime");
+       if (mount_type == "xfs")
+           mount_options.push_back("nouuid");
+     }
+     void
+     Lvm::createConfig() const
+     {
+       int r1 = mkdir((subvolume + "/.snapshots").c_str(), 0700);
+       if (r1 != 0 && errno != EEXIST)
+       {
+           y2err("mkdir failed errno:" << errno << " (" << strerror(errno) << ")");
+           throw CreateConfigFailedException("mkdir failed");
+       }
+     }
+     void
+     Lvm::deleteConfig() const
+     {
+       int r1 = rmdir((subvolume + "/.snapshots").c_str());
+       if (r1 != 0)
+       {
+           y2err("rmdir failed errno:" << errno << " (" << strerror(errno) << ")");
+           throw DeleteConfigFailedException("rmdir failed");
+       }
+     }
+     string
+     Lvm::infosDir() const
+     {
+       return (subvolume == "/" ? "" : subvolume) + "/.snapshots";
+     }
+     string
+     Lvm::snapshotDir(unsigned int num) const
+     {
+       return (subvolume == "/" ? "" : subvolume) + "/.snapshots/" + decString(num) +
+           "/snapshot";
+     }
++    SDir
++    Lvm::openInfosDir() const
++    {
++      SDir subvolume_dir = openSubvolumeDir();
++      SDir infos_dir(subvolume_dir, ".snapshots");
++
++      struct stat stat;
++      if (infos_dir.stat(".", &stat, AT_SYMLINK_NOFOLLOW) != 0)
++      {
++          throw IOErrorException();
++      }
++
++      if (stat.st_uid != 0 || stat.st_gid != 0)
++      {
++          y2err("owner of .snapshots wrong");
++          throw IOErrorException();
++      }
++
++      return infos_dir;
++    }
++
++
++    SDir
++    Lvm::openSnapshotDir(unsigned int num) const
++    {
++      SDir info_dir = openInfoDir(num);
++      SDir snapshot_dir(info_dir, "snapshot");
++
++      return snapshot_dir;
++    }
++
++
+     string
+     Lvm::snapshotLvName(unsigned int num) const
+     {
+       return lv_name + "-snapshot" + decString(num);
+     }
+     void
+     Lvm::createSnapshot(unsigned int num) const
+     {
+       sync();                 // TODO looks like a bug that this is needed (with ext4)
+       SystemCmd cmd(LVCREATE " --snapshot --name " + quote(snapshotLvName(num)) + " " +
+                     quote(vg_name + "/" + lv_name));
+       if (cmd.retcode() != 0)
+           throw CreateSnapshotFailedException();
+       int r1 = mkdir(snapshotDir(num).c_str(), 0700);
+       if (r1 != 0 && errno != EEXIST)
+       {
+           y2err("mkdir failed errno:" << errno << " (" << strerror(errno) << ")");
+           throw CreateSnapshotFailedException();
+       }
+     }
+     void
+     Lvm::deleteSnapshot(unsigned int num) const
+     {
+       SystemCmd cmd(LVREMOVE " --force " + quote(vg_name + "/" + snapshotLvName(num)));
+       if (cmd.retcode() != 0)
+           throw DeleteSnapshotFailedException();
+       rmdir(snapshotDir(num).c_str());
+     }
+     bool
+     Lvm::isSnapshotMounted(unsigned int num) const
+     {
+       bool mounted = false;
+       MtabData mtab_data;
+       if (!getMtabData(snapshotDir(num), mounted, mtab_data))
+           throw IsSnapshotMountedFailedException();
+       return mounted;
+     }
+     void
+     Lvm::mountSnapshot(unsigned int num) const
+     {
+       if (isSnapshotMounted(num))
+           return;
+       if (!mount(getDevice(num), snapshotDir(num), mount_type, mount_options))
+           throw MountSnapshotFailedException();
+     }
+     void
+     Lvm::umountSnapshot(unsigned int num) const
+     {
+       if (!isSnapshotMounted(num))
+           return;
+       if (!umount(snapshotDir(num)))
+           throw UmountSnapshotFailedException();
+     }
+     bool
+     Lvm::checkSnapshot(unsigned int num) const
+     {
+       return checkAnything(getDevice(num));
+     }
+     bool
+     Lvm::detectLvmNames(const MtabData& mtab_data)
+     {
+       Regex rx("^/dev/mapper/(.+[^-])-([^-].+)$");
+       if (rx.match(mtab_data.device))
+       {
+           vg_name = boost::replace_all_copy(rx.cap(1), "--", "-");
+           lv_name = boost::replace_all_copy(rx.cap(2), "--", "-");
+           return true;
+       }
+       y2err("could not detect lvm names from '" << mtab_data.device << "'");
+       return false;
+     }
+     string
+     Lvm::getDevice(unsigned int num) const
+     {
+       return "/dev/mapper/" + boost::replace_all_copy(vg_name, "-", "--") + "-" +
+           boost::replace_all_copy(snapshotLvName(num), "-", "--");
+     }
+     // ENABLE_LVM
+ #endif
  
  }
index 157e883eee83d3a4ac35a9ce566a5114b23784db,7e5a6ef68e5d68be4f356cf1938f8cbfa4740b57..51cc0fb038739408921d6943a36474c2ffa79132
  
  
  #include <string>
+ #include <vector>
  
 +#include "snapper/FileUtils.h"
+ #include "config.h"
  
 +
  namespace snapper
  {
      using std::string;
@@@ -74,7 -71,7 +78,8 @@@
  
      };
  
 +
+ #ifdef ENABLE_BTRFS
      class Btrfs : public Filesystem
      {
      public:
  
        virtual bool checkSnapshot(unsigned int num) const;
  
 +    private:
 +
 +      bool create_subvolume(int fddst, const string& name) const;
 +      bool create_snapshot(int fd, int fddst, const string& name) const;
 +      bool delete_subvolume(int fd, const string& name) const;
 +
      };
+ #endif
  
 +
+ #ifdef ENABLE_EXT4
      class Ext4 : public Filesystem
      {
      public:
  
        virtual bool checkSnapshot(unsigned int num) const;
  
+     private:
+       vector<string> mount_options;
      };
+ #endif
++
+ #ifdef ENABLE_LVM
+     class Lvm : public Filesystem
+     {
+     public:
+       static Filesystem* create(const string& fstype, const string& subvolume);
+       Lvm(const string& subvolume, const string& mount_type);
+       virtual string fstype() const { return "lvm(" + mount_type + ")"; }
+       virtual void createConfig() const;
+       virtual void deleteConfig() const;
+       virtual string infosDir() const;
+       virtual string snapshotDir(unsigned int num) const;
+       virtual string snapshotLvName(unsigned int num) const;
++      virtual SDir openInfosDir() const;
++      virtual SDir openSnapshotDir(unsigned int num) const;
++
+       virtual void createSnapshot(unsigned int num) const;
+       virtual void deleteSnapshot(unsigned int num) const;
+       virtual bool isSnapshotMounted(unsigned int num) const;
+       virtual void mountSnapshot(unsigned int num) const;
+       virtual void umountSnapshot(unsigned int num) const;
+       virtual bool checkSnapshot(unsigned int num) const;
+     private:
+       const string mount_type;
+       bool detectLvmNames(const MtabData& mtab_data);
+       string getDevice(unsigned int num) const;
+       string vg_name;
+       string lv_name;
+       vector<string> mount_options;
+     };
+ #endif
  
  }
  
index 7be1e295e62c391be9df2bd7fce97e7fae0e8143,15e274b618f2038ddd88f0b2f6d91f8c99df70ce..133812f026496d28f8b5dcb7cd72820a3aefbb16
@@@ -67,11 -69,7 +70,11 @@@ namespace snappe
        string prefix = sformat("%s %s libsnapper(%d) %s(%s):%d", datetime(time(0), false, true).c_str(),
                                ln[level], getpid(), file, func, line);
  
-       FILE* f = fopen(filename.c_str(), "a");
 +      static boost::mutex mutex;
 +
 +      boost::lock_guard<boost::mutex> lock(mutex);
 +
+       FILE* f = fopen(filename->c_str(), "a");
        if (f)
        {
            string tmp = text;
  
        if (geteuid())
        {
 -          struct passwd* pw = getpwuid(geteuid());
 -          if (pw)
 +          struct passwd pwd;
 +          struct passwd* result;
 +
 +          long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
 +          char buf[bufsize];
 +
 +          if (getpwuid_r(geteuid(), &pwd, buf, bufsize, &result) == 0 && result == &pwd)
            {
-               filename = string(pwd.pw_dir) + "/.snapper.log";
+               delete filename;
 -              filename = new string(string(pw->pw_dir) + "/.snapper.log");
++              filename = new string(string(pwd.pw_dir) + "/.snapper.log");
            }
        }
  
index bb2c9beaa64c400d1069844abf2443e8a504cff1,5603577e3625d91dbed300980ef4386fc99afc62..2f3452c3cee6490ba16ca56ee049171780975a9b
@@@ -2,11 -2,8 +2,10 @@@
  # Makefile.am for snapper/snapper
  #
  
- AM_CXXFLAGS = -D_FILE_OFFSET_BITS=64
 -AM_CXXFLAGS = -D_FILE_OFFSET_BITS=64 -DLIBDIR=\"$(libdir)\" -I/usr/include/libxml2
++AM_CXXFLAGS = -D_FILE_OFFSET_BITS=64 -DLIBDIR=\"$(libdir)\"
 +
 +INCLUDES = -I/usr/include/libxml2
  
  lib_LTLIBRARIES = libsnapper.la
  
  libsnapper_la_SOURCES =                                       \
Simple merge
index 07a9fe8a4ef2d40c0c485580683c2b5a83bced5e,8e9cc37807f6f9db61fdb3088f8d345081df8e8c..457f11f2971441d461f974115d72d88509879d9b
@@@ -36,7 -34,7 +36,6 @@@
  #include "snapper/Filesystem.h"
  #include "snapper/Enum.h"
  #include "snapper/SnapperTmpl.h"
--#include "snapper/SystemCmd.h"
  #include "snapper/SnapperDefines.h"
  #include "snapper/Exception.h"
  
Simple merge