Skip to content

Commit

Permalink
Merge pull request #68 from djberg96/dragonflybsd
Browse files Browse the repository at this point in the history
Add Dragonflybsd support, refactor umount
  • Loading branch information
djberg96 authored Jun 9, 2024
2 parents d855269 + 52a5eaf commit f83af16
Show file tree
Hide file tree
Showing 10 changed files with 175 additions and 117 deletions.
6 changes: 6 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 1.5.0 - 8-Jun-2024
* Add support for DragonFlyBSD.
* Remove Solaris support. It's dead, Jim.
* Now assumes umount2 function is present on Linux systems, and some
corresponding refactoring of the umount method.

## 1.4.5 - 22-May-2024
* Handle the possibility that a statvs64 alias may not exist on some Linux
platforms. Thanks go to Antoine Martin for the report.
Expand Down
2 changes: 1 addition & 1 deletion lib/sys/filesystem.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ module Sys
# return objects of other types. Do not instantiate.
class Filesystem
# The version of the sys-filesystem library
VERSION = '1.4.5'
VERSION = '1.5.0'

# Stat objects are returned by the Sys::Filesystem.stat method. Here
# we're adding universal methods.
Expand Down
113 changes: 64 additions & 49 deletions lib/sys/unix/sys/filesystem.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,27 @@ class Stat
# The filesystem type, e.g. UFS.
attr_accessor :base_type

# The filesystem ID
attr_accessor :filesystem_id

# The filesystem type
attr_accessor :filesystem_type

# The user that mounted the filesystem
attr_accessor :owner

# Count of sync reads since mount
attr_accessor :sync_reads

# Count of sync writes since mount
attr_accessor :sync_writes

# Count of async reads since mount
attr_accessor :async_reads

# Count of async writes since mount
attr_accessor :async_writes

alias inodes files
alias inodes_free files_free
alias inodes_available files_available
Expand Down Expand Up @@ -250,6 +271,16 @@ def self.stat(path)
obj.base_type = fs[:f_basetype].to_s
end

# DragonFlyBSD has additional struct members
if RbConfig::CONFIG['host_os'] =~ /dragonfly/i
obj.owner = fs[:f_owner]
obj.filesystem_type = fs[:f_type]
obj.sync_reads= fs[:f_syncreads]
obj.async_reads= fs[:f_asyncreads]
obj.sync_writes = fs[:f_syncwrites]
obj.async_writes = fs[:f_asyncwrites]
end

obj.freeze
end

Expand Down Expand Up @@ -325,41 +356,23 @@ def self.mounts
raise SystemCallError.new(method_name, FFI.errno)
end

if RbConfig::CONFIG['host_os'] =~ /sunos|solaris/i
mt = Mnttab.new
while getmntent(fp, mt) == 0
obj = Sys::Filesystem::Mount.new
obj.name = mt[:mnt_special].to_s
obj.mount_point = mt[:mnt_mountp].to_s
obj.mount_type = mt[:mnt_fstype].to_s
obj.options = mt[:mnt_mntopts].to_s
obj.mount_time = Time.at(Integer(mt[:mnt_time]))

if block_given?
yield obj.freeze
else
array << obj.freeze
end
end
else
while ptr = getmntent(fp)
break if ptr.null?
mt = Mntent.new(ptr)

obj = Sys::Filesystem::Mount.new
obj.name = mt[:mnt_fsname]
obj.mount_point = mt[:mnt_dir]
obj.mount_type = mt[:mnt_type]
obj.options = mt[:mnt_opts]
obj.mount_time = nil
obj.dump_frequency = mt[:mnt_freq]
obj.pass_number = mt[:mnt_passno]

if block_given?
yield obj.freeze
else
array << obj.freeze
end
while ptr = getmntent(fp)
break if ptr.null?
mt = Mntent.new(ptr)

obj = Sys::Filesystem::Mount.new
obj.name = mt[:mnt_fsname]
obj.mount_point = mt[:mnt_dir]
obj.mount_type = mt[:mnt_type]
obj.options = mt[:mnt_opts]
obj.mount_time = nil
obj.dump_frequency = mt[:mnt_freq]
obj.pass_number = mt[:mnt_passno]

