entry - みる会図書館


検索対象: UNIX MAGAZINE 2006年3月号
9件見つかりました。

1. UNIX MAGAZINE 2006年3月号

ロプログラミンク・テクニック 多治見寿和 newsysIog(5) 前回は、設疋ファイルの内容から処理対象のログファイ ルに関する部分を検出する get-worklist 関数を紹介しま した。この関数は、設定ファイルに記述された情報から、 処理対象となる可能性のあるファイルを抽出します。ただ し、実際に処理をおこなうかどうかは判断せず、判断 を示すェントリだけを取り出すものです。 今回は、取り出した情報をもとに処理すべきかどうかを 判断し、実際の処理もおこなう do-entry 関数をみていき ましよう。 d0 entry 関数 1 月号では、 main 関数をたんにローテートなどの処理 をおこなう関数として紹介しました。しかし実際には、処 理が必要かどうかを調べ、必要な場合にのみ処理を実行す る関数となっています。 do-entry 関数が引数として受け取るのは、 conf-entry 構造体へのポインタです。これはちょうど get-worklist 関数カす値と同じです。 get-worklist 関数は、処理が必 要なファイルに対応したエントリのリストを返します。 のエントリのリストは、 conf-entry 構造体を使って表現さ れています。 conf-entry 構造体には次の要素を指すため の next メンバーがあり、これをたどることで頂に次の要素 をたどっていけます。リストとして扱うには、 conf-entry 構造体へのポインタ型を操作することになります。 do-entry 関数はこのリストを引数にとっているように みえますが、実際には 1 つのエントリを処理するだけです。 たしかに conf-entry 構造体へのポインタはリストとして 扱えますが、たんなる構造体へのポインタとしての意味も UN 工 X MAGAZINE 2006.3 もちろんあります。 do-entry 関数は、引数を構造体への ポインタとして扱います。そのため、すべてのエントリを 処理するには、 do-entry 関数を呼び出す側でループを作る 必要があります。そこで、 main 関数では次のようなルー プ構造を作っていました。 while (p) { free—or-keep = do—entry(p) ; p = p->next ; if (free—or—keep = FREE_ENT ) free—entry(q) ; 変数 p には、 get-worklist 関数により返されたリスト が格納されています。これを引数として do-entry 関数を 呼び出せば、ちょうどリストの先頭要素を処理することに なるわけです。そこで、処理を終えたときに変数 p を次の 要素を指すように変更し、要素カっているあいだはルー プを続けるかたちになっています。 一方、関数の戻り値としては fk-entry 型の値を返しま す。この型は列挙型で、 FREE-ENT と KEEP-ENT の いずれかとなっています。工ントリの処理がすべて終って いればそのエントリは削除できるので、その場合は FREE- ENT を返します。しかし、ファイルの圧縮などの処理カ っていると、エントリを参照しなければならないため削除 できないケースがあります。このような場合には KEEP- ENT を返し、エントリを削除してはならないことを示し ます。 do-entry 関数内でおこなう処理は、エントリの解釈の 方法に依存します。 1 つのエントリには、この値を超える とローテーションを実行するサイズ、時間単位のローテー ション間隔が格納されています。これらの条件は、 1 つの 81

2. UNIX MAGAZINE 2006年3月号

工ントリで両方が指定されている場合もあります。その際 は、いずれかの条件が満たされたときにローテーションを 実行することになっています。逆にいうと、処理をおこな わないのはすべての条件が満たされないときです。これら に加えて、ローテーションを実行する時刻が格納されてい ることがあります。この場合には、ほかの条件を満たして いても、指定された時刻にならないと処理はおこなわれま せん。 処理をおこなわないことが分かれば、すぐに関数を終了 できます。この場合にはエントリを削除してかまわないの で、 FREE-ENT を返すことになります。逆に、処理しな ければならない場合には、 do-entry 関数という名前が示す とおり、実際にローテーション処理もおこないます。この とき、ファイルの圧縮処理カっていれば、エントリを残す 必要があるので KEEP-ENT を返し、圧縮しない場合に は FREE-ENT を返してエントリを削除してもらいます。 d0 ー entry 関数のソースコード 関数の動作が分かったところで、いつもどおりソースコ ードをみていきましよう。 do-entry 関数は、 newsyslog ・ c ファイルの 440 行目付近から始まっています。 局所的に利用するマクロ さきほど紹介したように、関数の戻り値は fk-entry 型 で、引数としては conf-entry 構造体へのポインタをとり ます。 static fk—entry do—entry (struct conf—entry * ent) 関数の開始直後には、次のようなマクロ定義があります。 ォルト値を設定するという方法もよく用いられます。この 場合には、最初の定義の部分をたとえは次のようにします。 #ifndef REASON_MAX # define REASON_MAX #endif / * REASON_MAX * / 80 #define REASON_MAX 80 このマクロは関数の内部でのみ使用するため、局所的な 疋義という意味も含め、ここで定義しています。局所的に 利用されるマクロなので、関数を抜けたあとは不要になり ます。そのため、関数の末尾で次のようにマクロの定義を 無効にしています。 #undef REASON_MAX このような局所的な定義では、あらかじめ値が定義され ているときにはそちらを使い、定義されていなければデフ 82 これは、 ifndef で REASON-MAX が定義されていな い場合を調べ、その場合にのみ値を定義するという方法で す。 C 言語のソースコードでは、インデントを使って入れ子 構造を表しますが、 ifdef などのプリプロセッサ命令で条 件判断をおこなう場合には、インデントが用いられること はあまりありません。これは、プリプロセッサ命令が、、行 頭から " 始まっていなければならないという決まりがある ためです。ただし、インデントがまったく使われないわけ ではありません。たしかに、プリプロセッサ命令は行頭に # 記号がなければなりませんが、上の例のように、その後 ろの部分には空白文字を含めることができます。 # の直後 に置く空白文字の数を調整すれば、インデントを入れるこ とが叮能なわけです。 さらに、上記の例では endif の行に、どの ifndef に対 応するものかが分かるようにコメントを付けています。 の例のような短いコードであればよけいに思えるかもしれ ませんが、長いコードを括っているときなどにはたいへん 肩効です。 C 言語の場合、通常は中括弧の対応を調べれば、 有効範囲がどこまでかはすぐに分かります。ェデイタにも それを調べる機能があるのが普通です。しかし、 ifdef など の有効範囲は簡単には分かりません。プログラムを読みや すくするためには、このような工夫も大切です。 do-entry 関数のソースコードでは、不要になったマク 口を無効にしていました。これと同じようなコードにした いと思うかもしれません。しかし、あらかじめ値が指定さ れていた場合には、無効にしてしまうと別の問題が生じる かもしれません。もともと定義がなかった場合にのみ無効 にできるというのか想でしよう。 これを実現するには、マクロを 1 つだけ使う方法では困 難です。というのも、マクロは実際の値を保持するために 使っていますが、そのほかに、あらかじめ値が指定されて いたかどうかの情報を保持する必要があるからです。これ は、もう 1 つ別のマクロを用いることで、たとえは次のよ うに簡単に実現できます。 UNIX MAGAZINE 2006 . 3

3. UNIX MAGAZINE 2006年3月号

図 4 system-call() はレジスタの内容をスタックに保存する EBX ECX EDX ESI EDI EBP EAX DS ES EAX EIP CS EFLAGS ESP SS syste m_call() int 0X80 CPU が割込みハンドラを呼び出すときには、いくつか のレジスタの内容をカーネルモード・スタックに待避させ ます ( 図 3 ) 。しかし、それ以外のレジスタに対しては何も おこないません。 CPU カ舸もしてくれないからといって、消えてよいわ けではありません。それらのレジスタの内容は、 int 命令を 実行する直前の状態を表すコンテキストの一部であり、ど こかに保存しておく必要があります。そして、カーネルか らユーザーモードに戻るときに、もとの状態に戻さなけれ ばなりません。 そこで system-call() は、最初にそれらのレジスタの内 容をスタックに待避させます。この段階でのスタックの様 子を図 4 に示します。 スタカ嶝場する理由はあとで説明します。ここでは、 EBP レジスタがプロセスの状態を管理する構造体を指すことだ げ億えておいてください。 230 行目ではプロセスのた態フラグを調べ、システムコ ールのトレースが指示されているかを判断します。もしフ ラグがセットされている場合は、 syscall_trace_entry() へ ジャンプします。 232 ~ 233 行目では、システムコール番号の有効性をチ ェックしています。 232 行目の nr_syscalls は、コンパイ ル時に、、 294 " に置き換えられます。この数字は、 Linux カ ーネルで定義されているシステムコール番号の上限を表し ます。 0235 : 0236 : 0237 : 0238 : 0241 : 0242 : 0243 : call *sys-call—table( , %eax, 4 ) movl %eax, 24(%esp) # 戻り値 syscall—exit : cli # 割込み禁止 movl TI-f1ags(%ebp) , %ecx testw $—TIF_ALLWORK_MASK , %cx Jne syscall—exit—work 0227 : 0230 : 0231 : 0232 : 0233 : movl $—THREAD_SIZE, %ebp andl %esp , %ebp testw $ 0X181 , TI_f1ags(%ebp) Jnz syscall—trace_entry cmpl $(nr—syscalls) , %eax J ae syscall-badsys 227 行目では、カレントプロセスのプロセス・デスクリプ タへのポインタを EBP に設疋します。 90 こで ESP レジ 235 行目の sys-call-table は、各システムコールのサ ービスルーチンのアドレスが本内されているテープルです。 このテープルも entry. S て疋義されています。 IA-32 のイ反想アドレスの大きさは 4 バイトなので、シス テムコール番号 (EAX レジスタの内容 ) を 4 倍した値を インデックスとし、 sys-call-table から取り出したアドレ スを呼び出します。 システムコールを実装するサービスルーチンは、 EAX レ ジスタに戻り値を格納して戻ると決まっているので、この 値をスタック上に保存されたレジスタ値 ( 図 4 ) に上書き します。 ESP の内容に 24 バイト加えたところは、 226 行目で EAX の内容を待避させた位置を指しています。そして、 の値はユーザーモードへ戻るときに 256 行目の pop 命令 によって EAX にロードされます。 241 ~ 243 行目では、プロセス・デスクリプタを調べ、 以下の状態を表すフラグのどれかがセットされていれば、 syscall-exit-work() へジャンプします。 再スケジュールを促す。 ・システムコールをトレースする。 保留中のシグナルがある。 UNIX MAGAZINE 2006 . 3

4. UNIX MAGAZINE 2006年3月号

特集 V Linux のプロセス [ 3 ] 図 3 害盻入みとスタックのえ ユーザーモード スタック 図 2 カーネルモードに入るためのゲート スタックが伸びる方向 カーネルモード スタック スタックポインタ→ - EIP が CS 自 割込み発生 動 ・←前のスタック EFLAGS 的 ポインタ ESP 待 SS さ せ る ユーザー プロセス カーネル ユーザー プロセス TSS espO ss0 ・割込みゲート ・タスクゲート ット値を CS および EIP レジスタにロードする ( 特権 Linux カーネルでは、トラップゲートを用いてシステム レベルが移行する ) 。 コールを実装しています。そして、トラップゲートには、 Linux カーネルでは、べクタ 0X80 のゲート・デスクリ 特権レベルを上げる際におこなうチェックのパラメータや、 プタには system-call() のアドレスが設疋されています。 実行ポインタのアドレス ( ェントリポイント ) などがカー このため、 int 0X80 を実行した CPU は、 system-call() ネルによって登録されています。 から実行を開始します。 int 命令によるべクタ 0X80 のソフトウェア割込みが発 見慣れない言葉がたくさん出てきて面喰らったかもしれ 生すると、 CPU は次の順でトラップゲートの処理をおこ ませんが、こでのポイントは、スタックポインタか哽新さ ないます れることと、 system-call() カ剛乎び出されることです。 1. IDT (lnterrupt Descriptor TabIe : 割込みデスクリ の 2 点を頭に入れておきましよう。 プタ・テープル ) から、 0X80 に対応するゲート・デス system-call( ) クリプタを読み取る。 2. ゲート・デスクリプタからセグメント・セレクタを読み system-call() は、すべてのシステムコールのエントリ 取る。 ポイントとなるサプルーチンです。そのコードは、以下の 3. GDT (Global Descriptor Table : グローバルデスク ように arch/i386/kernel/entry. S で疋義されています。 リプタ・テープル ) から、セグメント・セレクタに対応 ENTRY(system-ca11) 0224 : するセグメント・デスクリプタを読み取る。 %eax # システムコール番号を保存 0225 : pushl 4. セグメント・デスクリプタの権限をチェックする。 0226 : cld pushl %es 5. ゲート・デスクリプタの権限をチェックする。 %ds pushl %eax pushl 6. 特権レベルを移行させるため、 TSS の SS と ESP フィ pushl %ebp ールドが指すスタックへ SS と ESP レジスタの内容を pushl %edi pushl ブッシュする。その後、 TSS の SS と ESP フィールド pushl %edx の内容を SS と ESP レジスタにロードする ( 図 3 ) 。 pushl pushl %ebx 7. EFLAGS 、 CS 、 EIP の各レジスタの値をスタックにプ %edx movl $ (——USER-DS) , ッシュする。 movl %edx , %ds movl %edx , %es 8. ゲート・デスクリプタのセグメント・セレクタとオフセ 89 UNIX MAGAZINE 2006 . 3

5. UNIX MAGAZINE 2006年3月号

Mar. 2006 2006 年 3 月 1 日発行 ( 毎月 1 回 1 日発行 ) 第 21 巻第 3 号通巻 233 号昭和 63 年 9 月 5 日第三種郵便物認可 ユニックス・マガジン 仮想ストレージとしての ファイルシステム 一理想的なファイルシステム ・ストレージのモデル化 ・ファイルシステムの構造 ・ VFS の多層構造化 三二・ラ。 」のン幻ョ」じリっ住引せも プゴセ芳の第匕了 天文学とリ N Ⅸ M 円プログラミングの基礎 国立天文台のネットワーク ネットワーク回線の変更 プログラミング・テクニック newsyslog—do_entry 関数 リ N Ⅸ便利鮎 M00 引 e の活用法 し inux のツールたち Mandriva Linux 2006 文房具としてのリ N Ⅸ プライベート認証局の構築

6. UNIX MAGAZINE 2006年3月号

} else if (ent—>hours く = (ent->flags & CE-TRIMAT) ) { ent—>rotate ァイルがみあたらない (modtime が負の ) 場合にはロー 指定された時間以上使っているか、もしくは以前のログフ 時間間隔が指定されている場合、現在のログファイルを ローテーションの実行 ent—>rotate (modtime くの ) ) { ( (modtime > = ent—>hours) Ⅱ } else if ((ent—>hours > 0 ) & & - テーションをおこないます。 ーションをおこなうかどうかが設疋されているため、その に到達するまでに、エントリの rotate フィールドにローテ 最後は実際にローテーションをおこなう処理です。 if (temp—reason[O] ! = if (ent—>rotate) { 値を確認してローテーションを実施します。 86 れらの処理の関係でエントリを削除できなくなることがあ ルを圧縮する準備を整えます。最初に紹介したように、 なったり、必要であればシグナルを送る準備やログファイ この関数のなかで、ログファイルのバックアップをおこ free—or—keep = do—rotate(ent) ; お任せです。 実際のローテーション処理は、 do_rotate 関数にすべて を出力するようにしています。 ョンが指定されている場合には、どんな処理をおこなうか 設疋されていなくても、実際の処理は実行しない一 n オプシ 力するのはこれまでと同様です。さらに、 verbose 変数が 続いて、 verbose 変数の値にもとづいてメッセージを出 必要があるのです。 り当てる前に、文字列を十帑内するのに必要なサイズを知る ントリ用として使う領域を最小限に抑えるため、領域を割 にコピーするのは二度手間にみえるかもしれませんが、工 son という一時変数に設疋してから r-reason フィールド の r-reason フィールドにコヒーしています。 temp-rea- まず、ローテーションする理由を示す文字列を、エントリ temp—reason) ; ent—>r_reason strdup ( 疇 - るため、削除してよいかどうかを戻り値として返すので、そ れをそのまま do-entry 関数の戻り値として使います。 ローテーションをおこなわない場合には、 verbose 変数 の値にもとづいて、このログファイルを無視する旨を出力 します。 } else { if (verbose) printf ( ”ーー > , skipping\n" ) ; return (free—or—keep) , 最後に、 free-or-keep 変数の値を戻り値として関数を終 了します。 今月は、前回とりあげた、処理対象となるログファイル に関するエントリのリストを取り出す get-worklist 関数 に続き、実際にローテーションをおこなうかどうかを判断 する do-entry 関数を紹介しました。関数の内容としては 判断をおこなうだけですが、内部で do-rotate 関数を呼び 出すことにより、関数の終了時にはローテーション処理も 実行されます。 ローテーションをおこなうかどうかは時刻と時間間隔と サイズの 3 つの条件により判断しますが、時刻がもっとも 優先順位カ皜く、これカ甘旨定されていると、ほかの条件を 満たしていても、時刻の条件が満たされないかぎり口一テ ーションは実行されないようになっています。この優先順 位の関係を文章だけで説明するのはなかなか骨の折れる作 業ですが、今回はソースコードをみながら順に追っていっ たので、どういう条件のときにローテーションがおこなわ れるかがよく分かったのではないでしようか。 ( たじみ・ひさかず ) ☆ UNIX MAGAZINE 2006 . 3

7. UNIX MAGAZINE 2006年3月号

く、 pt-regs 構造体 ( 図 5 ) の大きさである 60 バイトを引 くことになります。 456 行目の childregs は、カーネルモード・スタックの 底にびったり合わせて pt-regs 構造体のデータを書き込め るアドレスを指します。そして、 467 行目では、 childregs から 8 バイトを引いたアドレスを設定しなおします。つま り、図 7 に示したように 8 バイトの余白を作ります。この 余白はあまり重要ではないので、気にしないで読み進めま しよう。 469 行目では、システムコールからユーザーモードへ戻 るとき、 EAX レジスタにロードされる値を 0 に設定して います。 fork や clone システムコールを発行した場合、子 プロセス側の戻り値が 0 になるのはこの値が返ってくるか らです。 470 行目では、子プロセスカ吏用するユーザーモード・ スタックのアドレスを設疋しています。 0129 : 0130 : andl %esp , %ebp popl %eax Jmp syscall—exit 0472 : 0473 : 0474 : 0475 : 0515 : 0521 : 0522. p—>thread. esp childregs ; p—>thread. espO = childregs + 1 ; p—>thread. eip = ret—from—fork; return err ; 472 行目と 475 行目では、前回説明した switch-to() により ESP と EIP レジスタにロードされる初期値を言定 しています。このため、スケジューラによって子プロセス が選択されると、子プロセスの第一歩は ret-from-fork() から始まります。 同様に 473 行目では、 --switch-to() によって TSS の espO にロードされるアドレスを設疋しています。 ret-from fork() ret-from-fork() は、新たに生成されたプロセスカ働き 出す直前に最後の仕上げをおこなうサプルーチンです。 コードは、 arch/i386/kernel/entry. S で次のように定 義されています。 0125 : 0126 : 0127 : 0128 : 98 ENTRY (ret_from-fork) pushl %eax ca11 schedule_tail movl $—THREAD_SIZE , %ebp 前回、説明したように、スケジューラカ噺しく生成さ れた子プロセスを選択すると、プロセスを切り替えるため に context-switch() を呼び出します。そして、 context- switch() は、スタックに ret-from-fork() のアドレスを ブッシュしてから --switch-to() へジャンプします。最後 に、 --switch-to() が ret 命令を実行すると、スタックか ら ret-from-fork() のアドレスが EIP レジスタにロード されます。ここまでが、プロセスを切り替えるための処理 です。 --switch-to() では、 prev プロセスへのポインタを戻り 値として返します。その戻り値は、 EAX レジスタに帑内 されています。 126 行目では、 schedule-tail() に渡す引数 (prev プ ロセスへのポインタ ) をスタックにブッシュしています (schedule-tail() については彳します ) 。 128 行目では、カレントプロセスのプロセス・デスクリ プタへのポインタを EBP に設定します。 129 行目では、 126 行目で移動させたスタックポインタ の位置をもとに戻しています。 130 行目からジャンプしている syscaILexit() では、さ きほど述べた、カーネルモード・スタックに待避されたレ ジスタをロードしてユーザーモードへ戻る処理をおこない ます。 文字の説明だけでは分かりにくいかもしれないので、親 プロセスと子プロセスの処理の流れを図 8 に示しました。 親プロセスは int 0X80 を実行するとカーネルモードへ 移行し、 system-call() へジャンプします。このとき、 部のレジスタの内容は自動的に、残りのレジスタは sys- tem-call() によってカーネルモード・スタックに待避され ます。システムコールのサービスルーチンを呼び出したあ とで、カーネルモード・スタックからレジスタの内容を口 ードし、さらに iret 命令カラ長りのレジスタをロードして、 ューザーモードへ戻ります。このとき、制御は int 命令の 次の命令へジャンプします。 一方、子プロセスのほうは、スケジューラに選択される までランキューのなかで待ちます。その後、スケジューラ UN 工 X MAGAZINE 2006 . 3

8. UNIX MAGAZINE 2006年3月号

UNiKNF ( 0 n t e n t s 2 0 0 6 / 0 3 [ 特集 ] 26 仮想ストレージとしての ファイルシステム 奥山健一 長い歴史をもちながら軽視されている仮想化技術が、ファイルシステム である。ストレージを仮想化する技術としての機能に焦点を絞り、詳細に 解説。ストレージのモデル化をおこない、理想的なファイルシステムの 構造について考えていく。 し inux のプロセス 白崎博生 今回はまず、プロセスとスレッド、タスクの概念、システムコールの働き について説明する。続いて、し inux カーネル 2.6.13 のソースコードに 沿って、プロセスを生成する fo 「 k システムコール、終了させる exit シス テムコールにおける処理を解説する。 87 連載 UNIX Communication Notes ・・・・・・山口英 情報資産の運用管理 ネットワーク・ミニ実験室・・・・・・荒井美千子 BIND9 の Dynamic Update 国立天文台のネットワーク・・・・・・大江将史 ネットワーク回線の変更 文房具としての UN Ⅸ・・・・・・宮地利幸、森島直人 プライベート認証局ーールート証明書の発行 天文学と UN Ⅸ・・・・・台坂博 M 円プログラミングの基礎 プログラミング・テクニック・・・・・・多治見寿和 newsyslog の d0 entry 関数 Pe 活用のヒント 今津英世 RSS ファイルの生成 COVER, CONTENTS DESIGN, ILLUSTRATION ・ MORIYA, KAZUO (AUDREY THE DESIGN)

9. UNIX MAGAZINE 2006年3月号

プログラミング・テクニック・ 図 1 free-or-keep のネ殞用ヒとメッセージの出力 free—or—keep = FREE—ENT ; if (verbose) { if (ent->flags & CE-COMPACT) printf ("%s く %dZ> : else if (ent->flags & CE—BZCOMPACT) printf ("%s く %dJ>: else printf ("%s く %d> : #ifdef REASON_MAX # define REASON_MAX_LOCAL REASON_MAX #else / * REASON—MAX * / # define REASON_MAX_LOCAL 80 #endif / * REASON-MAX * / ent—>log, ent->log, ent—>log, ent—>numlogs) ; ent—>numlogs) ; ent—>numlogs) ; こでは、最後にマクロを無効にするという考え方を 変え、ユーザーが定義する可能性のあるマクロの値は勝手 に定義しないという方針にしています。上のコードであれ ば、この部分を通過しても REASON-MAX マクロの状態 は変わらないため、別の部分に悪影響を与えることはあり ません。ただし、プログラム中で REASON-MAX-LO- CAL というマクロカ吏われていないことを確認し、 REA- SON-MAX カ吏用されている部分を REASON-MAX- LOCAL に変更するという手間はかかります。 do-entry 関数のソースコードに戻りましよう。続いて、 関数の戻り値として用いる free-or-keep を初期化してい ます。さらに、 verbose カ痕の場合には、実行する処理に 関するメッセージを出力しています ( 図 1 ) 。 出力するメッセージは、ローテートしたファイルを圧縮 modtime = age—old—log(ent->log) ; ent—>fsize sizefile(ent—>log) ; sizefile 関数と age-old-log 関数を利用しています。 次は、ログファイルに関する情報の取得です。これには、 ファイルの作成 する方法によって異なります。 に面倒です。ログファイルの最終更新時刻を調べても、最 ローテートした時刻を返します。この値を調べるのは意外 age-old 」 og 関数は、指定されたログファイルを最後に ない場合には、一 1 を返します。 ファイルのサイズとなります。指定されたログファイルが グファイル名を渡すので、こで返される値は現在のログ ロバイト単位で返します。引数として現在注目しているロ sizefile 関数は、引数で指定されたファイルの大きさをキ UNIX MAGAZ 工 NE 2006.3 後に更新された、つまり最後にログが追加された時刻を取 得することになります。ファイルの作成時刻なら正しい情 報が得られると考えるかもしれませんが、ローテーション を実施した時点で新しいログファイルを作成しているとは かぎりません。この段階ではファイルを作らず、あとでロ グを書き出す必要が生じたときに作成している可能性もあ ります。 age-old-log 関数では、ローテーションした旧いログが 格納されているファイルの最終更新時刻を、最後にローテ ートした時刻としています。これを調べるために、ログフ ァイル名の後ろに、、 .0 " カ咐いたファイルや、圧縮した際の 拡張子の付いたファイルを検索し、その最終更新時刻を取 得しています。戻り値としては、時刻そのものを返すので はなく、現在時刻との差、つまり現在のログファイルがど のくらいの期間存在しているかを表す値を 1 時間単位で返 します。 これらの値を取得したあと、エントリの rotate と first- rotate メンバーを 0 に初期化し、さきほと陬得したログフ ァイルのサイズを表す fsize の値を調べます。 ent—>rotate ent—>firstcreate if (ent->fsize く 0 ) { この値が負の数となるのは、ログファイルがないときで す。この場合には、オプションやフラグの値にもとづいて ファイルを作成しなければなりません。 この処理では、ファイルを作成しなかった場合にその理 由をメッセージとして出力します。そこでまず、そのメッ セージをイ尉寺づ - る temp-reason 配列を空文字列にします。 temp—reason [ 0 ] newsyslog コマンドの一 C オプションは、拓疋された回 数によって未カ畯わります。 1 回の場合、設疋ファイルで C フラグが指定されているログファイルがファイルシステ 83