Ruby: How to implement statfs syscall for Ruby 1.8 (pre Fiddle)
Here is statfs implementation for older Ruby releases that don’t have Fiddle:
#!/usr/bin/ruby
# gcc -x c -E <(echo "#include <sys/vfs.h>") | less
# struct statfs {
# long int f_type
# long int f_bsize
# unsigned long int f_blocks
# unsigned long int f_bfree
# unsigned long int f_bavail
# unsigned long int f_files
# unsigned long int f_ffree
# struct { int __val[2] } f_fsid
# long int f_namelen
# long int f_frsize
# long int f_flags
# long int f_spare[4]
# }
# extern int statfs (const char *__file, struct statfs *__buf)
require 'ostruct'
module Sys
# /usr/include/asm-x86_64/unistd.h
SYS_STATFS = 137
SENTINEL = 0x91d210f49de98115
FMT_STATFS = "Q16"
# Use SENTINEL to check that syscall doesn't overflow the buffer.
# BTW there is a bug in newer (post 1.8.6) ruby's syscall: you cannot
# provide buffer with NUL octets :( Luckily in this case you can fill
# the whole buffer with non-NUL octets because buffer is only used
# for returning data from the syscall
def self.statfs(filename)
buf = ([SENTINEL] * 16).pack FMT_STATFS
syscall SYS_STATFS, filename, buf
k = %w{type bsize blocks bfree bavail files ffree fsid namelen frsize
flags spare1 spare2 spare3 spare4}
v = buf.unpack FMT_STATFS
raise TypeError if v.pop != SENTINEL
OpenStruct.new k.zip(v)
end
end
st = Sys.statfs('/tmp')
puts st.inspect
Output:
<OpenStruct bavail=212090654, type=61267, flags=4128, files=60506112,
spare1=0, blocks=238218731, ffree=59367476, spare2=0, fsid=15391897869155704811,
spare3=0, bsize=4096, namelen=255, spare4=0, bfree=224191466, frsize=4096>