if block_given?
yield obj.freeze
else
array << obj.freeze
end
end
ensure
Expand Down Expand Up @@ -426,22 +439,24 @@ def self.mount(source, target, fstype = 'ext2', flags = 0, data = nil)
end

# Removes the attachment of the (topmost) filesystem mounted on target.
# Additional flags may be provided for operating systems that support
# the umount2 function. Otherwise this argument is ignored.
# You may also specify bitwise OR'd +flags+ to control the precise behavior.
# The possible flags on Linux are:
#
# Typically requires admin privileges.
# * MNT_FORCE - Abort pending requests, may cause data loss.
# * MNT_DETACH - Lazy umount, waits until the mount point is no longer busy.
# * MNT_EXPIRE - Mark mount point as expired, but don't actually remove it until
# a second call MNT_EXPIRE call is made.
#
def self.umount(target, flags = nil)
if flags && respond_to?(:umount2)
function = 'umount2'
rv = umount2_c(target, flags)
else
function = 'umount'
rv = umount_c(target)
end

if rv != 0
raise Error, "#{function} function failed: " + strerror(FFI.errno)
# * UMOUNT_NOFOLLOW - Don't dereference the target if it's a symbolic link.
#
# Note that BSD platforms may support different flags. Please see the man
# pages for details.
#
# Typically this method requires admin privileges.
#
def self.umount(target, flags = 0)
if umount_c(target, flags) != 0
raise Error, "umount function failed: #{strerror(FFI.errno)}"
end

self
Expand Down
2 changes: 2 additions & 0 deletions lib/sys/unix/sys/filesystem/constants.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ module Constants
MNT_DEFWRITE = 0x02000000 # filesystem should defer writes
MNT_MULTILABEL = 0x04000000 # MAC support for individual labels
MNT_NOATIME = 0x10000000 # disable update of file access time
MNT_NOCLUSTERR = 0x40000000 # disable cluster read
MNT_NOCLUSTERW = 0x80000000 # disable cluster write

