例 F-1 に示すのは、SAC からのメッセージに応答する以外は何もしないポートモニタのサンプルプログラムです。
# include <stdlib.h> # include <stdio.h> # include <unistd.h> # include <fcntl.h> # include <signal.h> # include <sac.h> char Scratch[BUFSIZ]; /* スクラッチバッファ */ char Tag[PMTAGSIZE + 1]; /* ポートモニタのタグ */ FILE *Fp; /* ログファイルへのファイルポインタ */ FILE *Tfp; /* pid ファイルへのファイルポインタ */ char State; /* ポートモニタの現在の状態 */ main(argc, argv) int argc; char *argv[]; { char *istate; strcpy(Tag, getenv("PMTAG")); /* * ポートモニタのプライベートディレクトリにログファイルをオープンします。 */ sprintf(Scratch, "/var/saf/%s/log", Tag); Fp = fopen(Scratch, "a+"); if (Fp == (FILE *)NULL) exit(1); log(Fp, "starting"); /* * 初期状態 (enabled または disabled) を取り出して、 * State をそれに合わせて設定します。 */ istate = getenv("ISTATE"); sprintf(Scratch, "ISTATE is %s", istate); log(Fp, Scratch); if (!strcmp(istate, "enabled")) State = PM_ENABLED; else if (!strcmp(istate, "disabled")) State = PM_DISABLED; else { log(Fp, "invalid initial state"); exit(1); } sprintf(Scratch, "PMTAG is %s", Tag); log(Fp, Scratch); /* * pid ファイルを設定してロックし、ポートモニタがアクティブなことを示します。 */ Tfp = fopen("_pid", "w"); if (Tfp == (FILE *)NULL) { log(Fp, "couldn't open pid file"); exit(1); } if (lockf(fileno(Tfp), F_TEST, 0) < 0) { log(Fp, "pid file already locked"); exit(1); } fprintf(Tfp, "%d", getpid()); fflush(Tfp); log(Fp, "locking file"); if (lockf(fileno(Tfp), F_LOCK, 0) < 0) { log(Fp, "lock failed"); exit(1); } /* * sac からのポーリングメッセージを処理します。...この関数は終了しません。 */ handlepoll(); pause(); fclose(Tfp); fclose(Fp); } handlepoll() { int pfd; /* 入力パイプのファイル記述子 */ int sfd; /* 出力パイプのファイル記述子 */ struct sacmsg sacmsg; /* 入力メッセージ */ struct pmmsg pmmsg; /* 出力メッセージ */ /* * sac からのメッセージを受信するためのパイプをオープンします。 */ pfd = open("_pmpipe", O_RDONLY|O_NONBLOCK); if (pfd < 0) { log(Fp, "_pmpipe open failed"); exit(1); } /* * sac へメッセージを送信するためのパイプをオープンします。 */ sfd = open("../_sacpipe", O_WRONLY); if (sfd < 0) { log(Fp, "_sacpipe open failed"); exit(1); } /* * 応答メッセージの構築を開始します。ここでは、クラス 1 のメッセージだけを * サポートします。 */ strcpy(pmmsg.pm_tag, Tag); pmmsg.pm_size = 0; pmmsg.pm_maxclass = 1; /* * sac からのメッセージへの応答を続けます。 */ for (;;) { if (read(pfd, &sacmsg, sizeof(sacmsg)) != sizeof(sacmsg)) { log(Fp, "_pmpipe read failed"); exit(1); } /* * メッセージのタイプを判定して、正しい応答を返します。 */ switch (sacmsg.sc_type) { case SC_STATUS: log(Fp, "Got SC_STATUS message"); pmmsg.pm_type = PM_STATUS; pmmsg.pm_state = State; break; case SC_ENABLE: /* 内部状態が変わっていることに注意 */ log(Fp, "Got SC_ENABLE message"); pmmsg.pm_type = PM_STATUS; State = PM_ENABLED; pmmsg.pm_state = State; break; case SC_DISABLE: /*内部状態が変わっていることに注意 */ log(Fp, "Got SC_DISABLE message"); pmmsg.pm_type = PM_STATUS; State = PM_DISABLED; pmmsg.pm_state = State; break; case SC_READDB: /* * 完全なポートモニタの場合は、ここで _pmtab を読み込んで * 必要なアクションを起こします。 */ log(Fp, "Got SC_READDB message"); pmmsg.pm_type = PM_STATUS; pmmsg.pm_state = State; break; default: sprintf(Scratch, "Got unknown message <%d>", sacmsg.sc_type); log(Fp, Scratch); pmmsg.pm_type = PM_UNKNOWN; pmmsg.pm_state = State; break; } /* * ポーリングに対する応答を返し、 * 現在の状態を知らせます。 */ if (write(sfd, &pmmsg, sizeof(pmmsg)) != sizeof(pmmsg)) log(Fp, "sanity response failed"); } } /* * 一般的なログ機能 */ log(fp, msg) FILE *fp; char *msg; { fprintf(fp, "%d; %s¥n", getpid(), msg); fflush(fp); } |
例 F-2 はヘッダーファイル sac.h を示しています。
/* utmpx id のバイト数 */ # define IDLEN 4 /* utmpx ids のワイルド文字 */ # define SC_WILDC 0xff /* ポートモニタタグの最大長 (バイト数) */ # define PMTAGSIZE 14 /* * doconfig() のための rflag 値 */ /* assign コマンドは許可しない */ # define NOASSIGN 0x1 /* run と runwait のコマンドは許可しない */ # define NORUN 0x2 /* * sac へのメッセージ (ヘッダーのみ)。このヘッダー形式はずっと固定されます。 * サイズフィールド (pm_size) には、ヘッダーに続くオプションデータ部のサイズを * 指定します。オプションデータ部の形式は、メッセージタイプ (pm_type) によって * 厳密に定義されます。 */ struct pmmsg { char pm_type; /* メッセージタイプ */ unchar pm_state; /* ポートモニタの現在の状態 */ char pm_maxclass; /* ポートモニタが理解できる最大の メッセージクラス */ char pm_tag[PMTAGSIZE + 1]; /* ポートモニタのタグ */ int pm_size; /* オプションデータ部のサイズ */ }; /* * pm_type の値 */ # define PM_STATUS 1 /* 応答ステータス */ # define PM_UNKNOWN 2 /* 未知のメッセージを受信しました */ /* * pm_state の値 */ /* * クラス 1 の応答 */ # define PM_STARTING 1 /* ポートモニタは起動状態 */ # define PM_ENABLED 2 /* ポートモニタは有効状態 */ # define PM_DISABLED 3 /* ポートモニタは無効状態 */ # define PM_STOPPING 4 /* ポートモニタは停止状態 */ /* * ポートモニタへのメッセージ */ struct sacmsg { int sc_size; /* オプションデータ部のサイズ */ char sc_type; /* メッセージタイプ */ }; /* * sc_type の値 * 次に定義するコマンドは SAC がポートモニタに送信するコマンドです。 * 拡張性を持たせるため、コマンドは各クラスに分類されます。 * 後に定義されるクラスは、それまでに定義されたクラスのコマンドに、 * そのクラスの新たなコマンドが追加されたスーパーセットです。 * どのクラスもヘッダーは同じです。新たなコマンドは、 * ヘッダーにオプションデータ部が追加される形で定義されます。 * オプションデータ部の形式は、コマンドで自動的に決まります。 * 重要な注: SAC から最初に送信されるメッセージは常にクラス 1 の * メッセージです。これに対して、ポートモニタは応答メッセージで * 自分が理解できる最大のクラスを知らせます。 * もう 1 つ注意しなければならないのは、ポートモニタは必ず * 受信したメッセージと同じクラスで応答しなければならないことです。 * (すなわち、クラス 1 のコマンドには必ずクラス 1 で応答します。) */ /* * クラス 1 のコマンド (現在は、クラス 1 のコマンドしかありません) */ # define SC_STATUS 1 /* ステータス要求 */ # define SC_ENABLE 2 /* 有効に設定 */ # define SC_DISABLE 3 /* 無効に設定 */ # define SC_READDB 4 /* pmtab の読み込みを要求 */ /* * Saferrno のエラー番号。Saferrno は pmadm と sacadm の両方で共有する * ことに注意してください。 */ # define E_BADARGS 1 /* 引数またはコマンド行が不正 */ # define E_NOPRIV 2 /* ユーザーは操作特権を持っていない */ # define E_SAFERR 3 /* 一般的な SAF エラー */ # define E_SYSERR 4 /* システムエラー */ # define E_NOEXIST 5 /* 指定が無効 */ # define E_DUP 6 /* エントリが既に存在している */ # define E_PMRUN 7 /* ポートモニタが実行中 */ # define E_PMNOTRUN 8 /* ポートモニタが実行されていない */ # define E_RECOVER 9 /* 修復中 */ |