次のコーディング例は、SAC からのメッセージに応答するだけの NULL ポートモニターです。
# 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); }
次のコーディング例は sac.h ヘッダーファイルを示します。
/* utmpx ID のバイト長 */ # define IDLEN 4 /* utmpx ID で使用できるワイルド文字 */ # define SC_WILDC 0xff /* ポートモニターのタグの最大バイト長 */ # define PMTAGSIZE 14 /* * doconfig() の rflag 値 */ /* assign を許可しない */ # define NOASSIGN 0x1 /* run または runwait を許可しない */ # define NORUN 0x2 /* * SAC へのメッセージ (ヘッダーのみ) このヘッダーは常に固定。 * size フィールド (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 の errno 値。pmadm と sacadm の両方が Saferrno を使用し、 * これらの値はこの両者で共有される点に注意してください。 */ # 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 /* 修復中 */