のぴぴのメモ

自分用のLinuxとかの技術メモ

【RHEL】linuxメモリのfreeとmeminfoの関係を図解し利用率の計算方法を説明してみる

はじめに

linuxサーバを利用する上で何時も頭を悩ますものの一つが、メモリ利用状況の評価(メモリ利用率)ではないでしょうか。私も悩みます。そこでRHELベースですが、メモリ利用容量/メモリ利用率の評価をどう考えるかということを整理しました。
詳細は後述しますが、例えばRHEL7のfreeコマンドとmeminfoの関係を整理するとこんな感じになります。
f:id:nopipi:20150913163740p:plain

ちなみにlinuxのメモリ解説&meminfoをどのように見ればいいかは、e.nakaiさんのページが参考になります。(私のメモリ周辺のバイブル的ページです^^;)
enakai00.hatenablog.com

linuxのメモリ利用容量(空き容量)の考え方

何を持って、「メモリが空いている」とするのか??
単純に考えると、何も利用していない(割り当てていない)領域を空き容量とすればいいはずです。しかしlinuxをはじめとする現在のOSでは、「使えるメモリはとことん使ってしまえ!!」という設計思想なため、空きメモリは積極的にファイルキャッシュ用途に利用してしまいます。その結果、「未割り当て領域を空き領域」と定義すると、メモリ利用率が常に100%となり「意味がねぇなぁ」という感じになってしまいます。

そこで改めて「メモリが空いている状態」を考える必要があります。そこで着目するのが、メモリ解放のカーネルの挙動です。カーネルはプロセスやドライバから新規メモリ(ページ)の確保要求があった時、未使用領域(freeコマンドやmeminfoで言うところのfree領域)から新規割り当てを行います。未使用領域が無い場合、既存のメモリを解放して空きを作り、新なメモリ割当を行います。この「既存メモリの解放処理」は2通りのやり方があり、一つはスワップアウトして空きを作る方法、もう一つはディスク同期してメモリ解放する方法になります。メモリ解放の方式を整理すると、以下の表のようになります。

メモリ解放方法 対象ページ 対象ページの例 再アクセス時の挙動
スワップアウトして解放 無名ページ
(anonymous page)
プロセスのメモリ(データ/スタック領域),共有メモリ,tmpfs スワップイン
ディスク同期して解放 ファイルページ
(file page)
ファイルキャッシュ&バッファ、プロセスのテキスト領域 ディスクから再読み込み

※1 無名ページ&ファイルページについては、記事文末を参照。
※2 プロセスのテキスト領域とは、プロセスの実行イメージ(プログラム)を格納するメモリ領域です。
※3 もちろん、プロセス終了やプログラム中のfree()など、本当に不要になって開放するパターンもありますが、ここでは割愛します。

ここでサーバ用途の場合のメモリ設計を考えると、「可能な限りスワップを発生させないようにメモリサイジングする」ことが重要になります。特に(バッチ処理ではなく)オンライン系のサーバ(web,AP,DBサーバとか)の場合、スワップイン処理にかかるオーバーヘッドによるクライアントへのレスポンス遅延が一番気になるためです。例えば通常1秒以内でレスポンスが帰っている処理が数秒や最悪十数秒に伸びることで、利用者のユーザビリティが落ち「使えねーシステム」の烙印を押されることになることになるためです。

ということで、メモリ空き容量を評価する上は、「スワップが発生しない程度」の空きが保たれていることが重要というとになり、結果として「未割当て領域+ディスク同期による解放領域」を空きと見なすという考えになります。(説明がちょっと強引ですが。)

ここまでの話を、式にまとめると以下のような形になります。

メモリの空き容量 = 未割り当て容量(free) + ディスク同期にて解放可能な容量(ファイルページ≒バッファ&キャッシュ)
メモリ利用容量 = メモリ合計容量 - メモリ空き容量
               = メモリから解放不可な容量 + 解放時にスワップアウトしてしまう容量





linuxのメモリ利用容量/空き容量の計算方法

と前置きが長かったですが、ここからがlinuxの悩ましい所。

なぜなら、linuxでメモリ容量を確認するfreeコマンドで取得できるバッファ&キャッシュ領域には、スワップする領域も含まれており、単純に「メモリ利用容量=メモリ全体 - free - Buffer&Cache」としてしまうと、メモリ利用容量を過小評価してしまうためです。最近のlinuxカーネルはこの辺を考慮したメモリ情報を表示してくれるのですが(RHEL7とか。詳細は後述)、昔の特にRHEL5以前は真面目にやろうとすると結構しんどかったです。(カーネルのメモリ管理を理解していなかったという要素も大きいですが。。。)

以下に最新のRHEL7から順に、代々のバージョンでどのようにメモリ利用容量/利用率を計算していたかを説明します。こうやって整理すると、「昔は苦労したなぁ〜」というのがよくわかりますね。^^;

■RHEL7

最初にRHEL7ですが、RHEL7からはメモリ利用率の計算が劇的に楽になりました。
というのも、上でぐちゃぐちゃ説明したことを、freeコマンドの「available」というパラメータで表示してくれるからです。(厳密には/proc/meminfoに"MemAvailable:"という利用可能なメモリ容量の目安を表示してくれるようになったのですが)

なので、わざわざmeminfoをみなくても、freeコマンドの結果をちょっと加工すれば利用率をだせるようになりました。

【freeコマンドとmeminfoの図解】

f:id:nopipi:20150913163740p:plain

【計算方法】

freeコマンドの結果をawkで処理させています。

#!/bin/bash
export LANG=C, LC_ALL=C

free | awk '
    BEGIN{
        total=0;used=0;available=0;rate=0;
    }

    /^Mem:/{
        total=$2;
        available=$7;
    }

    END{
        used=total-available;
        rate=100*used/total;
        printf("used%,total(KB),used(KB),available(KB)\n");
        printf("%.1f,%d,%d,%d\n",rate,total,used,available);
    }';
freeコマンド表示例
# free
              total        used        free      shared  buff/cache   available
Mem:        1884812      106076     1615644        8632      163092     1624364
Swap:       2097148           0     2097148
/proc/meminfo表示例
# cat /proc/meminfo
MemTotal:        1884812 kB
MemFree:         1615784 kB
MemAvailable:    1624504 kB
Buffers:             880 kB
Cached:           120396 kB
SwapCached:            0 kB
Active:            84932 kB
Inactive:          95568 kB
Active(anon):      59524 kB
Inactive(anon):     8332 kB
Active(file):      25408 kB
Inactive(file):    87236 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:       2097148 kB
SwapFree:        2097148 kB
Dirty:                 0 kB
Writeback:             0 kB
AnonPages:         59244 kB
Mapped:            20852 kB
Shmem:              8632 kB
Slab:              41816 kB
SReclaimable:      17396 kB
SUnreclaim:        24420 kB
KernelStack:        1680 kB
PageTables:         3688 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:     3039552 kB
Committed_AS:     268452 kB
VmallocTotal:   34359738367 kB
VmallocUsed:      156764 kB
VmallocChunk:   34359575144 kB
HardwareCorrupted:     0 kB
AnonHugePages:      4096 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
DirectMap4k:       53184 kB
DirectMap2M:     2043904 kB

