現在JavaScriptの設定が無効になっています。このページを利用するにはJavaScriptの設定を有効にしてください。トップ全記事一覧テクノロジー2010.09.16ソースコードリーディング(wコマンド編)-ロードアベレージ/ログインユーザ/プロセス情報の取得こんにちは、みなさんお久しぶりです。Yahoo!ショッピング開発担当の吉野哲仁です。約1年3ヶ月ぶりのソースコードリーディングは、wコマンドのソースコードを読んでいきたいと思います。■はじめにwコマンドは、システムの稼働状況とログインユーザーの情報を表示するコマンドです。システム運用ではよく使われます。ロードアベレージを取得するために使用する場合も多いと思います。wコマンドでやっていることは大きく分けて2つ。・現在のログインユーザー情報(ユーザー名、端末名、ログイン元ホスト、現在実行しているコマンドなど)の表示です。今回はこの2つにスポットを当てて読んでいきたいと思います。※ソースのリビジョンについて今回読むソースのリビジョンは、カレントの最新(9.0)ではなく、「RELENG_8_1_0_RELEASE」のcvsタグが付いているリビジョンです。w.cなどは最新とは若干処理が異なります(ログインユーザー情報の取得方法など)。<src/usr.bin/w>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/w/■1.現在のシステム状況の表示まずは実際の出力を見てみましょう。(bash)こんな感じで、システム稼働時間/ロードアベレージ/ログインユーザー情報などが出力されます。0.30この部分を見ていきます。ログインユーザー数の取得です。&ehead;[コード1]はutmpファイルから現在ログインしているユーザー情報の取得を行っています。ユーザー数をカウントする変数です。後ほど読んでいくログインユーザー情報の表示部分で使用する処理がありますので、ついでに読んでいきます。221行目では、ユーザーの端末デバイスファイル(/dev/ttyp*)のファイルステータス情報を取得しています。内に定義されている関数で、中ではstatシステムコールを使用して、端末デバイスファイルのstat構造体を取得しています。stpはstat構造体へのポインタです。237行目から出てくるepは、[コード2]にあるentry構造体のポインタです。最終的にはこのepの中にログインユーザー情報がすべて入ります。epはこの後も頻繁に登場するので覚えてください。253~259行目では、端末のアイドル時間を取得しています。}[コード3]ではマシンの稼働時間を取得して表示しています。15:34」といった形に整形して表示しています。}[コード4]では、ログインユーザー数の表示とロードアベレージの取得/表示をしています。461行目でログインユーザー数(nusers)の表示、466行目でgetloadavg()を使用してロードアベレージの取得を行っています。avenrun[3];」です。15分のロードアベレージといった感じでロードアベレージが取得できます。getloadavg()は標準ライブラリ関数ですが、今回は少しgetloadavg()の中身も読んでみましょう。}[コード5]はgetloadavg()の全コードです。ロードアベレージはsysctl()を使用して取得しています。sysctl()はシステム情報を取得する際に頻繁に使用されるライブラリ関数で、59,60行目にあるとおり、sysctl()の第1引数には取得する情報名を配列で指定しています。指定することでロードアベレージが取得できます。sysctl()の詳細については機会があったら別の回で読んでいきたいと思います。続いて、現在ログインしているユーザー情報を取得する部分を見ていきます。(bash)この部分です。[コード1]で、すでにutmpから端末IDやアイドル時間の取得を行いました。次はユーザーの実行プロセスの取得部分です。}[コード6]はユーザーの実行プロセスを特定する部分です。284行目でkvm_getprocs()を使って、すべてのプロセス情報を取得します(kvm_getprocs()に渡すkd[カーネル仮想メモリ領域へのディスクリプタ]を取得するために、208行目でkvm_openfiles()を使っています)。続いて286行目からプロセスの個数(nentries)分ループし、ep(現在のログインユーザー情報)の内容と比較してユーザーの現在の実行プロセスを特定します。290行目でepに格納されている端末ID(ep->tdev)とプロセスの端末ID(kp->ki_tdev)を比較して、同じ端末IDから実行されたプロセスを特定します。294行目でプロセスのグループID(kp->ki_pgid)と、端末のプロセスグループID(kp->ki_tpgid)を比較し、一致していたらそのプロセスは現在端末で実行されているプロセスとみなします。[コード7]では、特定したプロセスのコマンドラインを引数を含めてフルで取得し、ep->argsに格納しています。}[コード8]は非常に長いループですが、これが最後です。351行目~389行目では、ユーザーのログイン元ホスト(ep->utmp.ut_host)からホスト名を逆引きし、変数pに代入しています。ホストが逆引きできない場合もしくは-nオプションが指定されている場合は、IPアドレスをそのままpに保持します。390行目~401行目は-dオプションが指定された場合の処理で、現在その端末からされたすべてのプロセスIDとコマンド文字列を表示するための処理です。402行目~413行目で現在のログインユーザー情報の表示を行います。ヘッダ項目はすでにw.cの270行目~281行目で出力されています。402行目~408行目でユーザー名(ep->utmp.ut_name)、端末ID(ep->utmp.ut_lineから先頭のttyを除く)、ログイン元ホスト名(変数p)を出力します。続いて、409行目~411行目でログイン時間(ep->utmp.ut_time)とアイドル時間(ep->idle)を出力します。ログイン時間とアイドル時間の整形と出力に使用されているpr_attime()、pr_idle()は、w.cと同じディレクトリにあるpr_time.cに定義されています。最後に412,413行目で現在実行されているコマンド文字列(ep->args)を出力して完了です。たかがwコマンドといえど、今回登場したロードアベレージやプロセス情報の取得で使われているライブラリ関数は、topコマンドやpsコマンドなどいろんなコマンドで使用されているので、覚えておいて損はないと思います。使えばシステム情報が意外に簡単に取得できるので、実際にコードを書いて試してみてください。今回のお話は以上です。JAPANでは情報技術を駆使して人々や社会の課題を一緒に解決していける方を募集しています。詳しくは採用情報をご覧ください。JAPANのサービス開発を支える技術やデザイン、文化を発信しています。Reserved.このページの先頭へ。