diff --git a/Makefile b/Makefile index 4412259f..5a31ddd7 100644 --- a/Makefile +++ b/Makefile @@ -111,8 +111,6 @@ $(TARGET): src/version.hpp obj/obj-stamp $(OBJ) clone: $(TARGET) $(LN) -fs "$<" "$@" -fsck.mergerfs: tools/fsck.mergerfs - mount.mergerfs: $(TARGET) $(LN) -fs "$<" "$@" @@ -145,7 +143,7 @@ clean: rpm-clean distclean: clean $(GIT) clean -fd -install: install-base install-clone install-mount.mergerfs install-tools install-man +install: install-base install-clone install-mount.mergerfs install-man install-base: $(TARGET) $(INSTALL) -v -m 0755 -D "$(TARGET)" "$(INSTALLBINDIR)/$(TARGET)" @@ -158,9 +156,6 @@ install-mount.mergerfs: mount.mergerfs $(MKDIR) -p "$(INSTALLBINDIR)" $(CP) -a "$<" "$(INSTALLBINDIR)/$<" -install-tools: fsck.mergerfs - $(INSTALL) -v -m 0755 -D "tools/$<" "$(INSTALLSBINDIR)/$<" - install-man: $(MANPAGE) $(INSTALL) -v -m 0644 -D "$(MANPAGE)" "$(INSTALLMAN1DIR)/$(MANPAGE)" diff --git a/README.md b/README.md index ccefa15e..0f865129 100644 --- a/README.md +++ b/README.md @@ -304,7 +304,9 @@ A B C # TOOLING -* /usr/sbin/fsck.mergerfs: Provides permissions and ownership auditing and the ability to fix them. +Find extra tooling to help with managing `mergerfs` at: https://github.com/trapexit/mergerfs-tools + +* fsck.mergerfs: Provides permissions and ownership auditing and the ability to fix them # TIPS / NOTES diff --git a/tools/fsck.mergerfs b/tools/fsck.mergerfs deleted file mode 100755 index 2db3c598..00000000 --- a/tools/fsck.mergerfs +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2016, Antonio SJ Musumeci - -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. - -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import argparse -import os -import xattr -import errno - - -def main(): - parser = argparse.ArgumentParser(description='audit a mergerfs mount for inconsistencies') - parser.add_argument('device',type=str,help='device') - parser.add_argument('-v','--verbose',action='store_true',help='print details of audit item') - parser.add_argument('-f','--fix',choices=['manual','newest'],help='fix policy') - - args = parser.parse_args() - - if args.fix: - args.verbose = True - - if args.fix == 'manual': - fix = manual_fix - elif args.fix == 'newest': - fix = newest_fix - else: - fix = noop_fix - - try: - controlfile = os.path.join(args.device,".mergerfs") - version = xattr.getxattr(controlfile,"user.mergerfs.version") - - for (dirname,dirnames,filenames) in os.walk(args.device): - fulldirpath = os.path.join(args.device,dirname) - check_consistancy(fulldirpath,args.verbose,fix) - for filename in filenames: - fullpath = os.path.join(fulldirpath,filename) - check_consistancy(fullpath,args.verbose,fix) - - except IOError as e: - if e.errno == errno.ENOENT: - print("%s is not a mergerfs device" % args.device) - else: - print("IOError: %s" % e.strerror) - - -def check_consistancy(fullpath,verbose,fix): - paths = xattr.getxattr(fullpath,"user.mergerfs.allpaths").split('\0') - if len(paths) > 1: - stats = [os.stat(path) for path in paths] - if stats_different(stats): - print("mismatch: %s" % fullpath) - if verbose: - print_stats(paths,stats) - fix(paths,stats) - - -def noop_fix(paths,stats): - pass - - -def manual_fix(paths,stats): - done = False - while not done: - try: - value = input('Which is correct?: ') - setstat(stats[value % len(paths)],paths) - done = True - except NameError: - print("Input error: enter a value between 0 and %d" % (len(paths)-1)) - except Exception as e: - print("%s" % e) - done = True - - -def newest_fix(paths,stats): - stats.sort(key=lambda stat: stat.st_mtime) - try: - setstat(stats[-1],paths) - except Exception as e: - print("%s" % e) - - -def setstat(stat,paths): - for path in paths: - try: - os.chmod(path,stat.st_mode) - os.chown(path,stat.st_uid,stat.st_gid); - print("setting %s > uid: %d gid: %d mode: %o" % - (path,stat.st_uid,stat.st_gid,stat.st_mode)) - except Exception as e: - print("%s" % e) - - -def stats_different(stats): - base = stats[0] - for stat in stats: - if ((stat.st_mode == base.st_mode) and - (stat.st_uid == base.st_uid) and - (stat.st_gid == base.st_gid)): - continue - return True - return False - - -def print_stats(Files,Stats): - for i in xrange(0,len(Files)): - print("- %i: %s > uid: %s; gid: %s; mode: %o" % - (i,Files[i],Stats[i].st_uid,Stats[i].st_gid,Stats[i].st_mode)) - - -if __name__ == "__main__": - main()