Skip to content

Instantly share code, notes, and snippets.

@dgdavid dgdavid/btrfs_checker.rb
Last active Jan 30, 2019

Embed
What would you like to do?
Check if the given path is in a btrfs filesystem
require 'yast'
require 'yast2/execute'
require 'pathname'
# Returns if the given path is placed in a btrfs
#
# @param path [String, Pathname]
#
# @return [Boolean]
def btrfs_available_for?(path)
mounted_btrfs = Yast::Execute.locally!.stdout(
["df", "-t", "btrfs", "--output=target"],
["tail", "-n", "+2"]
).split.uniq
not_mounted_btrfs = Yast::Execute.locally!.stdout(
["df", "-x", "btrfs", "--output=target"],
["tail", "-n", "+2"]
).split.uniq
candidate_paths = Pathname.new(path).descend.map(&:to_s)
return false if mounted_btrfs.empty?
return false if (not_mounted_btrfs & candidate_paths).any?
(mounted_btrfs & candidate_paths).any?
end
# Simply for testing (manually, through irb) the scenario
# > for a system with "/" in btrfs and a separate "/home" with ext4
#
def fake_btrfs_available_for?(path)
candidate_paths = Pathname.new(path).descend.map(&:to_s)
return false if btrfs_targets.empty?
return false if (not_btrfs_targets & candidate_paths).any?
(btrfs_targets & candidate_paths).any?
end
def btrfs_targets
["/"]
end
def not_btrfs_targets
["/home"]
end
@dgdavid

This comment has been minimized.

Copy link
Owner Author

commented Jan 30, 2019

In a system with below df output

ytm@linux-9x6v:~/suse/src> df -t btrfs
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/vda2       10476524 6597212   3644836  65% /
/dev/vda2       10476524 6597212   3644836  65% /tmp
/dev/vda2       10476524 6597212   3644836  65% /srv
/dev/vda2       10476524 6597212   3644836  65% /var
/dev/vda2       10476524 6597212   3644836  65% /opt
/dev/vda2       10476524 6597212   3644836  65% /usr/local
/dev/vda2       10476524 6597212   3644836  65% /home
/dev/vda2       10476524 6597212   3644836  65% /boot/grub2/i386-pc
/dev/vda2       10476524 6597212   3644836  65% /boot/grub2/x86_64-efi
/dev/vda2       10476524 6597212   3644836  65% /root

it will returns true

irb(main):001:0> require_relative './btrfs_check_poc.rb'
=> true
irb(main):002:0> btrfs_available_for?('/home/ytm_tester')
=> true
irb(main):003:0>

@dgdavid

This comment has been minimized.

Copy link
Owner Author

commented Jan 30, 2019

In a system with below df output

❯ df -t btrfs
df: no file systems processed

it will returns false

irb(main):001:0> require_relative './btrfs_check_poc.rb'
=> true
irb(main):002:0> btrfs_available_for?('/home/ytm_tester')
=> false
irb(main):003:0> 
@dgdavid

This comment has been minimized.

Copy link
Owner Author

commented Jan 30, 2019

for a system with "/" in btrfs and a separate "/home" with ext4

irb(main):001:0> require_relative './btrfs_check_poc.rb'
=> true
irb(main):002:0> btrfs_available_for?('/home/ytm_tester')
=> false
irb(main):003:0> btrfs_available_for?('/alternative_home/ytm_tester')
=> true
@wfeldt

This comment has been minimized.

Copy link

commented Jan 30, 2019

I would have gone for something like df --output=fstype /home simply to avoid path operations and symlink complications.

What if /home is a symlink to a different file system?

@dgdavid

This comment has been minimized.

Copy link
Owner Author

commented Jan 30, 2019

Thank you @wfeldt

So,

def btrfs?(path)
  dirname = Pathname.new(path).dirname
  fstype = Yast::Execute.locally!.stdout(
    ["df", "--output=fstype", dirname],
    ["tail", "-n", "+2"]
  ).chomp

  fstype == "btrfs"
end

will be enough :)

@lslezak

This comment has been minimized.

Copy link

commented Jan 30, 2019

Related to the recent security hardening, we should call /usr/bin/df (with full path).

But I found an easier way:

# /usr/bin/stat -f --format '%T' /home
xfs

No need for removing the df header from the output...

@lslezak

This comment has been minimized.

Copy link

commented Jan 30, 2019

Ah, you might need to add the --dereference to follow symlinks...

@dgdavid

This comment has been minimized.

Copy link
Owner Author

commented Jan 30, 2019

@lslezak,

Pretty nice! Thank you!

@dgdavid

This comment has been minimized.

Copy link
Owner Author

commented Jan 30, 2019

BTW,

Related to the recent security hardening

Thank you for the reminder! :) I was using the Yast::Execute.locally! because of this, but I forgot to use the full path.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.