ノリブログ?

mysqlクエリとCPU状況をシェルスクリプトで監視

カテゴリー:Linux

使用してるサーバに負荷がかかっていてmysqlが原因として疑われたのでCPUの状況とMysqlの実行中クエリを表示するシェルスクリプトを組んでみました。
まず、mysqlの実行中クエリを取得する方法について調べてみると以下のSQLで得られることがわかりました。

 show full processlist;

次にこのSQLをmysqlにログインせずにコマンドとして送って結果の出力を得られないか調べてみました。
以下のようなコマンドで、結果を得られるようです。-pの後に、スペースをはさまずにパスワードを入れてるところがポイント。

  mysql -uuser -ppassword -e 'show full processlist'

ということで、これをつかって以下のようなシェルスクリプトを書いてみました。

if test -f $1;
then
num=0
else
num=`expr $1 + 1`
fi

while [ $count -ne $num ];
do
date
echo ' '
top -c -b -n 1 | head
echo ' '
mysql -uuser -ppassword -e 'show full processlist'
count=`expr $count + 1`
echo ' '
echo '********************************************************************'
echo ' '
sleep 3
done

使い方は、上のコードをfilename.shという名前で保存後、"filename.sh 実行回数"と実行すると指定した回数だけ3秒間隔でtopコマンドでとってきたCPUの状態とmysqlで実行中のクエリが表示されます。
ちなみに、回数の指定がないときはCtrl+Cが入力されるまで実行される。
↓実行例

 filename.sh 3

FirefoxでPHPが二重実行

カテゴリー:Linux

ブラウザ上に出力するテキストが大量にあるPHPを実行していると、想定していたよりかなり時間が、かかるという問題を調べていた。
なお調べている途中で、PHPファイル内部に以下のような記述をしてPHPファイルが実行されたときの時間をログに出力するようにしていた。
<?php exec("echo 'date:".date("H:i:s")."'  >>  log"); ?>
そこでブラウザからファイルに1度アクセスしてログを確認してみると、実行ログが2回分はいっていた。
つまり、1度のアクセスにつきPHPが2回実行されているようだ。
この問題について調べてみた。

環境

  • クライアント
    • Firefox/2.0.0.11
    • Windows Vista
  • サーバ
    • PHP Version 4.3.9

ここで、他のブラウザ、環境で試すと再現しないことから、クライアント側のhtmlファイルの解釈によって問題がおきるかどうかが変わっていることがわかった。
そこでサーバ側のPHPファイルを見直してみるとデバッグ用の出力をhtml開始タグの記述前の箇所で行っていたためデバッグ用の出力をhtmlのbody内部に出力するようにさせたところ二重実行はされなくなった。

Webアプリケーションからシェルスクリプトを動作させるときのサニタイズ

カテゴリー:Linux

作成しているWebアプリケーションに、GETパラメータから値を受け取ってその値を元にシェルスクリプトを動作させるという処理がありました。

このような処理があるときは値を受け取ったときに適切にサニタイズしなければサーバに致命的な脆弱性を生みます。

では、どのよう値が危険なのかを説明していきたいと思います。

今回、以下のようなシェルスクリプトを実行するとします。$1はWebアプリから受け取った値です。

cp $1

セミコロン

ここでもし$1の中身が「;rm -rf *」であればシェルスクリプトが実行する内容は

cp;rm -rf *

ディレクトリ内のファイルが全て削除されてしまいます。
これを防ぐため「;」はバックスラッシュでエスケープしておくべきです。

スラッシュ

次に$1の中身が「../../../../etc/filename」のようにシステムにかかわるパスであれば、システムファイルが書き換えられてしまう危険性があります。
そこで上の階層のディレクトリをディレクトリを書き換えられないようにするため「/」もエスケープする文字列に指定しておくべきでしょう。

 

 

 

perlで刺身の上にたんぽぽを載せるスクリプトを書く

カテゴリー:perl

経緯

南部製作所でアルバイトしている坂本です。

今週アルバイトの時間がとれなさそうで、それを南部製作所代表の河野さんに報告すると
「じゃあアルバイトに変わりに何かバイトで使う技術を勉強してきたら、アルバイト代支給します。」
とのこと。

テーマは何にしようかなと考えて正規表現、perl、シェルスクリプトぐらいが候補にあがりました。
今、Webアプリケーションの開発はPHPで行っており、perlはほとんど触れたことがありません、、。

perlを使えるようになっておけばテストスクリプトやターミナルから実行する簡単なスクリプトを作るときに、手早くできるようになりそうなのでperlの勉強をすることにしました。

