「一般ユーザー権限で chroot 環境下で外部コマンドを実行する」というコードを脳に優しく書けるようにするために、 ensure 節を使って後始末のことを心配しないメソッドをつくる。
run_with_chroot - chroot 環境下で外部コマンドを実行する
「一般ユーザー権限で chroot 環境下で外部コマンドを実行する」用。なお、 mount, umount, chroot は sudoers で使用を許可されているものとする。
def run_with_chroot(root, command)
dirs_for_chroot = %w[bin dev etc lib lib64 proc tmp usr var]
begin
Dir.mkdir(root) unless Dir.exists?(root)
dirs_for_chroot.each do |dir|
Dir.mkdir("#{root}/#{dir}") unless Dir.exists?("#{root}/#{dir}")
system("sudo mount -o bind #{dir} #{root}/#{dir}")
end
system("sudo chroot #{root} #{command}")
ensure
dirs_for_chroot.each do |dir|
system("sudo umount #{root}/#{dir}")
end
end
end
# chroot 環境下で /hoge というファイルを作成すると、
# chroot 環境外では /var/root/hoge というファイルができる
run_with_chroot('/var/root', 'touch /hoge')
chroot 環境をお膳立てするために、事前に mount しておいて事後に umount する必要があるが、これを毎回書くのはしんどいし、途中でプログラムが例外を投げて umount しないまま落ちたりすると面倒なことになる。そこで umount するコードを ensure 節に置くことで、後始末用のコードが確実に実行されるようにする。
プログラムを root 権限で動かせるなら system("chroot /path/to/root command") の代わりに Dir.chroot を使うとなお良い。そうすれば with_chroot というブロック付きメソッドを定義して、より読みやすいコードが書けるだろう。