From: Arvin Schnell Date: Wed, 29 Aug 2012 15:55:59 +0000 (+0200) Subject: Merge branch 'master' into dbus X-Git-Tag: v0.1.3~134 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6cbeda42c9cd7f0ce469afdb13c101c4d444d875;p=thirdparty%2Fsnapper.git Merge branch 'master' into dbus --- 6cbeda42c9cd7f0ce469afdb13c101c4d444d875 diff --cc snapper.spec.in index a46663d0,3d582653..cb05ad1a --- a/snapper.spec.in +++ b/snapper.spec.in @@@ -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 diff --cc snapper/AppUtil.cc index 5c1d276f,146d9e4b..638487d2 --- a/snapper/AppUtil.cc +++ b/snapper/AppUtil.cc @@@ -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, ...) { diff --cc snapper/AppUtil.h index 4bca1e7c,14433eda..fb628001 --- a/snapper/AppUtil.h +++ b/snapper/AppUtil.h @@@ -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 options; + }; + + bool getMtabData(const string& mount_point, bool& found, MtabData& mtab_data); + + template void classic(StreamType& stream) { diff --cc snapper/File.cc index a970a802,bd8317b5..9fc1ed67 --- a/snapper/File.cc +++ b/snapper/File.cc @@@ -34,9 -34,11 +34,8 @@@ #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" diff --cc snapper/Filesystem.cc index f8b0ec66,2aabfded..12bd2298 --- a/snapper/Filesystem.cc +++ b/snapper/Filesystem.cc @@@ -25,10 -25,7 +25,11 @@@ #include #include #include +#include +#include +#include +#include + #include #include "snapper/Log.h" #include "snapper/Filesystem.h" @@@ -36,33 -33,10 +37,35 @@@ #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 { @@@ -79,25 -93,17 +122,36 @@@ } + 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) { @@@ -230,58 -188,20 +284,71 @@@ 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) @@@ -484,5 -388,197 +549,230 @@@ { 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 } diff --cc snapper/Filesystem.h index 157e883e,7e5a6ef6..51cc0fb0 --- a/snapper/Filesystem.h +++ b/snapper/Filesystem.h @@@ -25,10 -25,10 +25,12 @@@ #include + #include +#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: @@@ -101,15 -97,10 +108,17 @@@ 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: @@@ -137,7 -127,55 +148,59 @@@ virtual bool checkSnapshot(unsigned int num) const; + private: + + vector 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 mount_options; + + }; + #endif } diff --cc snapper/Logger.cc index 7be1e295,15e274b6..133812f0 --- a/snapper/Logger.cc +++ b/snapper/Logger.cc @@@ -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); + static boost::mutex mutex; + + boost::lock_guard lock(mutex); + - FILE* f = fopen(filename.c_str(), "a"); + FILE* f = fopen(filename->c_str(), "a"); if (f) { string tmp = text; @@@ -139,15 -138,11 +143,16 @@@ 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"); } } diff --cc snapper/Makefile.am index bb2c9bea,5603577e..2f3452c3 --- a/snapper/Makefile.am +++ b/snapper/Makefile.am @@@ -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 = \ diff --cc snapper/Snapshot.cc index 07a9fe8a,8e9cc378..457f11f2 --- a/snapper/Snapshot.cc +++ b/snapper/Snapshot.cc @@@ -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"