■RHEL6

RHEL6時代までのfreeコマンドでは、バッファ&キャッシュ領域にスワップアウトしてしまうメモリも含まれているため、meminfoを直接参照していました。ただRHEL5以前とは異なり、RHEL6ではメモリ管理にSplitLRUが導入され、無名ページとファイルページを分て管理するようになっており、meminfoでもactive,inactive(メモリ回収候補ページのリスト)の登録ページ数が種別ごとに表示されるようになっているので、それを利用してメモリ計算をしています。

【freeコマンドとmeminfoの図解】

f:id:nopipi:20150913163744p:plain


【計算方法】

/proc/meminfoのデータをawkでガリガリ計算させています。

export LANG=C, LC_ALL=C

awk '
    BEGIN{
        total=0;used=0;available=0;rate=0;
    }

    /^MemTotal:/         {total=$2;}
    /^MemFree:/          {available=available+$2;}
    /^Active\(file\):/   {available=available+$2;}
    /^Inactive\(file\):/ {available=available+$2;}

    END{
        used=total-available;
        rate=100*used/total;
        printf("used%,total(KB),used(KB),available(KB)\n");
        printf("%.1f,%d,%d,%d\n",rate,total,used,available);
    }' /proc/meminfo;
freeコマンド表示例
# free
             total       used       free     shared    buffers     cached
Mem:       1020236     147168     873068        268      17824      54444
 -/+ buffers/cache:      74900     945336
Swap:      1048572          0    1048572
/proc/meminfo表示例
MemTotal:        1020236 kB
MemFree:          873068 kB
Buffers:           17832 kB
Cached:            54460 kB
SwapCached:            0 kB
Active:            38724 kB
Inactive:          51140 kB
Active(anon):      17580 kB
Inactive(anon):      256 kB
Active(file):      21144 kB
Inactive(file):    50884 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:       1048572 kB
SwapFree:        1048572 kB
Dirty:                60 kB
Writeback:             0 kB
AnonPages:         17588 kB
Mapped:            15584 kB
Shmem:               268 kB
Slab:              34304 kB
SReclaimable:       8984 kB
SUnreclaim:        25320 kB
KernelStack:        1280 kB
PageTables:         5236 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:     1558688 kB
Committed_AS:     101760 kB
VmallocTotal:   34359738367 kB
VmallocUsed:      138664 kB
VmallocChunk:   34359594564 kB
HardwareCorrupted:     0 kB
AnonHugePages:         0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
DirectMap4k:        8192 kB
DirectMap2M:     1040384 kB

RHEL5以前

で、一番悩ましいRHEL5以前です。この時代はfreeコマンドがダメでかつ、この当時は無名ページとファイルページを一緒に管理(一つのLRUリストにゴジャッと登録していた)ため、meminfoでもファイルページ数を的確に把握することができませんでした。

そこでどうするかというと、ファイルキャッシュ&バッファとしてカウントされるもののうち、無名ページに該当するものほとんどは、(1)tmpfs用のメモリ,(2)IPCの共有メモリ用のメモリ、の2つになることに着目します。そこで、それぞれの利用状況を取得してその分をmeminfoから取得した値から引き算し近似的に利用可能な容量を計算するというやり方をします。

  • キャッシュ&バッファから除外する容量の計算方法
    • tmpfs --> dfコマンド結果から、tmpfsのusedの容量を足し算する
    • IPC共有メモリ --> "ipcs -u"コマンドの"pages allocated"(共有メモリ様に割り当て済みのページ数)を取得
【freeコマンドとmeminfoの図解】

f:id:nopipi:20150913163749p:plain

【計算方法】

dfコマンド、"ipcs -u"コマンド、と/proc/meminfoのデータを組み合わせて、awkで計算させています。

#!/bin/bash

export LANG=C, LC_ALL=C

#メモリファイル
TMPFS=`/bin/df --portability |awk 'BEGIN{used=0;} /^tmpfs/{used=used+$3}END{print used}'`

#IPC シェアードメモリ
PAGE_SIZE=$((`/usr/bin/getconf PAGE_SIZE` / 1024))
IPC_SHM=`/usr/bin/ipcs -u |awk -v SIZE=${PAGE_SIZE} '/^pages allocated/{print $3 * SIZE}'`

#シェアードメモリ合計(tmpfs + ipc_shm)
SHMEM=$(( ${TMPFS} + ${IPC_SHM} ))

awk -v shmem=${SHMEM} '
    BEGIN{
        total=0;used=0;available=0;rate=0;
    }

    /^MemTotal:/ {total=$2;}
    /^MemFree:/  {available=available+$2;}
    /^Buffers:/  {available=available+$2;}
    /^Cached:/   {available=available+$2;}

    END{
        available=available-shmem
        used=total-available;
        rate=100*used/total;
        printf("used%,total(KB),used(KB),available(KB)\n");
        printf("%.1f,%d,%d,%d\n",rate,total,used,available);
    }' /proc/meminfo;
freeコマンド表示例
# free
             total       used       free     shared    buffers     cached
Mem:       2058764     313972    1744792          0      19748     165736
  • /+ buffers/cache: 128488 1930276
Swap: 4095992 0 4095992
/proc/meminfo表示例
MemTotal:      2058764 kB
MemFree:       1744792 kB
Buffers:         19756 kB
Cached:         165736 kB
SwapCached:          0 kB
Active:         103444 kB
Inactive:       160096 kB
HighTotal:           0 kB
HighFree:            0 kB
LowTotal:      2058764 kB
LowFree:       1744792 kB
SwapTotal:     4095992 kB
SwapFree:      4095992 kB
Dirty:             112 kB
Writeback:           0 kB
AnonPages:       78060 kB
Mapped:          10520 kB
Slab:            26440 kB
PageTables:       3472 kB
NFS_Unstable:        0 kB
Bounce:              0 kB
CommitLimit:   5125372 kB
Committed_AS:   158884 kB
VmallocTotal: 34359738367 kB
VmallocUsed:    265472 kB
VmallocChunk: 34359470723 kB
HugePages_Total:     0
HugePages_Free:      0
HugePages_Rsvd:      0
Hugepagesize:     2048 kB

蛇足

その1:無名ページとファイルページ

まず、このページではファイルページと記載しましたが、正確には「ファイルバックド(file-backed)ページ」ですかね。また、ファイルページを記事内では「ディスクと同期して解放」と記載してますが、正確にはディスクと同期するのは未同期データの解放の時のみです。同期済みの場合は同期処理なく解放します。

