久々にメールアドレスでも新しく作ろうと思って、nologinで新規ユーザ作成してみた。

thunderbirdでちゃちゃちゃとアカウント設定して、いざ受信って思ったら、
「接続:ホストにログイン情報を送信しています・・・」
のまま音沙汰なし。

パスワードとかいろいろ確認しても特におかしくないので、とりあえずmaillogを確認したら、こんなメッセージが。

-----------------------------------------------------------------------------------------
dovecot.... mail_location not set and autodetection failed: Mail storage autodetection failed with home=......
-----------------------------------------------------------------------------------------

うーん、これはなんだろう。

なんか雰囲気的に、メールボックスの場所が指定されてないから、メールを取りにいけません的な感じだろうか・・・

おかしいなあ、前までは普通にユーザ作成してメーラーの設定するだけですぐにいけたんだけどなあ・・・
と思いつつ、とりあえず問題ありそうな「/etc/dovecot.conf」を確認。

ってゆうか、このファイル一回も中身見たことないし〜。

メールサーバ入れたときもdovecotの設定なんか一回もやんなかったのに・・・
デフォルトでいままでいけてたんですけどね。


でもなんかこの辺が臭かったので、

-------------------------------------------------------------------------------------------
# Location for users' mailboxes. This is the same as the old default_mail_env
# setting. The default is empty, which means that Dovecot tries to find the
# mailboxes automatically. This won't work if the user doesn't have any mail
# yet, so you should explicitly tell Dovecot the full location.
#
# If you're using mbox, giving a path to the INBOX file (eg. /var/mail/%u)
# isn't enough. You'll also need to tell Dovecot where the other mailboxes are
# kept. This is called the "root mail directory", and it must be the first
# path given in the mail_location setting.
#
# There are a few special variables you can use, eg.:
#
# %u - username
# %n - user part in user@domain, same as %u if there's no domain
# %d - domain part in user@domain, empty if there's no domain
# %h - home directory
#
# See for full list. Some examples:
#
# mail_location = maildir:~/Maildir
# mail_location = mbox:~/mail:INBOX=/var/mail/%u
# mail_location = mbox:/var/mail/%d/%1n/%n:INDEX=/var/indexes/%d/%1n/%n
#
#
#
#mail_location =
-------------------------------------------------------------------------------------------

google様で直訳してみると、locationの設定は必須ですよ〜みたいな感じなのかな?

とりあえず例のまんま設定してみる。

-------------------------------------------------------------------------------------------
mail_location = mbox:~/mail:INBOX=/var/mail/%u
-------------------------------------------------------------------------------------------

てなかんじ。

すると・・・おお!メーラーがちゃんとメールを読みに行った!

なんじゃそりゃ。


ユーザディレクトリにも「mail」ディレクトリが作成されてる。
さっきまで無かったのに・・・
この「mail」ディレクトリって何なのかわかんなかったけど、dovecotが勝手に作ってるんですね・・・


とりあえずpopはOKそうなので、ついでにSMTP(postfix)の方も確認。
/etc/postfix/main.cfを開いて、それっぽい部分を見てみると、

-------------------------------------------------------------------------------------------
# DELIVERY TO MAILBOX
#
# The home_mailbox parameter specifies the optional pathname of a
# mailbox file relative to a user's home directory. The default
# mailbox file is /var/spool/mail/user or /var/mail/user. Specify
# "Maildir/" for qmail-style delivery (the / is required).
#
#home_mailbox = Mailbox
#home_mailbox = Maildir/
-------------------------------------------------------------------------------------------

どうやら、デフォルトのメールボックスは/var/spool/mail/userか、 /var/mail/userで、何もいじらないとここにメールを届けに行くらしい。
というわけで、さっきのdovecotの設定とつじつまがあってるのでOK。

まあ、ちゃんとした人たちはMaildir形式にちゃんと設定してるんだろうけど、横着な私はこれで問題無し。


一応確認のためにpostfixから送信して、dovecotで取りに行ってちゃんと読めたのでめでたし。

しかし軽く7時間かかったのは痛かった。


サーバ立ち上げた時から今まで問題なかったのに、いつからdovecotのデフォルト設定変わったの?って感じ。

アップデートなんてまったくやってないのに。

