Samba共有ファイルを使用中のマシンがわかるスクリプト
私の顧客の1人は、Visual Basic 6およびAccessベースの数多くの小型アプリケーションを直接Linux上で稼働させて、Sambaによるネットワーク共有を介して各Windows XPクライアントから利用できるようにしている。だが、そうしたアプリケーションやデータベースのアップデートが必要になるたびに、彼は新しいバイナリやAccessファイルをサーバにアップロードできるようにそのアプリケーションからのログオフをユーザに依頼することになる。しかし、彼の管理する中規模ネットワークにはそうしたアプリケーションを使用しているクライアントが100台ほど存在するため、たとえログオンしているのが1人だけでも、そのアプリケーションを使用中のユーザが見つかるまで延々と電話をかけ続け、見つかったユーザにログオフを依頼して、アップロードを実行しなければならない。
今回、この問題をlsof
、netstat
、gawk
、grep
、uniq
をはじめとするユーティリティの組み合わせによって解決するスクリプトを作成した。アプリケーションのバイナリはすべて、/usr/appsの下にある、payroll、accounting、sales、invoiceといったサブフォルダに格納されている。たとえば、先ほどの顧客が給与台帳(payroll)システムを使用中のすべてのユーザを知る必要があるなら、以下に示すように、開かれている全ファイルを表示してくれるlsof
ユーティリティが利用できる。
lsof | grep /usr/apps/payroll smbd 16258 systems cwd DIR 8,5 4096 2191586 /usr/apps/payroll smbd 16258 systems 27rR REG 8,5 2449408 2191760 /usr/apps/payroll/payroll.exe smbd 16258 systems 28u REG 8,5 37883904 1684790 /usr/apps/payroll/dbpayroll.mdb smbd 16258 systems 29uw REG 8,5 256 1684290 /usr/apps/payroll/dbpayroll.ldb smbd 19237 systems cwd DIR 8,5 4096 2191586 /usr/apps/payroll smbd 19237 systems 25rR REG 8,5 2449408 2191760 /usr/apps/payroll/payroll.exe smbd 19237 systems 27u REG 8,5 37883904 1684790 /usr/apps/payroll/dbpayroll.mdb smbd 19237 systems 28uw REG 8,5 256 1684290 /usr/apps/payroll/dbpayroll.ldb smbd 19237 systems 29rW REG 8,5 45056 1684863 /usr/apps/payroll/report1.rpt
この出力のプロセスID(PID)が16528から19237までの部分は、smbd(Samba)によって複数のファイルが開かれていることを示している。たとえば、2人のユーザがpayroll.exeアプリケーションを使用中であることがわかる。また、最後の行は、report1.rptファイルが使用中であることを示している。これは標準的なCrystal Reportの拡張子であり、このアプリケーションもビジー状態であることがわかる。しかし、こちらはユーザ名がわからないので、以下のようにして先ほどの出力結果から必須の情報(PID番号)だけを抽出する必要がある。
lsof | grep /usr/apps/payroll | gawk '{ print $2 }' 16258 16258 16258 16258 19237 19237 19237 19237 19237
このようにgawk
を使えば2番目のフィールドだけを抜き出せるが、重複するものは必要ない。そういうときは、ソートされた一覧から重複する行を削除してくれるuniq
を使えばよい。
lsof | grep /usr/apps/payroll | gawk '{ print $2 }' | uniq 16258 19237
この結果をテンポラリ(tmp)ファイルに残すには、次のようにする。
lsof | grep /usr/apps/payroll | gawk '{ print $2 }' | uniq > tmp
続いて、netstat
コマンドを使ってこれらのPID番号をネットワークソケットに関連付ける。次のようにnetstat
に-p
オプションを指定すると、各ソケットが属するプログラムのPIDと名前が表示される。
netstat -p | grep 16258 tcp 0 0 192.168.100.250:netbios-ssn 192.168.100.32:1028 ESTABLISHED 16258/smbd
4番目のカラム(192.168.100.250:netbios-ssn
)はサーバマシンを、5番目のカラム(168.100.32:1028
)はクライアントマシンのIPアドレスおよびポート番号を示している。ここで必要なのは5番目のカラムのほうである。
今度は、PIDをtmpファイルに記録する処理をすべて1つのスクリプトにまとめてみよう。
lsof | grep /usr/apps/payroll | gawk '{ print $2 }' | uniq > tmp echo "PCs USING THE APPLICATION:" while read row ; do netstat -p | grep $row | gawk '{ print $5 }' | cut -d":" -f1 done < tmp
netstat -p | grep $row | gawk '{ print $5 }' | cut -d":" -f1
という行は、まずnetstat
を実行してから$rowに対するgrep
を呼び出す。この変数$rowには、tmpファイルのそれぞれの行が順に入る。続いてgawk
で5番目のカラムを抜き出したあと、cut
でデリミタ”:”を除いたうえでIPアドレスにあたる最初のフィールドを取り出す。
このスクリプトに名前を付けたら、chmod 700 script.sh
によって実行ファイルにする。スクリプトの実行結果は、次のようになるはずだ。
./script.sh PCs USING THE APPLICATION 192.168.100.32 192.168.100.78
あとはIPアドレスとユーザ名の関連付けを行うだけでよい。そのために、以下のような行を/etc/hostsに追記する。
192.168.100.32 Lindsay_Hayek 192.168.100.78 Salma_Lohan 192.168.100.145 Tom_Norton 192.168.100.193 Edward_Cruise
また、この/etc/hostsを参照するためのgrep
を、先ほどのスクリプトのnetstatの行に加えて次のようにする
grep `netstat -p | grep $row | gawk '{ print $5 }' | cut -d":" -f1` /etc/hosts
しかしこのままでは、/etc/hostsに記されていないIPアドレスが見つかった場合、このスクリプトはエラーを返し、単純にそのIPアドレスを表示してはくれない。この問題はif文を使えば解決できる。上記の命令が正しいものであれば(変数$?に0が返される)、スクリプトはtmpファイルの次の行に進む。しかし、0以外の値が返された場合は該当するIPアドレスが/etc/hostsに見つからなかったということなので、単純にそのIPアドレスを表示するようになっている。あとでネットワーク管理者に訊けば、そのIPアドレスが誰のものかわかるかもしれない。ここで、最終的なスクリプトを以下に示す。
lsof | grep /usr/apps/payroll | gawk '{ print $2 }' | uniq > tmp echo "PCs USING THE APPLICATION:" while read row ; do grep `netstat -p | grep $row | gawk '{ print $5 }' | cut -d":" -f1` /etc/hosts if [ $? -ne 0 ]; then netstat -p | grep $row | gawk '{ print $5 }' | cut -d":" -f1 end if done < tmp
実行すると、次のような結果が得られる。
./script.sh PCs USING THE APPLICATION 192.168.100.32 Lindsay_Hayek 192.168.100.78 Salma_Lohan 192.168.100.90
このスクリプトはさらに拡張することもできる。たとえば、lsof | grep /usr/apps/payroll | gawk '{ print $2 }' | uniq > tmp
の行でpayrollと指定してしまうと対象とするアプリケーションが変わるたびにその部分を編集しなければならなくなるので、次のようにするとよい。
lsof | grep /usr/apps/$1 | gawk '{ print $2 }' | uniq > tmp echo "PCs USING THE APPLICATION: $1"
ここで$1はコマンドラインから渡す引数であり、次のようにして指定する。
./script.sh accounting PCs USING THE APPLICATION accounting 192.168.100.145 Tom_Norton 192.168.100.178 192.168.100.193 Edward_Cruise
また、アプリケーションのメニューを作成したり、Zenityを使ってXウィンドウ環境での対話型スクリプトにしたりすることも可能だろう。
Sergio Gonzalez DuranはLinux管理者やシステム開発者、またネットワークセキュリティのカウンセラーとして活動しながら、各種Linux講座での指導や、Linuxおよびオープンハウス関連のスペイン語WebサイトLinuxtotal.com.mxの公開も手がけている。
linux.com 原文