無名ページとファイルページの違いをざっくりと書くと、本文にも記載しましたが以下の通りになります。

  • 無名ページ --->メモリが足りない時スワップアウト(スワップへ退避)され、物理メモリから解放されるページ
  • ファイルページ ---> メモリが足りない時ディスク同期し解放されるページ

蛇足になりますが、10年前にカーネル本(オライリー&ペンギン黒本)を読んだ時は、いきなり「無名ページ」と出て来て、何が何だか分からず挫折した経験があります。それから10年経ってやっと「スワップする/しない、の差なのね」という理解に到達。この辺の理解している人としてない人の溝の深さが、カーネルを理解する上での障壁(カーネル難しぃ〜)の一つになっているのかなと思います。

その2:図解の内容のツッコミ

「SReclaimable」領域を、「ディスク同期して解放」で色塗りしていますが、実際は単純にslabとして未使用領域で、メモリが足りない場合は単純に開放するだけですね。後で気付いたのですが、図を修正するのが面倒なので、そのままにしちゃいました。

その3:RHEL6の計算

RHEL6では、"active(file)"と"inative(file)"から計算していますが、RHEL7のavailaleのカーネル内部の計算を見るに、"SReclaimable"も加算しなければならないですね。まあ全体量に対して、"SRelaimale"は小さいので加算しなくても大した影響はないとおもいますが。

その4:Inactiveを空き領域とすることは間違い。

ちなみに、linuxでのメモリ利用量(空き容量)をググると「利用可能なメモリ ≒(MemFree+Inactive)」という話がでますが、これはガチャピン先生が指摘されていますが、間違いです。

【Fedora22】日本語入力設定のメモ

忘れないように、自分用のメモ

IME設定(デフォルトibus-kkcを入力ソースに追加)

Fedora22のデフォルトIMEは、ibus-kkcのようでデフォルトでインストールされている。しかし、入力ソースに含まれておらずインストール直後の状態では日本語入力ができない(私の環境だけ?)。なので、日本語入力できるように追加設定をする。

  1. 「アクティビティ」→「設定」を開き、「地域と言語」を選択
  2. 「入力ソース」で「+」ボタンを押す
  3. 出て来たウィンドウの言語リストから「日本語(かな漢字)」を選択し「追加」ボタンを押す
  4. 本のウィンドウの「入力ソース」に新しい入力ソースが追加されていることを確認

IME切替ショートカットの変更(「半角/全角」キーに変更)

個人的に「半角/全角」キーでIME切り返したいので設定変更。

  1. 「アクティビティ」→「設定」を開き、「キーボード」を選択
  2. タブを「ショートカット」に変更
  3. 左のカテゴリから「タイピング」を選択し、「次の入力ソースへ切り替える」を選択
  4. キー設定部分が「新しいアクセラレータ」と表示されるので、「半角/全角」キーを入力し設定する

【RHEL7】sysctlのカーネルパニックオプション

sysctlのカーネルパニックオプション

ちょいとカーネルパニックをどう設定すればよいかという話があって、ためしにsyscltをpanicでgrepすると、意外にというかpanicに関するパラメータがバラバラ出てきてどうすればよいかイマイチわからない。

# sysctl -a|grep panic
fs.xfs.panic_mask = 0
kernel.hung_task_panic = 0
kernel.panic = 0
kernel.panic_on_io_nmi = 0
kernel.panic_on_oops = 1
kernel.panic_on_stackoverflow = 0
kernel.panic_on_unrecovered_nmi = 0
kernel.panic_on_warn = 0
kernel.softlockup_panic = 0
kernel.unknown_nmi_panic = 0
vm.panic_on_oom = 0

ということで整理してみた。

panicの整理

整理するとこんな感じ。

  • パニック本体設定
      • kernel.panic
  • トリガー設定
    • NMI割込みトリガー(SVP/iLO2とかからのNMI割込みによるダンプ取得)
      • kernel.panic_on_unrecovered_nmi
      • kernel.unknown_nmi_panic
      • kernel.panic_on_io_nmi
    • OOPSメッセージトリガー
      • kernel.panic_on_oops
    • カーネル警告メッセージトリガー
      • kernel.panic_on_warn
    • watchdogトリガー
      • kernel.softlockup_panic
    • ハングタスクチェックトリガー
      • kernel.hung_task_panic
    • カーネル内のスタックオーバーフロートリガー
      • kernel.panic_on_stackoverflow
    • OOM killerトリガー
    • xfs系統
      • fs.xfs.panic_mask

panic系パラメータの関係

カーネルソースから各パラメータの関係を整理すとこうなる。
f:id:nopipi:20150516115617p:plain

それぞれのパラメータの挙動

kernel.panic

  • 説明
    • panic時の挙動設定。kdump利用時は、このパラメータが使われている処理ロジックの前に、kdumpのセカンドカーネル起動が走るため、パラメータが使われることはない。
  • 設定
    • kernel.panic > 0:n秒後まって再起動
    • kernel.panic = 0:ハング(デフォルト)
    • kernel.panic < 0:即時再起動

kernel.panic_on_unrecovered_nmi

  • 説明
    • メモリECCで修復不能なエラー、PCI通信の致命的エラー、あとサーバ管理コンソール(SVP/CMM/iLO2)からのダンプ取得のためのNMI割込み時に、panicさせるかの設定。
  • 設定
    • kernel.panic_on_unrecovered_nmi=0:panicしない(デフォルト)
    • kernel.panic_on_unrecovered_nmi=1:panicする

kernel.unknown_nmi_panic

  • 説明
    • kernel.panic_on_unrecovered_nmiとほぼ同じで、PCI通信の致命的エラー時のpanicが含まれないだけ。なのでpnic_on_unrecovered_nmiだけ設定すれば十分。
  • 設定
    • kernel.kernel.unknown_nmi_panic=0:panicしない(デフォルト)
    • kernel.kernel.unknown_nmi_panic=1:panicする

kernel.panic_on_io_nmi

  • 説明
    • IOエラーが原因で NMI割込みが発生した場合のpanic有無。致命的なパターンなのでpanicがいいのかな。またHPのサーバではiLO2からのダンプ取得のためにONにするようなことが書かれている。
  • 設定
    • kernel.panic_on_io_nmi=0:panicしない(デフォルト)
    • kernel.panic_on_io_nmi=1:panicする

kernel.panic_on_warn

  • 説明
    • カーネルのワーニング出力時(WARN()呼び出し時)にpanicさせるかの設定。カーネルのデバックでもない限り、WARN()ごときでpanicさせないだろう。
  • 設定
    • kernel.panic_on_warn=0:panicしない(デフォルト)
    • kernel.panic_on_warn=1:panicする