・・・よくわからないなー
前記事(http://www.igreks.jp/dev/2010/01/mysql.html)のようにALTER TABLEを使って更新するのもいいのだが、できれば構造のテンプレートに合わせて一発でコピーしたい。

ただ単にテーブルの構造とデータをコピーする場合、普通は、

---------------------------------------------------------------------------------------
CREATE TABLE sample_new LIKE sample_original
INSERT INTO sample_new SELECT * FROM sample_original
---------------------------------------------------------------------------------------


しかし、新しい構造のテーブルにあわせて、構造を変更しながらデータをコピーするといった方法が見つからないため、スクリプトの処理を合わせて実現してみる。
あんまりスマートじゃないけど・・・

まず、最新の構造のテンプレートを作っておく。


■最新のテーブル構造のテンプレート(tbl.pl)
---------------------------------------------------------------------------------------

package tbl;

sub conf{
my %tbl = (

'table_a' => {
'column' => '
id INT AUTO_INCREMENT PRIMARY KEY,
column_1 VARCHAR(36),
column_2 VARCHAR(255),
column_3 VARCHAR(255)
',
'option' => '
ENGINE = MyISAM DEFAULT CHARSET = utf8
'
},

'table_b' => {
'column' => '
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
column_1 INT,
column_2 VARCHAR(255),
column_3 VARCHAR(255)
',
'option' => '
ENGINE = MyISAM DEFAULT CHARSET = utf8
'
},



);
return \%tbl;
}
1;

---------------------------------------------------------------------------------------


テンプレートを読み込んで新しいテーブルを一時作成し、
そのテーブルに既存のテーブルのデータをインポートする。

■更新処理(tbl_update.pl)
---------------------------------------------------------------------------------------
#!/usr/bin/perl

package::main;

my $dbh;



# この辺でデータベースへの接続処理(詳細割愛)

print "Content-type: text/html\n\n";

print "<p>データベースの再構築を開始します</p>\n";

# 既存のテーブル名をリストで取得
my $sth = $dbh->prepare("SHOW TABLES LIKE 'hoge_%'") || die $dbh->errstr();
$sth->execute();
my @hoge_tbl = ();
while(my @tbl = $sth->fetchrow_array()){
push(@hoge_tbl,$tbl[0]);
}

# テンプレート読み込み
require "./tbl.pl";
my $tbl = &tbl::conf(); # ※リファレンスで受け取り

foreach(@hoge_tbl){

# 既存テーブルのカラム名をリストで取得
my @cols = ();
my $sth = $dbh->prepare("DESCRIBE $_") || die $dbh->errstr();
$sth->execute();
while(my $href = $sth->fetchrow_hashref()){
push(@cols,$href->{'Field'});  # unshiftしちゃだめよ
}
my $cols = join(',',@cols);

#####################################
# テーブル名の末尾に個別にIDとかが付いてなければこの処理はいらない
$_ =~ /hoge_(.+?)(_.+?)?$/;
my $name = $1;
######################################

# 新しい構造の空テーブルを「pre_***」という名前で一旦作成
my $sth = $dbh->prepare("
CREATE TABLE IF NOT EXISTS pre_$_ (
$$tbl{$name}{'column'}
) $$tbl{$name}{'option'}
") || die $dbh->errstr();
$sth->execute();

# 既存のテーブルのデータを、カラム名を明示的に指定して挿入
# これをしないとカラムの数が合いませんよ!と怒られる
my $sth = $dbh->prepare("INSERT INTO pre_$_ ($cols) SELECT * FROM $_"); # ※1
$sth->execute();

# 既存のテーブル削除
my $sth = $dbh->prepare("DROP TABLE IF EXISTS $_");
$sth->execute();

# 新しいテーブルのリネーム("pre_"をとる)
my $sth = $dbh->prepare("ALTER TABLE pre_$_ RENAME $_");
$sth->execute();

}

print "<p>データベースの再構築が完了しました。</p>\n";

exit;
---------------------------------------------------------------------------------------


以上。

新しいテーブルにカラムが追加されてる場合は問題ないが、カラムが削除された場合は、多分※1のところでエラーになる・・・

こういうの一発でできるSQLないのかなぁ。

配列関係の重複チェックは一度ハッシュ(%check)に入れると簡単


-----------------------------------------------------------------------------------------

my %hash = (
a => 'あああ',
b => 'いいい',
c => 'ううう',
d => 'あああ',
e => 'おおお',
f => 'あああ'
);

my %check = ();

for(values %hash){
die "$_ が重複してるよ!" if $check{$_};
$check{$_} = 1; #### 1とかaとか好きなの入れる
}

-----------------------------------------------------------------------------------------
LWPを使ったhttpレスポンスの取得には、HTTP::Request(::Common)モジュールを使ってリクエストのオブジェクトを作っておくと、レスポンス情報を確認するさまざまなメソッドを使用することができる。

HTTPモジュール群にはまず「HTTP::Message」があり、このオブジェクトには幾つかのヘッダとコンテント(ボディ)取得用のクラスが入ってるが、このクラスは抽象クラスである。
つまりHTTP::RequestとHTTP::Responseのための基本クラスとしてだけ使われ、それ自身のインスタンスは生成されることはない。

「HTTP::Response」はHTTP形式のレスポンスをカプセル化するクラスである。
このクラスのインスタンスは通常、LWP::UserAgentオブジェクトのrequestメソッドによって作成され返される。

また、「HTTP::Headers」は同様にHTTP形式のメッセージヘッダをカプセル化するクラスである。
このクラスのインスタンスは通常、HTTP::RequestやHTTP::Responseクラスのメンバー変数として、ライブラリ内部用に作成される。

つまり、

my $url = 'http://yahoo.co.jp';
my $ua = LWP::UserAgent->new();
my $req = &HTTP::Request::Common::GET($url);
my $res = $ua->request($req);

のように、レスポンス用オブジェクト($res)生成しておけば、上の3つのモジュールで定義されているメソッドは全てこのオブジェクト($res)から以下のように参照することができる。

---------------------------------------------------------------------------------------------------

(HTTP::Message)

■$res->protocol([$proto])
・・・そのメッセージに使われるHTTPプロトコルを設定する。protocol()は"HTTP/1.0"または"HTTP/1.1"のような文字列が返る。

■$res->content([$content])
・・・引数が与えられていれば、コンテントを設定する。引数が無ければ、コンテントは触れられずに返される。

■$res->add_content($data)
・・・前のコンテントの末尾にさらにデータを追加する。

■$res->content_ref
・・・コンテント文字列へのリファレンスを返す。
コンテントが巨大であれば、この方法が効率的。また、直接操作が出来る。
例:${$res->content_ref} =~ s/\bfoo\b/bar/g;

■$res->headers;
・・・HTTP::Headersオブジェクトを返す。

■$res->headers_as_string([$endl])
・・・HTTP::Headers->as_stringを呼び出す。

(HTTP::Headers)

■$res->header($field [=> $value],...)
・・・ヘッダの値を取得または設定する。
ヘッダ・フィールド名は大文字/小文字を区別しない。
引数が無い場合は複数の($field => $values)の組を受け取る。
$valueを複数設定することにより1回の呼び出しでたくさんのフィールドを更新することも可能。$valuesにはスカラまたはスカラのリストへのリファレンスを指定することができる。
$valueが未定義だったり指定されていなければヘッダは変更されない。

複数の値を持つフィールドは、スカラ・コンテキストでは","を区切り文字としてつなげられ返される。

(例)
 $header->header(MIME_Version => '1.0',
      User_Agent => 'My-Web-Client/0.01');
 $header->header(Accept => "text/html, text/plain, image/*");
 $header->header(Accept => [qw(text/html text/plain image/*)]);
 @accepts = $header->header('Accept');

■$res->scan(\&doit)
・・・ヘッダそれぞれにサブルーチンを適用する。コールバック・ルーチンは2つのパラメータ(フィールド名と1つの値)で呼び出される。
ヘッダが1つ以上の値を持っていれば、ルーチンはそれぞれの値につき1回呼ばれる。コールバック・ルーチンに渡されるフィールド名はHTTP仕様で提案されている大文字/小文字をもち、推奨されている"Good Practice"の順でやってくる。

■$res->as_string([$endl])
・・・フォーマットされたMIMEヘッダとしてヘッダ・フィールドを返す。
文字列を組み立てるために内部でscan()メソッドを使っているので、結果はHTTP仕様で提案されている大文字小文字で、ヘッダ・フィールドの順序の推奨されている"Good Practice"に従う。
長いヘッダの値はたたまれない。

オプションのパラメータには使用する行末シーケンスを指定できる。デフォルトは"\n"。
この場合、ヘッダに埋め込まれた"\n"文字は、この行末シーケンスで置きかえられる。

■$res->push_header($field, $val)
・・・指定されたヘッダに新しいフィールドの値を追加する。
ヘッダ・フィールド名は大文字小文字を区別しない。
同じフィールド名で、値を持たずに指定した場合、前の値が残る。
引数にはスカラやスカラのリストへのリファレンスを指定することが出来る。

(例)$header->push_header(Accept => 'image/jpeg');

■$res->remove_header($field,...)
・・・指定された名前を持つヘッダを削除する

(HTTP::Response)

■$res->code([$code])
・・・レスポンスコード(301など)を返す。

■$res->message([$message])
・・・レスポンスメッセージを返す。

■$res->request([$request])
・・・このレスポンスを発生したリクエストのリファレンスを返す。
ここまでの間に、リダイレクトや認証のリトライがある場合もあるので、$ua->request()メソッドに渡されたものと同じリクエストである必要はない。

■$res->previous([$previousResponse])
・・・最初のレスポンスがリダイレトクまたは認証されていなければ、レスポンスのチェーンを返す。

■$res->status_line
・・・文字列"$res->code + $res->message"を返す。
もしmessage属性が設定されていなければ、code(HTTP::Statusを参照にした)の公的な名前に置き換えられる。

■$res->base
・・・レスポンスのベースURLを返す。
戻り値はURIオブジェクトへのリファレンス。

ベースURLは以下のいずれかの情報源から1〜3の優先順で取得される。

 1. ドキュメント内容に埋め込まれたもの:例えばHTMLドキュメント内での
 2. レスポンスでの"Content-Base:"または"Content-Locatin:"ヘッダ
  古いHTTP実装との互換性のため、"Base:"ヘッダも探す。
 3. このレスポンスを要求したURL。
  これはレスポンスの前に、いくつかのリダイレクトを受信しているかもしれないため、$ua->request()メソッドに渡された元のURLでない場合もある。

■$res->as_string
・・・コンテントのプレーンテキストを返す。
主にデバッグのために使われる。引数は指定できない。

■$res->is_info
■$res->is_success
■$res->is_redirect
■$res->is_error
・・・レスポンスが情報的(informational)であるか、成功したか、リダイレクトであるか、エラーであるかを返す。
(偽ならおそらくundefか0を返す)

■$res->error_as_HTML()
・・・何のエラーが発生したかを示す完全なHTMLドキュメントが入っている文字列を返す。
このメソッドは$res->is_errorがTRUEのときだけ呼ぶべき。

■$res->current_age
・・・ section 13.2.3.によって指定されたレスポンスの"現在の年齢"("current age")を計算する。
レスポンスの年齢は元のサーバサーバーによって送信されてからの時間。
返される値は累計秒。

■$res->freshness_lifetime
・・・ section 13.2.4.で指定されたそのレスポンスの"新鮮期間"("freshness lifetime")を計算する。
"新鮮期間"はレスポンスが生成されてから終了するまでの時間の長さ。
返される値は累計秒。

■$res->is_fresh
・・・freshness_lifetime()とcurrent_age()の値をベースに、レスポンスが新鮮であればTRUEを返す。
レスポンスがもはや新鮮でなければ、もう一度取り出されるか、元のサーバによって再評価されるべきである。

■$res->fresh_until
・・・このエンティティがもはや新鮮ではない時刻を返す。


------------------------------------------------------------------------------------------------------

参考URL:
http://homepage3.nifty.com/hippo2000/perltips/HTTP/Headers.html
http://homepage3.nifty.com/hippo2000/perltips/HTTP/Message.html
http://homepage3.nifty.com/hippo2000/perltips/HTTP/Response.html
----------------------------------------------------------------------------------------------

#!/usr/bin/perl -w

use strict;
use LWP::UserAgent;
use HTTP::Request::Common;

# オブジェクト作成
my $ua = LWP::UserAgent->new();
my $url = 'http://yahoo.co.jp';
my $req = &HTTP::Request::Common::GET($url);

# レスポンスを得る
my $res = $ua->request($req);

# フィールド名を指定してヘッダを取得
my $con_type = $res->header('Content-Type');

#処理
if($con_type =~ /shift_jis/i){
  # (sjis用エンコーディング処理)
}
elsif($con_type =~ /euc-jp/i){
  # (ujis用エンコーディング処理)
}
elsif($con_type =~ /utf-8/i){
  # (utf8用エンコーディング処理)
}
  ・
  ・
  ・

----------------------------------------------------------------------------------------------


※charsetをダイレクトに返してくれるメソッドはどうやら無いらしい・・・
あったら教えてください。
多くの参考サイトや本では、LWPモジュール群を利用してのSSLアクセスには「Crypt::SSLeay」モジュールが必要と説明されているが、どうやら「Net::SSLaey」モジュールがあれば可能なようだ。

もちろんサーバにSSL環境(OpenSSLとかmodSSLとか)があるっていうのが前提ではあるが。

OpenSSLとLWPのつなぎ役をしてくれるのがCrypt::SSLeayだが、もともと、OpenSSLとSSLeayとの高度な機能インタフェースを提供するモジュールが「Net::SSLaey」モジュールである。


以下確認作業

■まず適当なスクリプトでPerlの@INCの中身を確認----------------------------------------------------------------------------------------------
#!/usr/bin/perl

print "Content-type: text/plain\n\n";

foreach(@INC){
print $_.'\n';
}

exit;
----------------------------------------------------------------------------------------------

■結果↓

----------------------------------------------------------------------------------------------
/usr/local/lib/perl5/site_perl/5.10.0/i386-linux-thread-multi
/usr/local/lib/perl5/site_perl/5.10.0
/usr/lib/perl5/vendor_perl/5.10.0/i386-linux-thread-multi
/usr/lib/perl5/vendor_perl/5.10.0
/usr/lib/perl5/vendor_perl
/usr/lib/perl5/5.10.0/i386-linux-thread-multi
/usr/lib/perl5/5.10.0
/usr/lib/perl5/site_perl
.
----------------------------------------------------------------------------------------------

■次に、Crypt::SSLeayとNet::SSLeayが入っているか確認↓

----------------------------------------------------------------------------------------------
(コマンド)
$ su
# cd /

# find -path *Crypt/SSL*

#
(↑Crypt::SSLeayは入っていない)

# find -path *Net/SSL*

./usr/lib/perl5/vendor_perl/5.10.0/i386-linux-thread-multi/Net/SSLeay
./usr/lib/perl5/vendor_perl/5.10.0/i386-linux-thread-multi/Net/SSLeay/Handle.pm
./usr/lib/perl5/vendor_perl/5.10.0/i386-linux-thread-multi/Net/SSLeay.pm
./usr/lib/perl5/vendor_perl/5.10.0/i386-linux-thread-multi/auto/Net/SSLeay
./usr/lib/perl5/vendor_perl/5.10.0/i386-linux-thread-multi/auto/Net/SSLeay/https_cat.al
./usr/lib/perl5/vendor_perl/5.10.0/i386-linux-thread-multi/auto/Net/SSLeay/do_https4.al
./usr/lib/perl5/vendor_perl/5.10.0/i386-linux-thread-multi/auto/Net/SSLeay/get_httpx3.al
./usr/lib/perl5/vendor_perl/5.10.0/i386-linux-thread-multi/auto/Net/SSLeay/get_http.al
./usr/lib/perl5/vendor_perl/5.10.0/i386-linux-thread-multi/auto/Net/SSLeay/put_http.al
./usr/lib/perl5/vendor_perl/5.10.0/i386-linux-thread-multi/auto/Net/SSLeay/want_read.al
   ・
   ・
   ・
(以下省略)

(↑@INCでは「/usr/lib/perl5/vendor_perl/5.10.0/i386-linux-thread-multi」にNet::SSLeayが入っている)
----------------------------------------------------------------------------------------------

■試しに名前を変えてみる↓

----------------------------------------------------------------------------------------------
# cd /usr/lib/perl5/vendor_perl/5.10.0/i386-linux-thread-multi/Net
# mv SSLeay.pm SSLeay.pm2
----------------------------------------------------------------------------------------------

■スクリプト↓でhttpsにリクエストしてみる

----------------------------------------------------------------------------------------------
#!/usr/bin/perl

use strict;
use LWP::UserAgent;
use HTTP::Request::Common;

my $ua = LWP::UserAgent->new();

my $url = "https://www.hogehoge.jp"; # 実在するセキュアサイト

$request = &HTTP::Request::Common::GET($url);
$response = $ua->request($request);

print "Content-type: text/plain\n\n";
print $response->status_line;

exit;
----------------------------------------------------------------------------------------------

■実行結果↓

----------------------------------------------------------------------------------------------

501 Protocol scheme 'https' is not supported

(httpsプロトコルはサポートしていません)
----------------------------------------------------------------------------------------------

■SSLeay.pmを元に戻す↓

----------------------------------------------------------------------------------------------
# mv SSLeay.pm2 SSLeay.pm
----------------------------------------------------------------------------------------------

■さっきのスクリプトをもう一度実行↓

----------------------------------------------------------------------------------------------

302 Found

(ファイルが存在します=接続成功)
----------------------------------------------------------------------------------------------


めでたしめでたし。
あるプロセスがサーバに過大な負荷をかけているとき、その犯人と、原因のプログラムファイルを発見する一番早い(?)方法。


まずtopコマンドやpsコマンドで、そのプロセスのプロセス番号を調べる。

-------------------------------------------------------------------------------------------

$ su

# top

-------------------------------------------------------------------------------------------


プロセス番号がわかったら、

-------------------------------------------------------------------------------------------

# ls -l /proc/(プロセス番号)/exe

-------------------------------------------------------------------------------------------

として、実行ファイルのシンボリックリンクを参照する。
※エディタで直接/proc/(プロセス番号)/exe にアクセスしてもバイナリファイルなので見れません。


結果↓

------------------------------------------------------------------------------------------

lrwxrwxrwx 1 hoge.hoge 0 2010-01-27 05:23
/proc/プロセス番号/exe -> /home/●●/hoge/○○○

------------------------------------------------------------------------------------------

つまり「●●」が犯人で「○○○」が問題のファイル。



あとは犯人に警告するなりプロセスをkillするなりご自由に。
DocumentRoot以外の場所にあるファイルをダウンロードさせようとして、プログラム側で「Location」させても、普通はアクセスできない。

そういった場合は前記事(http://www.igreks.jp/dev/2009/10/perlmysql2.html)の応用で、「cat」コマンドを利用するとダウンロードできるようになる。


-----------------------------------------------------------------------

#!/usr/bin/perl -w

use strict;

my $dir = '../../hoge'; #Documentroot外のディレクトリ
my $file = 'huga'; #その中にあるファイル

print "Content-Type: application/octet-stream\n";
print "Content-Type: application/download; name=$file\n";
print "Content-Disposition: attachment; filename=$file\n";
print "\n";
#### print content
system "cat $dir/$file";

exit;

-----------------------------------------------------------------------


※DocumentRoot以下に置いてBasic認証かけるよりは安全?
※LWP転送するときもOK

SQLだけでこういう処理をする方法が調べてもわからないので、スクリプト側でチェックしてみる。

メイン
------------------------------------------------------------------------------------------
#!/usr/bin/perl -w

use strict;
use DBI;
require './db.pl';

&db::open();

 my $table = 'table_name';
 ##追加カラム情報セット
 my @add = (
  ['field1' ,'INT' ],
  ['field2' ,'VARCHAR(255)' ],
  ['field3' ,'DATE' ],
  ['field4' ,'INT', ],
  ['field5' ,'VARCHAR(255)' ],
  ['field6' ,'VARCHAR(255)' ],
  ['field7' ,'INT' ]
 );
 my $cols = '';
 ##現在のテーブル情報を取得
 &db::query("DESCRIBE $table");
 while(my $href = $db::sth->fetchrow_hashref()){
  ##カラム名をセット
  $cols .= '<>'.$href->{'Field'}.'<>';
 }
 ##無ければ追加
 foreach(@add){
  if($cols !~ /<>$_[0]<>/){
    &db::query("ALTER TABLE $table ADD $_[0] $_[1]");
  }
 }

&db::close();
exit;
---------------------------------------------------------------------------------------



DB接続(db.pl)
---------------------------------------------------------------------------------------
package db;

use strict;

sub open{
my $dbs = "DBI:mysql:dbname:dbhost";
our $dbh = DBI->connect($dbs,dbuser,dbpass);
if(!$dbh){
die "データベースに接続できません";
}
}

sub query{
my ($sql) = @_;
our $sth = $db::dbh->prepare($sql) || die $db::dbh->errstr();
my $exec = $sth->execute || die $sth->errstr();
return $exec;
}

sub close{
$db::sth->finish;
$db::dbh->disconnect;
}

1;
---------------------------------------------------------------------------------------
実行中のプロセスのCPU使用率やメモリ占有率などをリアルタイムで監視するUNIXコマンド。

-----------------------------------------------------------------

$ su (rootになる)

# top

(プロセス一覧が表示される)


"q"で終了
----------------------------------------------------------------

以上。


オプションとして便利なのは、

-d: 更新間隔を指定する: -d ss.tt (秒.10分の1秒)
-u: 指定した実効UIDかユーザ名にマッチするプロセスだけをモニターする: -u somebody


例えばWEBサーバが実効しているプロセスだけを0.5秒間隔に確認したい場合は、

--------------------------------------------
# top -d 0.5 -u apache
--------------------------------------------

でOK。