df コマンド
UNIX 系のシステムでの基本コマンド df の模造品です。
ファイルシステムの使用状態を示すコマンドです。
システムコールの statfs(2) を使用し、ファイルシステムの情報をとりだします。
ここで紹介しているスクリプトは、Linux 用です。
syscall で statfs(2) を呼びだすことで他の Unix 系システムでも応用ができると思います。
デフォルトで、ディスクの使用状態を示します。
オプション「-i」で i-node の使用状態(ファイルの数)を示します。
また、引数として「ファイル名」「ディレクトリ名」を渡すことで、そのファイルシステムの情報を表示します。
オプション 意味 -ii-node 情報の表示 -aサイズ 0 のファイルシステムも表示 -kブロックサイズを KB で表示 -m デフォルトブロックサイズを MB で表示
$ df Filesystem 1m-blocks Used Available Use% Mounted on /dev/hda2 2957 1955 851 69% / /dev/hda5 15488 11777 2924 80% /t $ df -k Filesystem 1k-blocks Used Available Use% Mounted on /dev/hda2 3028108 2002316 871972 69% / /dev/hda5 15860192 12059732 2994804 80% /t $ df -i Filesystem Inodes IUsed IFree %IUsed Mounted on /dev/hda2 384768 85229 299539 22% / /dev/hda5 2015232 166788 1848444 8% /t
Web ブラウザでの表示上は Ruby のスクリプトですが、HTML の特殊文字をエスケープしています。 テキストとしてセーブしてご利用ください。
Linux 用です。
#! /usr/local/bin/ruby
# /home/tetsu/src/ruby/linux/df.rb
# Created: May 12,1999 Wednesday 05:05:31
# Author: tetsu(WATANABE Tetsuya)
RCS_ID = '$Id: df.rb,v 1.16 2004/09/15 06:28:08 tetsu Exp $'
# usage:
class StatFS
def initialize(path)
@path = path
size = 64
unpack_fmt = 'iiiiiiiiiiiiiiii'
foo = ' ' * size
# asm/unistd.h __NR_statfs 99
syscall(99, @path, foo)
type, @bsize, @blocks, @bfree, @bavail, @files, @ffree, @namelen =
foo.unpack(unpack_fmt).values_at(0, 1, 2, 3, 4, 5, 6, 9)
@type =
case type
when 0xADFF then 'AFFS_SUPER_MAGIC'
when 0x137D then 'EXT_SUPER_MAGIC'
when 0xEF51 then 'EXT2_OLD_SUPER_MAGIC'
when 0xEF53 then 'EXT2_SUPER_MAGIC'
when 0xF995E849 then 'HPFS_SUPER_MAGIC'
when 0x9660 then 'ISOFS_SUPER_MAGIC'
when 0x137F then 'MINIX_SUPER_MAGIC'
when 0x138F then 'MINIX_SUPER_MAGIC2'
when 0x2468 then 'MINIX2_SUPER_MAGIC'
when 0x2478 then 'MINIX2_SUPER_MAGIC2'
when 0x4d44 then 'MSDOS_SUPER_MAGIC'
when 0x564c then 'NCP_SUPER_MAGIC'
when 0x6969 then 'NFS_SUPER_MAGIC'
when 0x9fa0 then 'PROC_SUPER_MAGIC'
when 0x517B then 'SMB_SUPER_MAGIC'
when 0x012FF7B4 then 'XENIX_SUPER_MAGIC'
when 0x012FF7B5 then 'SYSV4_SUPER_MAGIC'
when 0x012FF7B6 then 'SYSV2_SUPER_MAGIC'
when 0x012FF7B7 then 'COH_SUPER_MAGIC'
when 0x00011954 then 'UFS_MAGIC'
when 0x012FD16D then '_XIAFS_SUPER_MAGIC'
end
end
attr :path
attr :type
attr :bsize
attr :blocks
attr :bfree
attr :bavail
attr :files
attr :ffree
attr :namelen
end
def pr_i(dev, foo)
inodes_used = foo.files - foo.ffree
printf("%-20s %7d %7d %7d %3d%% %s\n",
dev,
foo.files,
inodes_used,
foo.ffree,
if foo.files == 0 then 0
else (inodes_used.to_f * 100.0 / foo.files.to_f).round end,
foo.path)
end
def pr_d(dev, foo, bs)
blocks_used = foo.blocks - foo.bfree
printf("%-20s %8d %8d %8d %3d%% %s\n",
dev,
foo.blocks * foo.bsize / bs,
blocks_used * foo.bsize / bs,
foo.bavail * foo.bsize / bs,
if blocks_used + foo.bavail == 0 then 0
else (blocks_used.to_f * 100.0 / (blocks_used.to_f + foo.bavail.to_f)).round end,
foo.path)
end
class Mtab
def initialize
@file = '/etc/mtab'
@info = []
f = File.open('/etc/mtab')
while f.gets
@info.push($_.split)
end
f.close
end
attr :file
attr :info
end
def usage
STDERR.print <<EOF
usage: #{$0} [-a] [-i] [file or dir]
-a: all
-i: i-node
-m: MB blocks (default)
-k: KB blocks
-v: version
#{RCS_ID}
EOF
exit 1
end
opt_i = false # inode
opt_a = false # all
opt_block_size = 1024 * 1024 # MB
while ARGV[0] =~ /^-/
$_ = ARGV.shift
if ~/i/ then opt_i = true end
if ~/a/ then opt_a = true end
if ~/k/ then opt_block_size = 1024 end
if ~/m/ then opt_block_size = 1024 * 1024 end
if ~/v/
puts RCS_ID
exit
end
usage if ~/[^\-aikmv]/
end
if opt_i
puts 'Filesystem Inodes IUsed IFree %IUsed Mounted on'
else
puts "Filesystem #{if opt_block_size == 1024 then '1k' else '1m' end}-blocks Used Available Use% Mounted on"
end
mt = Mtab.new
if ARGV.size == 0
mt.info.each do |arr|
dev, dir, type, opt = arr
next if (dev == 'none' or dev == 'usbdevfs') and opt_a == false
foo = StatFS.new(dir)
if opt_i then pr_i(dev, foo) else pr_d(dev, foo, opt_block_size) end
end
else
dev_arr = []
while path = ARGV.shift # stat ARGV
st = File.stat(path)
dev_arr.push(st.dev)
end
dev2mtab = {}
mt.info.each do |arr| # stat FS
dev, dir, type, opt = arr
st = File.stat(dir)
dev2mtab[st.dev] = arr
end
dev_arr.each do |id| # print
dev, dir, type, opt = dev2mtab[id]
foo = StatFS.new(dir)
if opt_i then pr_i(dev, foo) else pr_d(dev, foo, opt_block_size) end
end
end
syscall を使用し、statfs(2) システムコールを呼びだしています。
このとき、statfs(2) が要求する引数を渡すことになりますが、その「場所」「入れもの」を用意します。
ここには構造体と同じメモリイメージが入っていますので、unpack で値をとりだします。
必要な値をインスタンス変数に入れています。
あとは、この値を使用してディスクの使用量を表示します。
使用しているアルゴリズムは、GNU fileutils に含まれる df.c とほぼ同じです。
一度作成してから確認しました。
使用率を表示する部分は、整数演算で行っています。
このため、小数点が切り捨てになっていて、本来の df コマンドと違っています。
df コマンドは、四捨五入しています。
本物の df コマンドは、もっとたくさんのオプションを持っています。
必要なものがあれば、追加してみてはいかがでしょうか?
表示も、最近なら MB 単位がよかったかな?
クラスの中に、メッセージ出力も含めてしまった方がよかったかな。 でも、「ファイルシステム名」をどこから引っ張りだす?
小数点の扱いを変更。
小数点の扱いを変更。
Ruby 1.9 系対応。 Array#select から Array#values_at へ。
正規表現の書き直し
usbdevfs 対応。
いままで KB 単位のレポートでしたが、MB 単位をサポート。 最近のディスクは大きいので。
コメントの追加。 syscall の 99 番がどのファイルに定義されているか。