MNT_VISFLAGMASK = (
MNT_RDONLY | MNT_SYNCHRONOUS | MNT_NOEXEC |
Expand Down
32 changes: 9 additions & 23 deletions lib/sys/unix/sys/filesystem/functions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,9 @@ def self.linux64?
end
end

def self.solaris?
RbConfig::CONFIG['host_os'] =~ /sunos|solaris/i
end

private_class_method :linux64?

if linux64? || solaris?
if linux64?
begin
attach_function(:statvfs, :statvfs64, %i[string pointer], :int)
rescue FFI::NotFoundError # Not every Linux distro has an alias
Expand All @@ -39,29 +35,19 @@ def self.solaris?
attach_function(:strerror, [:int], :string)
attach_function(:mount_c, :mount, %i[string string string ulong string], :int)

begin
attach_function(:umount_c, :umount, [:string], :int)
rescue FFI::NotFoundError
if RbConfig::CONFIG['host_os'] =~ /darwin|osx|mach|bsd/i
attach_function(:umount_c, :unmount, [:string], :int)
end
if RbConfig::CONFIG['host_os'] =~ /darwin|osx|mach|bsd|dragonfly/i
attach_function(:umount_c, :unmount, %i[string int], :int)
else
attach_function(:umount_c, :umount2, %i[string int], :int)
end

private_class_method :statvfs, :strerror, :mount_c, :umount_c

begin
if RbConfig::CONFIG['host_os'] =~ /sunos|solaris/i
attach_function(:fopen, %i[string string], :pointer)
attach_function(:fclose, [:pointer], :int)
attach_function(:getmntent, %i[pointer pointer], :int)
private_class_method :fopen, :fclose, :getmntent
else
attach_function(:getmntent, [:pointer], :pointer)
attach_function(:setmntent, %i[string string], :pointer)
attach_function(:endmntent, [:pointer], :int)
attach_function(:umount2, %i[string int], :int)
private_class_method :getmntent, :setmntent, :endmntent, :umount2
end
attach_function(:getmntent, [:pointer], :pointer)
attach_function(:setmntent, %i[string string], :pointer)
attach_function(:endmntent, [:pointer], :int)
private_class_method :getmntent, :setmntent, :endmntent
rescue FFI::NotFoundError
if RbConfig::CONFIG['host_os'] =~ /darwin|osx|mach/i
begin
Expand Down
75 changes: 54 additions & 21 deletions lib/sys/unix/sys/filesystem/structs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@
module Sys
class Filesystem
module Structs
# Used by DragonFlyBSD
class UUID < FFI::Struct
UUID_NODE_LEN = 6

layout(
:time_low, :uint32,
:time_mid, :uint16,
:time_hi_and_version, :uint16,
:clock_seq_hi_and_reserved, :uint8,
:clock_seq_low, :uint8,
:node, [:uint8, UUID_NODE_LEN]
)
end

# The Statfs struct is a subclass of FFI::Struct that corresponds to a struct statfs.
class Statfs < FFI::Struct
# Private method that will determine the layout of the struct on Linux.
Expand Down Expand Up @@ -86,6 +100,31 @@ def self.linux64?
:f_spare, [:ulong, 4]
)
end
when /dragonfly/i
layout(
:f_spare2, :long,
:f_bsize, :long,
:f_iosize, :long,
:f_blocks, :long,
:f_bfree, :long,
:f_bavail, :long,
:f_files, :long,
:f_ffree, :long,
:f_fsid, [:int32_t, 2],
:f_owner, :uid_t,
:f_type, :int,
:f_flags, :int,
:f_syncwrites, :long,
:f_asyncwrites, :long,
:f_fstypename, [:char, 16],
:f_mntonname, [:char, 80],
:f_syncreads, :long,
:f_asyncreads, :long,
:f_spares1, :short,
:f_mntfromname, [:char, 80],
:f_spares2, :short,
:f_spare, [:long,2]
)
else
layout(
:f_bsize, :uint32,
Expand Down Expand Up @@ -148,22 +187,27 @@ def self.linux64?
:f_fsid, :ulong,
:f_namemax, :ulong
)
elsif RbConfig::CONFIG['host'] =~ /sunos|solaris/i
elsif RbConfig::CONFIG['host'] =~ /dragonfly/i
layout(
:f_bsize, :ulong,
:f_frsize, :ulong,
:f_blocks, :uint64_t,
:f_bfree, :uint64_t,
:f_bavail, :uint64_t,
:f_files, :uint64_t,
:f_ffree, :uint64_t,
:f_favail, :uint64_t,
:f_blocks, :uint64,
:f_bfree, :uint64,
:f_bavail, :uint64,
:f_files, :uint64,
:f_ffree, :uint64,
:f_favail, :uint64,
:f_fsid, :ulong,
:f_basetype, [:char, 16],
:f_flag, :ulong,
:f_namemax, :ulong,
:f_fstr, [:char, 32],
:f_filler, [:ulong, 16]
:f_owner, :uid_t,
:f_type, :uint,
:f_syncreads, :uint64,
:f_syncwrites, :uint64,
:f_asyncreads, :uint64,
:f_asyncwrites, :uint64,
:f_fsid_uuid, UUID,
:f_uid_uuid, UUID
)
elsif !linux64?
layout(
Expand Down Expand Up @@ -199,17 +243,6 @@ def self.linux64?
end
end

# The Mnttab struct represents struct mnnttab from sys/mnttab.h on Solaris.
class Mnttab < FFI::Struct
layout(
:mnt_special, :string,
:mnt_mountp, :string,
:mnt_fstype, :string,
:mnt_mntopts, :string,
:mnt_time, :string
)
end

# The Mntent struct represents struct mntent from sys/mount.h on Unix.
class Mntent < FFI::Struct
layout(
Expand Down
1 change: 1 addition & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
config.include_context(Sys::Filesystem)
config.filter_run_excluding(:windows) unless Gem.win_platform?
config.filter_run_excluding(:unix) if Gem.win_platform?
config.filter_run_excluding(:dragonfly) unless RbConfig::CONFIG['host_os'] =~ /dragonfly/i
end
2 changes: 1 addition & 1 deletion spec/sys_filesystem_shared.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

RSpec.shared_examples Sys::Filesystem do
example 'version number is set to the expected value' do
expect(Sys::Filesystem::VERSION).to eq('1.4.5')
expect(Sys::Filesystem::VERSION).to eq('1.5.0')
expect(Sys::Filesystem::VERSION).to be_frozen
end

Expand Down
Loading

0 comments on commit f83af16

Please sign in to comment.