次のコーディング例は、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 /* 修復中 */