kernel.softlockup_panic

  • 説明
    • カーネルのwatchdog監視が有効(kernel.nmi_watchdogか、kernel.watchdogが1の場合、有効)の場合で、watchdog監視に引っかかった時のpanic発生有無。
  • 設定
    • kernel.softlockup_panic=0:panicしない(デフォルト)
    • kernel.softlockup_panic=1:panicする

kernel.hung_task_panic

  • 説明
    • khungtaskカーネルスレッドが、TASK_UNINTERRUPTIBLE状態が120秒(デフォルト)超過しているスレッドを監視していて、該当するスレッドがいた時にpanicさせるかの設定。
  • 設定
    • kernel.hung_task_panic=0:panicしない(デフォルト)
    • kernel.hung_task_panic=1:panicする

kernel.panic_on_stackoverflow

  • 説明
    • カーネル内でスタックオーバーフローが発生した時にpanicさせるかの設定。
  • 設定
    • kernel.panic_on_stackoverflow=0:panicしない(デフォルト)
    • kernel.panic_on_stackoverflow=1:panicする

vm.panic_on_oom

  • 説明
    • OOM killer発生時のpanic有無
  • 設定
    • vm.panic_on_oom=0:panicしない(デフォルト)
    • vm.panic_on_oom=1:panicする。ただし、cgroupの制限に引っかかった場合はpanicしない。
    • vm.panic_on_oom=2:panicする。cgroup制限も含め問答無用でpanicする。

RHEL7 initramfsの展開方法

今までのやり方では展開されない

普通、initramfsの中身を展開する場合は、gunzipあたりとcpioを使って以下のようにするはず。

$ cd /tmp
$ cp /boot/initramfs.img initramfs.gz
$ gunzip initramfs.gz
$ mkdir ramdisk
$ cd ramdisk
$ cpio -i -d -H newc --no-absolute-filenames < ../initramfs

ところが、最近のFedora/CentOS/RHELで上記をやると、これは「gzipじゃない!!」と怒られてしまう。

$gunzip initramfs.gz
gzip: initramfs.gz: not in gzip format

