ほっしーの技術ネタ備忘録

技術ネタの備忘録です。基本的に私が忘れないためのものです。他の人の役にも立つといいなぁ。

ezjail 仮想マシンで実行する (2)

id:Hossy:20110627 これのバージョンアップ版です。


マシン名を . にするとホストマシンで実行します。(=sudo)

$ jsudo . hostname
host.example.net

マシン名を / にすると全仮想マシンで実行します。

$ jsudo / hostname
host.example.net
jm1.example.net
jm2.example.net

screen のキャプションを sleep@jm1 の形式で書き変えます。

$ jsudo jm1 sleep 10

カレントディレクトリが ezjail マシン内ならマシン名は省略します。

$ cd /usr/jails/jm1
$ jsudo jm1 hostname
jm1: command not found.
$ jsudo hostname
jm1.example.net

プログラムのパスが ezjail マシン内ならマシン名は省略可能です。

$ jsudo jm2 /usr/jails/jm2/etc/rc.d/cron status
cron is running as pid 1681.
$ jsudo /usr/jails/jm2/etc/rc.d/cron status
cron is running as pid 1681.


続きを読むを開くとソースコードが表示されます。

#!/bin/tcsh

# 設定
set ezjail_jailcfgs="/usr/local/etc/ezjail"

# ダブルクオーテーション内でのバックスラッシュを有効化する
set backslash_quote

# 引数なし実行は禁止
if ( $#argv < 1 ) then
	echo "ERROR: too few arguments"
	exit 1
endif

# -v オプション
if( $argv[1]:q == "-v" ) then
	if ( $#argv < 2 ) then
		echo "ERROR: too few arguments"
		exit 1
	endif
	shift argv

	set verb=1
else
	set verb=0
endif

# ホストマシンで実行する場合
if( $argv[1]:q == "." ) then
	if ( $#argv < 2 ) then
		echo "ERROR: too few arguments"
		exit 1
	endif
	shift argv

	# screen キャプションの設定
	printf "\033k`basename $argv[1]`@host\033\134"

	# 通常の sudo で実行する
	/usr/local/bin/sudo $argv:q

	exit 0
endif

# 全マシン(ホスト含む)で実行する場合
if( $argv[1]:q == "/" ) then
	if ( $#argv < 2 ) then
		echo "ERROR: too few arguments"
		exit 1
	endif
	shift argv

	# ホストで実行
	$0 . $argv:q

	# 各仮想マシンで実行
	foreach cf ( ${ezjail_jailcfgs}/* )
		$0 `basename ${cf}` $argv:q
	end

	exit 0
endif

# 各 ezjail 設定ファイルをスキャンする
foreach cf ( ${ezjail_jailcfgs}/* )
	# jail のルートディレクトリを取得 (末尾の / は取り除く)
	set cmd=". ${cf}; echo \${jail_`basename ${cf}`_rootdir}"
	set result=`sh -c ${cmd:q} | sed -e 's#/$##'`

	# カレントパスが jail 内の場合は jail 名を記憶
	pwd | grep -q "^$result\(/.*\)\?\$" && set jname_arg=`basename ${cf}`

	# 第一引数が jail 内のファイルを指す場合は jail 名を記憶
	echo $1 | grep -q "^$result\(/.*\)\?\$" && set jname_arg=`basename ${cf}`
end

if ( $?jname_pwd ) then
	# カレントパスが jail 内
	set ezjail_name=$jname_pwd
else if( $?jname_arg ) then
	# 第一引数が jail 内
	set ezjail_name=$jname_arg
else
	# それでもダメなら第一引数を jail 名として解釈する
	if ( $#argv < 2 ) then
		echo "ERROR: too few arguments"
		exit 1
	endif
	set ezjail_name=$1
	shift argv
endif

# 使用不可能な文字を取り除く
set ezjail_safename=`echo -n "${ezjail_name}" | tr -c '[:alnum:]' _`

# ezjail 設定ファイルの有無を確認
set ezjail_config="${ezjail_jailcfgs}/${ezjail_safename}"
if( ! -f ${ezjail_config} ) then
	echo "ERROR: there is no such a jail name."
	exit 1
endif

# jail のルートディレクトリを取得 (末尾の / は取り除く)
set cmd=". ${ezjail_config}; echo \${jail_${ezjail_safename}_rootdir}"
set ezjail_rootdir=`sh -c ${cmd:q} | sed -e 's#/$##'`

# カレントパスを jail 内の絶対パスに変換する
pwd | grep -q "^${ezjail_rootdir}\(/.*\)\?\$"
if( $? == 0 ) then
	set ezjail_pwd=`pwd | sed -e "s#^${ezjail_rootdir}##"`
else
	# jail の外にいる場合は /tmp にする
	set ezjail_pwd="/tmp"
endif

# 引数に含まれる絶対パスも jail 内のパスに変換する
foreach i ( `jot $#argv 1` )
	set tmp="$argv[$i]"
	set argv[$i]=`echo ${tmp:q} | sed -e "s#^${ezjail_rootdir}##"`
end

# jid の取得
if( -f "/var/run/jail_${ezjail_safename}.id" ) then
	set jid=`cat /var/run/jail_${ezjail_safename}.id`
	jls | grep -q -E "^ +${jid} " || unset jid
	if (! ${?jid} ) then
		echo "ERROR: there is no such a jail id."
		exit 1
	endif
else
	echo "ERROR: there is no such a jail name."
	exit 1
endif

# 設定値の表示
if( $verb == 1 ) then
	echo "jail_name: $ezjail_safename"
	echo "jail_root: $ezjail_rootdir"
	echo "jail_path: $ezjail_pwd"
	echo "jid: $jid"
	echo -n "command: "; printf "[%s]" $argv:q; echo
	echo ===
endif

# screen キャプションの設定
printf "\033k`basename $argv[1]`@$ezjail_safename\033\134"

# jail 内で実行するスクリプト
set verb_cmd="\
echo -n 'host: '; hostname;\
echo -n 'pwd: '; pwd;\
echo -n 'command: '; printf '[%s]' \$argv:q; echo;\
echo ===\
"
if( $verb == 1 ) then
	set cmd="cd $ezjail_pwd; $verb_cmd:q; \$argv:q;"
else
	set cmd="cd $ezjail_pwd; \$argv:q;"
endif

# jexec で tcsh を経由してスクリプトを実行する
/usr/local/bin/sudo /usr/sbin/jexec $jid /bin/tcsh -c $cmd:q $argv:q

# タイトルの削除
printf "\033]2;\007"

exit 0