話し合った結果、勉強時間が数時間ぐらいしかとれないので達成目標はとりあえず。。。
「刺身にたんぽぽをのせるレベル」になること。

そして一週間後

「はじめてのperl」を9章ぐらいまで読みました。
簡単なファイル操作スクリプトなどは書けるようになったと思います。

で、ちゃんと勉強できたかどうか試すために与えられた課題は

  1. ディレクトリの中に、たんぽぽの画像ファイル(tanpopo.gif)と複数の刺身の画像ファイルがある
  2. 刺身ファイルはjpgファイルでありファイル名中に「sashimi」がはいっている
  3. 刺身画像とたんぽぽ画像を合成して「刺身の上にたんぽぽを載せる」スクリプトを書け

という課題。。。たしかに達成目標そのままでした。
ということで以下のようなスクリプトを書きました。

実行方法:

# ls | perl filename.pl

正規表現でファイルをチェックをするところがサブルーチン化せずにコピペでつかってたり、use strictやってなかったりと、なかなか目にあまるところがありますが、時間不足と練習不足です。。。
これからperlを使いながら慣れて行きたいと思います。
注:下のスクリプトでは実行前にtanpopo.gifのマスクファイル,mask.pbmを作成しておく必要があります。

 

#/usr/bin/perl
chomp ( @files = <>);

$t_image = "tanpopo.gif";

print "grep sashimi file....\n";
foreach $_ (@files){
if ($_ =~ /sashimi|sasimi/i){
print " [OK]:".$_;
print "\n";
push(@sashimi,$_);
}else{
print " [NG]:".$_;
print "\n";
}
}
print "\n";


print "sashimi list:
";
foreach $_ (@sashimi){
print " ".$_;
print "\n";
}
print "\n";


print "grep jpg file....\n";
foreach $_ (@sashimi){
if ($_ =~ /jpg|jpeg/i){
print " [OK]:".$_;
print "\n";
push(@s_images,$_);
}else{
print " [NG]:".$_;
print "\n";
}
}
print "\n";

print "sashimi jpg file list:
";
foreach $_ (@s_images){
print " ".$_;
print "\n";
}
print "\n";
print "genereting file.....\n";
$image_num = 0;
foreach $_ (@s_images){
system("jpegtopnm $_ | pnmscale -xsize=200 > s_tmp");
system("giftopnm $t_image | pnmscale -xsize=100 > t_tmp");
system("pnmcomp -alpha mask.pbm t_tmp s_tmp | pnmtojpeg > generetedimg$image_num.jpg");
$image_num++;
}

ユーザー領域にインストールしたcpanをシェル以外から実行したときの問題点

カテゴリー:Linux

ユーザー領域にインストールしたcpanをシェル以外から実行したときの問題点

cpanのインストールディレクトリをユーザ領域に設定することで ルート権限を持たないユーザでもcpanライブラリを利用することができる。
参考URL:

注意しなければいけないのはライブラリの保存場所の環境変数を設定しておく必要があること。

例えばbashであれば、インストールしたディレクトリが/home/user/perllibだとすると

export PERL5LIB=/home/user/perllib

としてライブラリを指定する必要がある。
(いちいち打ち込まなくても.bashrcを設定しておけば大丈夫)

しかし、この方法でCrypt::CBCをインストールした後、perlプログラムをbash以外から実行しようとした時、環境変数の設定が上の方法だと通らないことに気づいた。
(今回はメールの自動応答プログラム作成のため.forwardから実行するようにしていた、詳細はこの記事を参考に)

プログラム中に以下のようなことを試してみたがダメだった。

exec("export PERL5LIB=/home/user/perllib");
$ENV{"PERL5LIB"} = "/home/start/perllib";

そこで環境変数を通さずにローカルにインストールしたライブラリを読み込む方法を調べてみた。

環境変数を通さずにローカルにインストールしたライブラリを読み込む方法

プログラムを実行するときのカレントディレクトリにperlのライブラリディレクトリ(perllib)がインストールされている場合は

use perllib::Crypt::CBC

とすれば実行することができる。

ただし今回は.forwardが実行するのでカレントディレクトリがインストールディレクトリと一致しなく、ディレクトリの移動もできなかったため、上の方法では動作しなかった。

最終的にperlの-Iオプションでライブラリのパスが指定できることがわかり

これで対応した。 .forwardで実行する部分を以下のように書き換えた。

/usr/bin/perl -I /home/user/perllib ~/filename.pl

<< Before