じゃあ、fileで確認するとcpioだというから直接cpioで展開すると、CPUのマイクロコードらしきものしか展開されない(´・ω・`)

$ mkdir ramdisk
$ cd ramdisk
$ file ../initramfs.gz
../initramfs.gz: ASCII cpio archive (SVR4 with no CRC)
$ cpio -i -d -H newc --no-absolute-filenames < ../initramfs.gz
26 blocks
$ find .
.
./kernel
./kernel/x86
./kernel/x86/microcode
./kernel/x86/microcode/GenuineIntel.bin
./early_cpio

[RHEL7/CentOS7/FC21]initramfsの展開方法

グーグルさんに聞いてみる

キーワードを変えていろいろ調べたら、出てきた。
forums.fedoraforum.org

手順

上記内容をちょっとだけ丁寧に解説。

バイナリ解析ツールのインストール

まずバイナリー解析用ツールを入れないといけないらしい。

yum -y install binwalk

なおRHELCentOSのレポジトリにはbinwalkはないので、ネットからrpmパッケージをDLしてrpmコマンドで個別にインストールするか、ソースを落としてコンパイルする。

initramfsの解析と展開
$ cp /boot/initramfs-3.10.0-229.el7.x86_64.img .
$ binwalk initramfs-3.10.0-229.el7.x86_64.img

DECIMAL         HEX             DESCRIPTION
-------------------------------------------------------------------------------------------------------
13312           0x3400          gzip compressed data, from Unix, last modified: Thu Apr 30 13:18:46 2015, max compression
3412955         0x3413DB        bzip2 compressed data

$ dd if=initramfs-3.10.0-229.el7.x86_64.img of=initramfs.gz bs=13312 skip=1
1350+1 records in
1350+1 records out
17982993 bytes (18 MB) copied, 0.0431475 s, 417 MB/s
$ gunzip initramfs.gz
$ mkdir ramdisk
$ cd ramdisk/
$ cpio -i -d -H newc --no-absolute-filenames < ../initramfs
80381 blocks
    • binwalk解析でgzipが始まる位置を確認(上記例では、13312bytesから開始)
    • ddコマンドでgzipの前のデータをスキップしてコピー("bs=13312 skip=1"がミソ)
    • それ以降は今までのやり方と同じ

なおgzipが始まる位置はその時々で変わる(おそらくmicrocodeのデータサイズが変わるから)ため、都度binwalk解析の確認が必要。

RHEL6 squashfsの作り方

squashfsとは

squashfsとは、圧縮された読み込み専用のファイルシステムでLiveCD(CD/DVDブートして利用するOS)で利用されている。詳しくはwikipediaを見るのが手っ取り早いかと。
wikipedia:SquashFS

squashfsファイルシステムの作り方

squashfs用ツールのインストール

squshfsなファイルシステムはmksquashfsコマンドを利用するが、CentOSなどではデフォルトでは入っていないため、個別にrpmパッケージ(squashfs-tools)インストールする必要がある。

# yum install squashfs-tools

squashfsファイルシステムの作成

mksquashfsコマンドで、squashfsファイルシステムを作成する。

$ mksquashfs ./SOURCE/ File.squashfs

squashfsファイルシステムのマウント

出来上がったsqushfsはmountコマンドのループバックオプションでマウントする。

#  mount -o loop File.squashfs /MountPoint/

fstabで自動マウント

fstabに登録するときは以下のように記載する。

/Directory/File.squashfs /MountPoint  squashfs loop 0 0

mountコマンドでマウントする。

# mount -a

追伸

昔、cloopで圧縮ファイルを作るということをやっていたけど(Fedora5/RHEL4 cloopでLinux圧縮ファイルシステムを作る - のぴぴのメモ、Upstreamにマージされていて各ディストリビューションにもデフォルトで入っているsquashfsのほうが使いやすいですよね。

Linux /proc/meminfoの統計情報を取得する。

/proc/meminfoの統計情報を取得する

 Linuxのメモリ挙動を詳しく分析するためには/proc/meminfoを見る必要がある。がしかし、sarコマンドのように時系列でmeminfo情報を取得してくれるコマンドはなく、自作のスクリプトなどで取得するしかない。  

そこで、スクリプトで/proc/meminfo情報を時系列で取得する方法を説明する。

  • 2013.3.4 awkコマンド修正(ヘッダ末尾のリターンコード忘れてた)

コマンドで取得する(テストなどの秒間隔での取得)

ざっくりいうと、meminfoをawkCSV形式に整形してログファイルに追加でリダイレクトするコマンドを、wlile分で無限ループさせているだけ。終了する場合は、CTRL+Cで強制終了させる。

LANG=C;( awk 'BEGIN{ printf "\"DATE\",\"TIME\""} {printf ",\"%s(%s)\"",$1,$3} END{printf "\n"}' /proc/meminfo > meminfo.csv ); while true;do ( awk 'BEGIN{ printf strftime("%Y/%m/%d, %H:%M:%S") } {printf ",%d",$2} END{printf "\n"}' /proc/meminfo >> meminfo.csv );sleep 1; done

これを動かすと、こんな結果が取得される。

"DATE","TIME","MemTotal:(kB)","MemFree:(kB)","Buffers:(kB)","Cached:(kB)","SwapCached:(kB)","Active:(kB)","Inactive:(kB)","Active(anon):(kB)","Inactive(anon):(kB)","Active(file):(kB)","Inactive(file):(kB)","Unevictable:(kB)","Mlocked:(kB)","SwapTotal:(kB)","SwapFree:(kB)","Dirty:(kB)","Writeback:(kB)","AnonPages:(kB)","Mapped:(kB)","Shmem:(kB)","Slab:(kB)","SReclaimable:(kB)","SUnreclaim:(kB)","KernelStack:(kB)","PageTables:(kB)","NFS_Unstable:(kB)","Bounce:(kB)","WritebackTmp:(kB)","CommitLimit:(kB)","Committed_AS:(kB)","VmallocTotal:(kB)","VmallocUsed:(kB)","VmallocChunk:(kB)","HardwareCorrupted:(kB)","AnonHugePages:(kB)","HugePages_Total:()","HugePages_Free:()","HugePages_Rsvd:()","HugePages_Surp:()","Hugepagesize:(kB)","DirectMap4k:(kB)","DirectMap2M:(kB)"
2013/03/03, 23:58:48,2054984,1161012,99012,605416,0,282204,439192,17128,8,265076,439184,0,0,4128760,4128760,8,0,16960,15536,172,132568,77788,54780,808,4056,0,0,0,5156252,140192,34359738367,274388,34359451196,0,0,0,0,0,0,2048,8192,2088960
2013/03/03, 23:58:49,2054984,1160996,99012,605412,0,282176,439192,17104,8,265072,439184,0,0,4128760,4128760,8,0,16976,15576,172,132580,77792,54788,816,4036,0,0,0,5156252,140192,34359738367,274388,34359451196,0,0,0,0,0,0,2048,8192,2088960
2013/03/03, 23:58:50,2054984,1160996,99020,605412,0,282176,439200,17104,8,265072,439192,0,0,4128760,4128760,20,0,16976,15576,172,132580,77792,54788,816,4036,0,0,0,5156252,140192,34359738367,274388,34359451196,0,0,0,0,0,0,2048,8192,2088960
2013/03/03, 23:58:51,2054984,1160996,99020,605412,0,282216,439200,17144,8,265072,439192,0,0,4128760,4128760,20,0,16972,15576,172,132580,77792,54788,816,4036,0,0,0,5156252,140192,34359738367,274388,34359451196,0,0,0,0,0,0,2048,8192,2088960

cronで取得する(日/週/月単位のトレンド取得)

長期のトレンドを見たい場合は、cronで分以上の間隔で取得するのが良い。

取得用のシェル

  • /usr/lib64/sa/meminfo.sh
#!/bin/bash
LANG=C
PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:
export LANG PATH
umask 022

LOGFILE_BASE="/var/log/sa/meminfo"
LOGFILE="${LOGFILE_BASE}.`date +%Y%m%d`"

# Write header, if LOGFILE does not exist.
if [ ! -f ${LOGFILE} ]; then
    awk '
        BEGIN{
            printf "\"DATE\",\"TIME\""
        }
        {
            printf ",\"%s(%s)\"",$1,$3
        }
        END{
            printf "\n"
        }' /proc/meminfo > ${LOGFILE}

    fi

# Write data
awk '
        BEGIN{
            printf strftime("%Y/%M/%d, %H:%M:%S")
        }
        {
            printf ",%d",$2
        }
        END{
            printf "\n"
        }' /proc/meminfo >> ${LOGFILE}

exit 0

シェルをキックするcron設定

1分間隔で取得する。

  • /etc/cron.d/meminfo
# Get meminfo.
* * * * * root /usr/lib64/sa/meminfo  > /dev/null 2>&1

ログのローテーションは。。。別に考えよう(^^;

シェル用のメッセージロギングツール

シェルのメッセージを一元的に出力する自作のツールです。
職場で使われているロギングツールがシンプルで使いやすいので、同じようなものを自作したものです。

ツールはgithubで公開しています。

configureの作り方(autotoolsの使い方)

はじめに

オープンソースでよくある、configure → make → make installというセットアップの流れ。これはGNUのautotoolsというツール&フレームワーク群により実現されている。
本記事ではそのautotoolsによりconfigureを作成する手順を説明する。

作成の流れ

  1. 必要ファイルの作成(automake時に必要)
  2. Makefile.am作成(後の作成/修正も可)
  3. autoscanコマンドの実行
  4. configure.acファイルの作成&編集
  5. aclocal実行
  6. autoheader実行
  7. automake実行
  8. autoconf実行

ユーザが編集するファイルは、configure.acとMakefile.am。これらファイルを修正した時は、aclocalコマンド以降を都度実行してファイルを再生性する。なので、aclocalコマンド以降をシェル化して一気に実行するようにしておくと便利である。

f:id:nopipi:20130109013829p:plain

手順詳細

必要ファイルの作成

automakeコマンド実行時に求められるファイルを作成する。とりあえずファイルがあればよいので、空ファイルを作成する。(内容は必要に応じ別途修正する)

$ touch INSTALL NEWS README LICENSE AUTHORS ChangeLog

Makefile.am作成(後の作成/修正も可)

次のautoscanコマンドで、AC_CONFIG_FILESを自動生成するため、とりあえずMakefile.amを作成する。とりあえずこの段階では空ファイルでもかまわない。(automake実行時に中身があればOK)

 -> Makefile.amのつくり方(別途作成予定)

autoscanコマンドの実行

configure.scanを作成し、それをRenameしてconfigure.acを作成する。

$ autoscan
$ mv configure.scan configure.ac

configure.acファイルの作成&編集

configure.acを修正する。詳細は別途作成

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

sAC_PREREQ([2.63])
AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS]) <== パッケージ&バージョン&連絡先を記入
AC_CONFIG_SRCDIR([src/uplog_util.c])
AC_CONFIG_HEADERS([config.h])

# Checks for programs.
AC_PROG_CC

# Checks for libraries.

# Checks for header files.
AC_CHECK_HEADERS([fcntl.h limits.h locale.h stdlib.h string.h sys/socket.h syslog.h unistd.h])

# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_PID_T

# Checks for library functions.
AC_FUNC_FORK
AC_FUNC_MALLOC
AC_FUNC_STRNLEN
AC_CHECK_FUNCS([dup2 getcwd gethostname gettimeofday memset realpath select setlocale socket strerror])

AC_CONFIG_FILES([Makefile
                 conf/Makefile
                 src/Makefile]) <==Makefile.amを増やしたらここに追加
AC_OUTPUT

aclocal実行以降

以後はシェル化し、Makefile.amやconfigure.ac修正時に都度実行すると楽。

echo aclocal
aclocal
echo autoheader
autoheader
echo automake
automake --add-missing --copy
echo autoconf
autoconf

ESXi TeraTermマクロ自動化

本当はvSphere CLIをインストールして利用すればよいのだが、VMのPowerOnとハイパーバイザのシャットダウンだけで十分だったので、TeraTermのマクロで自動化。

前提

ESXiは、SSH 鍵認証でログインできること。
SSH設定詳細はこちら→ESXi5 SSH 有効化&鍵認証(TeraTermの自動ログインマクロ付) - のぴぴのメモ

ESXi Hypervisorシャットダウン

コマンド"vim-cmd hostsvc/standby_mode_enter'"で停止。

; ==========================================================
; Setting (IP, UserName, KEY file)
HOSTADDR = 'xxx.xxx.xxx.xx'       ;ESXiのIPアドレス
USERNAME = 'root'
KEY_FILE = 'xxxxxxxxxxxxxxxxxxxx' ;ログインに使用する秘密鍵
CNF_FILE = 'xxxxxxxxxxxxxxxxxxxx' ;TeraTermの設定ファイル
; ==========================================================


;; Generate login command
COMMAND = HOSTADDR
strconcat COMMAND ':22 /ssh /2 /auth=publickey /user='
strconcat COMMAND USERNAME
strconcat COMMAND ' /keyfile="'
strconcat COMMAND KEY_FILE
strconcat COMMAND '" /F="'
strconcat COMMAND CNF_FILE
strconcat COMMAND '"'

;; Login
connect COMMAND
wait '~ #'

;; shutdown hypervisor
sendln 'vim-cmd hostsvc/standby_mode_enter'
sendln 'exit'

end

VM PowerON

  1. "vim-cmd vmsvc/getallvms"コマンドで、VM一覧を取得
  2. 取得したVM一覧よりリストを生成、起動したいVMの番号をインプットボックスより入力
  3. "vim-cmd vmsvc/power.getstate vim"で、各VMのPower状態を取得
  4. "vim-cmd vmsvc/power.on VMID"コマンドでVMを起動
; ==========================================================
; Setting (IP, UserName, KEY file)
HOSTADDR = 'xxx.xxx.xxx.xx'       ;ESXiのIPアドレス
USERNAME = 'root'
KEY_FILE = 'xxxxxxxxxxxxxxxxxxxx' ;ログインに使用する秘密鍵
CNF_FILE = 'xxxxxxxxxxxxxxxxxxxx' ;TeraTermの設定ファイル
; ==========================================================
;; Initialize
NUM=256
strdim VM_NO   NUM
strdim VM_NAME NUM
strdim VM_STAT NUM

timeout=1


;; Generate login command
COMMAND = HOSTADDR
strconcat COMMAND ':22 /ssh /2 /auth=publickey /user='
strconcat COMMAND USERNAME
strconcat COMMAND ' /keyfile="'
strconcat COMMAND KEY_FILE
strconcat COMMAND '" /F="'
strconcat COMMAND CNF_FILE
strconcat COMMAND '"'

;; Login
connect COMMAND
wait '~ #'


;;PowerOn VM
count = 0
result = 1
sendln 'vim-cmd vmsvc/getallvms'
waitln 'Vmid'
while result
    ; receive VM list
    recvln
    if result = 0 then
        goto getall_fail
    endif
    strmatch inputstr '~ #'
    if result <> 0 then
        goto getall_fail
    endif
    
    ; Split
    strreplace inputstr 1 '\s+' ' '
    strsplit inputstr " "
    VM_NO[count]   = groupmatchstr1
    VM_NAME[count] = groupmatchstr2
    
    count = count + 1
    goto getall_end
    :getall_fail
    result = 0
    
    :getall_end
endwhile

; Get VM power status
for i 0 count-1
    ; get VM stat
    MSG = 'vim-cmd vmsvc/power.getstate '
    strconcat MSG VM_NO[i]
    sendln MSG
    waitln 'Retrieved'
    
    recvln
    strsplit inputstr " "
    VM_STAT[i] = groupmatchstr2
next


;;Select VM
MSG="Select VM Number\n-----------------------------\n"
for i 0 count-1
    int2str stri  i
    strconcat MSG stri
    strconcat MSG '.\t'
    strconcat MSG VM_STAT[i]
    strconcat MSG '\t'
    strconcat MSG VM_NAME[i]
    strconcat MSG '\n'
next
strconcat MSG '\n\n-1\tCancel\n-----------------------------'

:select_RETRY
inputbox MSG 'select VM' 1
str2int vmnum inputstr
if result = 0 then
    goto select_RETRY
endif
if vmnum < 0 then
    goto EXIT_MACRO
endif


; PowerON VM
COMMAND= 'vim-cmd vmsvc/power.on '
strconcat COMMAND VM_NO[vmnum]
sendln COMMAND
wait '~ #'

;;exit
:EXIT_MACRO

sendln 'exit'
end

VM PowerOFF

  1. "vim-cmd vmsvc/getallvms"コマンドで、VM一覧を取得
  2. 取得したVM一覧よりリストを生成、起動したいVMの番号をインプットボックスより入力
  3. "vim-cmd vmsvc/power.getstate vim"で、各VMのPower状態を取得
  4. "vim-cmd vmsvc/power.off VMID"コマンドでVMを停止
; ==========================================================
; Setting (IP, UserName, KEY file)
HOSTADDR = 'xxx.xxx.xxx.xx'       ;ESXiのIPアドレス
USERNAME = 'root'
KEY_FILE = 'xxxxxxxxxxxxxxxxxxxx' ;ログインに使用する秘密鍵
CNF_FILE = 'xxxxxxxxxxxxxxxxxxxx' ;TeraTermの設定ファイル
; ===========================================================
;; Initialize
NUM=256
strdim VM_NO   NUM
strdim VM_NAME NUM
strdim VM_STAT NUM

timeout=1


;; Generate login command
COMMAND = HOSTADDR
strconcat COMMAND ':22 /ssh /2 /auth=publickey /user='
strconcat COMMAND USERNAME
strconcat COMMAND ' /keyfile="'
strconcat COMMAND KEY_FILE
strconcat COMMAND '" /F="'
strconcat COMMAND CNF_FILE
strconcat COMMAND '"'

;; Login
connect COMMAND
wait '~ #'


;;PowerOn VM
count = 0
result = 1
sendln 'vim-cmd vmsvc/getallvms'
waitln 'Vmid'
while result
    ; receive VM list
    recvln
    if result = 0 then
        goto getall_fail
    endif
    strmatch inputstr '~ #'
    if result <> 0 then
        goto getall_fail
    endif
    
    ; Split
    strreplace inputstr 1 '\s+' ' '
    strsplit inputstr " "
    VM_NO[count]   = groupmatchstr1
    VM_NAME[count] = groupmatchstr2
    
    count = count + 1
    goto getall_end
    :getall_fail
    result = 0
    
    :getall_end
endwhile

; Get VM power status
for i 0 count-1
    ; get VM stat
    MSG = 'vim-cmd vmsvc/power.getstate '
    strconcat MSG VM_NO[i]
    sendln MSG
    waitln 'Retrieved'
    
    recvln
    strsplit inputstr " "
    VM_STAT[i] = groupmatchstr2
next

;;Select VM
MSG="Select VM Number\n-----------------------------\n"
for i 0 count-1
    int2str stri  i
    strconcat MSG stri
    strconcat MSG '.\t'
    strconcat MSG VM_STAT[i]
    strconcat MSG '\t'
    strconcat MSG VM_NAME[i]
    strconcat MSG '\n'
next
strconcat MSG '\n\n-1\tCancel\n-----------------------------'

:select_RETRY
inputbox MSG 'select VM' 1
str2int vmnum inputstr
if result = 0 then
    goto select_RETRY
endif
if vmnum < 0 then
    goto EXIT_MACRO
endif


; PowerON VM
COMMAND= 'vim-cmd vmsvc/power.off '
strconcat COMMAND VM_NO[vmnum]
sendln COMMAND
wait '~ #'

;;exit
:EXIT_MACRO

sendln 'exit'
end

ESXi5 SSH 有効化&鍵認証(TeraTermの自動ログインマクロ付)

VMware ESXi5をSSHでリモートで操作したい場合の設定手順を記録する。

1.ESXのSSHサービスを有効にする

SSHのサービス有効化は、コンソール画面とvSphereClientの2通りのがあるらしい。
ここではコンソール画面からの変更を記載する。

  • "F2"キーを押し、コンソールにログインする
  • "Trubleshooting Options"を選択する
  • "Enable SSH"を選択し「リターン」キーを押す

これでSSHが有効化される。

ちなみにコンソール画面から直接操作するには、ひとつ上の項目"Enable ESXi shell"を有効化する。ついでに、コンソールシェル(ESXi shell)も有効化する。(必須ではない)

  • "Trubleshooting Options" -> "Enable ESXi shell"でシェルを有効かする。
  • ESXi shellを有効化したあと"ALT+F1"キーを押すとシェル画面に切り替わる
  • 元の画面(System Coustomization)に戻るには、"ALT+F2"キーを押す

2.TeraTermからパスワード認証ログインを確認

TeraTermからSSHのパスワード認証でログイン可能なことを確認する。ここで中が必要なのは、ESXi5では「チャレンジレスポンス認証」を利用しているらしく、TeraTermSSH認証で「チャレンジレスポンス認証を使う(キーボードインタラクティブ)」を選択する必要があることである。(下図参照)
f:id:nopipi:20121117215649p:plain

3.鍵の設定

SSHでとりあえずログインできることを確認したら、ESXiにログインに利用する公開鍵を登録する。

  • TeraTermで鍵を作成する(詳細はググルこと)
    • 「設定(S)」->「SSH鍵生成(N)」を選択
    • 鍵の種類を「RSA」にして「生成(G)」ボタンで鍵を生成
    • 公開鍵&秘密鍵を保存する
  • ESXiにパスワード認証でログインする

~ # cd /etc/ssh/keys-root
/etc/ssh/keys-root #
  • TeraTermで作成した公開鍵をエディタで開きファイル内の文字列をauthorized_keysに貼り付ける
/etc/ssh/keys-root # cat > authorized_keys
<<公開鍵のテキストカット&ペーストする>>
"CTL+D"を押すと入力終了する
/etc/ssh/keys-root #
  • TeraTermから鍵認証でログインできることを確認する
  • TeraTermからESXiにSSH接続
  • SSH認証画面で「RSA/DSA鍵を使う」を選択し、秘密鍵のファイルを指定

f:id:nopipi:20121117220601p:plain

4.TeraTerm鍵認証による自動ログインマクロ

参考までに、SSH鍵認証の場合の自動ログインマクロを公開。

; ==========================================================
; Setting (IP, UserName, KEY file)
HOSTADDR = 'xxx.xxx.xxx.xx'       ;ESXiのIPアドレス
USERNAME = 'root'
KEY_FILE = 'xxxxxxxxxxxxxxxxxxxx' ;ログインに使用する秘密鍵
CNF_FILE = 'xxxxxxxxxxxxxxxxxxxx' ;TeraTermの設定ファイル
; ==========================================================


;; Generate login command
COMMAND = HOSTADDR
strconcat COMMAND ':22 /ssh /2 /auth=publickey /user='
strconcat COMMAND USERNAME
strconcat COMMAND ' /keyfile="'
strconcat COMMAND KEY_FILE
strconcat COMMAND '" /F="'
strconcat COMMAND CNF_FILE
strconcat COMMAND '"'

;; Login
connect COMMAND
wait '~ #'

end

ダイレクトIOの実装

ファイルシステム上のファイルにキャッシュを解さずread/writeするためには、DirectIOで操作する必要がある。DirectIOを操作するには、

  1. ファイルをオープンする時に、O_DIRECTオプションを付与する
  2. read/writeで操作する際のバッファは、512KB(Linux kernel2.6以降)でアライメントする(したがって、バッファ意はposix_memalignで確保する。mallocや配列で確保するとread()/write()時に、EINVALエラーとなる)
  3. コンパイル時に"_GNU_SOURCE"オプションを付与する。

サンプルコードは以下の通り。

#include <unistd.h>
#include <fcntl.h>


#define BLOCKSIZE 512


int main(void)
{
        int  fdi, fdo;
        int  size = 100 * 1024 * 1024; /* 100MB */
        char *buf;

        /* allocate buffer memory */
        posix_memalign( (void **)&buf, BLOCKSIZE, size);

        /* open file */
        fdi = open("file_in", O_RDONLY                |O_DIRECT );
        fdo = open("file_out",O_WRONLY|O_CREAT|O_TRUNC|O_DIRECT,
                                S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP );

        /* copy "fdi" file to "fdo" file. */
        read(fdi, buf, size);
        write(fdo,buf, size);

}

コンパイルコマンド

$ gcc -D_GNU_SOURCE -o directio directio.c

テスト

$ dd if=/dev/zero of=file_in bs=1024 count=102400
102400+0 records in
102400+0 records out
104857600 bytes (105 MB) copied, 1.31783 s, 79.6 MB/s
$ ./directio

straceコマンドでシステムとレースしてみても

$ strace ./directio
   <中略>
open("file_in", O_RDONLY|O_DIRECT)      = 3
open("file_out", O_WRONLY|O_CREAT|O_TRUNC|O_DIRECT, 0660) = 4
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 104857600) = 104857600
write(4, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 104857600) = 104857600
exit_group(104857600)                   = ?
$

デーモンは2度forkするのが作法らしい

デーモンプロセス起動時の作法

デーモンを起動する場合、2度forkするのが作法らしく、これは「セッションリーダにならないようにすることで端末の制御を誤ってしないように」ということらしい。

詳しくはこちらを参照

そうなのかぁと思いながら、見よう見まねでdaemonの関数を作ってみました。

サンプルプログラム

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

static pid_t do_daemon(int close_interface)
{

        pid_t ret;
        int   fd;

        /*create child process and terminate parent process*/
        ret = fork();
        if( ret < 0 ){
                /* fork error */
                perror("Cannot fork");
                return(-1);
        }else if( ret != 0 ){
                /* parent process */
                return(ret);

        }
        /* child process */

        /* change chiled process to session gruop reader */
        ret = setsid();
        if( ret < 0 ){
                perror("Cannot create a session");
                return(-1);
        }

        /* create 2nd child process and terminate parent process again
         * to never connect terminal
         */
        ret = fork();
        if( ret < 0 ){
                /* fork error */
                perror("Cannot fork");
                return(-1);
        }else if( ret != 0 ){
                /* parent process */
                return(ret);
        }

        /* change the current directory to root directory */
        (void) chdir("/");

        /* close stdin/stdout/stderr */
        fd = open("/dev/null", O_RDWR);
        if( fd < 0 ){
                perror("Cannot open NULL device");
                return(-1);
        }

        /* close the STDIN file descriptor */
        if ((fd != STDIN_FILENO) && (dup2(fd, STDIN_FILENO) < 0)){
                perror("Cannot close the STDIN");
                (void)close(fd);
                return(-1);
        }

        /* close the STDOUT and STDERR file descriptor, if option is TRUE */
        if( close_interface ){
                /* close the STDOUT file descriptor */
                if ((fd != STDOUT_FILENO) && (dup2(fd, STDOUT_FILENO) < 0)) {
                        perror("Cannot close the STDOUT");
                        (void)close(fd);
                        return(-1);
                }

                /* close the STDERR file descriptor */
                if ((fd != STDERR_FILENO) && (dup2(fd, STDERR_FILENO) < 0)) {
                        perror("Cannot close the STDERR");
                        (void)close(fd);
                        return(-1);
                }
        }

        if( fd > STDERR_FILENO ){
                (void)close(fd);
        }

        /* daemon complete */
        return(0);

}

でもudevとかsyslogdとかのソースを見ると、案外fork一度しかやってなかったりするんだけどね。

はてな記法

Hatenaで記事を書く上で、やっぱり「はてな記方法」を知らないと綺麗な記事はかけないですね。
ということで、「はてな記法」のリファレンス

【RHEL6】yumでRHEL6のDVDからrpmパッケージをインストールする方法

1.RHELメディアのマウント

今回の例では、/mntにDVDをマウントする。

mount -t iso9660 -o ro /dev/cdrom /mnt

2.yumレポジトリの設定

/etc/yum.repos.d/に、xxx.repoというファイルを作る。(xxxは任意)
/etc/yum.repos.d/mnt_rhel60.repo

[rhel60_dvd]                ※1
name=RHEL6.0(x86_64) DVD    ※2
baseurl=file:///mnt/Server/
enabled=1           ※3
gpgcheck=1           ※4
gpgkey=file:///mnt/RPM-GPG-KEY-redhat-release ※5

※1 : レポジトリ名(わかりやすい名前をつける)
※2 : ラベル名(わかりやすい名前をつける)
※3 : 常に参照する場合は1。0の場合、yumオプションで"--enablerepo="を指定する。
※4 : GPG認証チェックを有効化する
※5 : GPG-KEYのファイルパスを指定

3.RHN接続の無効化(任意)

必須ではないが、RHNの接続エラーが毎回出るので抑止する。(enabled=0とする)

/etc/yum/pluginconf.d/rhnplugin.conf
[main]
#enabled = 1
enabled = 0
gpgcheck = 1

4.確認

yumコマンドで、DVDのパッケージが認識できるか確認。

# yum list
Loaded plugins: refresh-packagekit
Installed Packages
   <中略>
cdparanoia.x86_64     10.2-5.1.el6      rhel60_dvd
cdparanoia-libs.i686  10.2-5.1.el6      rhel60_dvd
cdrdao.x86_64         1.2.3-4.el6       rhel60_dvd
celt051.x86_64        0.5.1.3-0.el6     rhel60_dvd
check.i686            0.9.8-1.1.el6     rhel60_dvd
    <中略>

※指定したレポジトリ名のパッケージが表示されることを確認。

【RHEL6】ipv6無効化

ipv6の無効化方法について説明。

1.設定

/etc/modprobe.d/にdisable_ipv6.confというファイル設定ファイルを作成する。
(ファイル名は任意の名前で可)
/etc/modprobe.d/disable_ipv6.conf

options ipv6 disable=1

2.IPv6向けiptableサービスの無効化

(1)ip6tablesサービスの停止

# service ip6tables stop
ip6tables: モジュールを取り外し中:              [  OK  ]

(2)ip6tablesサービスの自動起動抑止

# chkconfig ip6tables off
# chkconfig --list|grep ip6tables

3.ネットワークの再起動

ネットワークを再起動する。

# service network restart

(面倒であればOSの再起動でもいいんでは)

4.確認

(1)dmesg設定

dmesgに下記メッセージがあることを確認。

IPv6: Loaded, but administratively disabled, reboot required to enable

※(意訳)モジュールをロードしたけど、管理上機能が無効化されてるよ

(b)ifconfigでipv6アドレスがないことを確認

 ifconfigにてIPv6の情報が表示されていないことを確認する。

-IPv6が有効な場合
$ ifconfig
eth0 Link encap:Ethernet HWaddr XX:XX:XX:XX:XX:XX
inet addr:192.168.1.10 Bcast:192.168.0.255 Mask:255.255.255.0
inet6 addr: fe80::240:63ff:feea:7bed/64 Scope:Link
<以下略>
-IPv6が無効な場合
$ ifconfig
eth0 Link encap:Ethernet HWaddr XX:XX:XX:XX:XX:XX
inet addr:192.168.1.10 Bcast:192.168.0.255 Mask:255.255.255.0
<以下略>

以上

【参考】

 一般的な方法として、modprobe.confに「alias net-pf-10 off」と設定する方法があちらこちらで紹介されている。しかいこの設定は、「off」という存在しないモジュールをロードさせようとすることで(当然失敗する)、結果としてipv6のモジュールをロードさせないようにしている。
 おそらく、disableオプションが実装される前の苦肉の策の設定ではないだろうか。