ディレクトリリストプログラムとその補助ルーチン (rpcgen)
例 D–1 rpcgen プログラム: dir.x
/*
* dir.x: リモートディレクトリリストのプロトコル
* このソースモジュールは rpcgen ツールの機能を説明するために使用する
* rpcgen ソースモジュールです。ヘッダーファイル (.h) と
* 付属するデータ構造体の両方を生成するため、
* rpcgen -h -T スイッチを付けてコンパイルします。
*/
const MAXNAMELEN = 255; /*ディレクトリエントリの長さの最大値*/
typedef string nametype<MAXNAMELEN>; /* ディレクトリエントリ */
typedef struct namenode *namelist; /*リスト内のリンク*/
/*
* ディレクトリリスト内のノード
*/
struct namenode {
nametype name; /* ディレクトリエントリの名前 */
namelist next; /* 次のエントリ */
};
/*
* READDIR 操作の戻り値:
* 真に移植性の高いアプリケーションでは、
* このサンプルプログラムのように UNIX の
* errno を返す方法に頼るのではなく、決められたエラーコードの
* リストを使用する。
* この例では、成功したリモート呼び出しと
* 失敗したリモート呼び出しを区別するために共用体が使用されている。
*/
union readdir_res switch (int errno) {
case 0:
namelist list; /*エラーなし: ディレクトリリストを返す*/
default:
void; /*エラー発生: 他には何も返さない*/
};
/*
* ディレクトリプログラムの定義
*/
program DIRPROG {
version DIRVERS {
readdir_res
READDIR(nametype) = 1;
} = 1;
} = 0x20000076;
例 D–2 リモート dir_proc.c
/*
* dir_proc.c: リモート readdir の実装
*/
#include <rpc/rpc.h> /* 必ず必要 */
#include <dirent.h>
#include "dir.h" /* rpcgen が作成 */
extern int errno;
extern char *malloc();
extern char *strdup();
/* ARGSUSED1*/
readdir_res *
readdir_1(dirname,req)
nametype *dirname;
struct svc_req *req;
{
DIR *dirp;
struct dirent *d;
namelist nl;
namelist *nlp;
static readdir_res res; /* 必ず static で宣言 */
/*
* ディレクトリのオープン
*/
dirp = opendir(*dirname);
if (dirp == (DIR *)NULL) {
res.errno = errno;
return (&res);
}
/*
* 以前の戻り値を解放
*/
xdr_free(xdr_readdir_res, &res);
/*
* ディレクトリエントリを収集する。ここで割り当てられたメモリーは、
* 次に readdir_1 が呼び出されたときに xdr_free によって解放されます。
*/
nlp = &res.readdir_res_u.list;
while (d = readdir(dirp)) {
nl = *nlp = (namenode *) malloc(sizeof(namenode));
if (nl == (namenode *) NULL) {
res.errno = EAGAIN;
closedir(dirp);
return(&res);
}
nl->name = strdup(d->d_name);
nlp = &nl->next;
}
*nlp = (namelist)NULL;
/* 戻り値を返す */
res.errno = 0;
closedir(dirp);
return (&res);
}
例 D–3 rls.c クライアント
/*
* rls.c: リモートディレクトリリストクライアント
*/
#include <stdio.h>
#include <rpc/rpc.h> /* 必ず必要 */
#include "dir.h" /* rpcgen が生成 */
extern int errno;
main(argc, argv)
int argc;
char *argv[];
{
CLIENT *cl;
char *server;
char *dir;
readdir_res *result;
namelist nl;
if (argc != 3) {
fprintf(stderr, "usage: %s host directory\n",
argv[0]);
exit(1);
}
server = argv[1];
dir = argv[2];
/*
* コマンド行で指定したサーバー上の MESSAGEPROG を呼び出す際に使用する
* クライアント「ハンドル」を作成。
*/
cl = clnt_create(server, DIRPROG, DIRVERS, "visible");
if (cl == (CLIENT *)NULL) {
clnt_pcreateerror(server);
exit(1);
}
result = readdir_1(&dir, cl);
if (result == (readdir_res *)NULL) {
clnt_perror(cl, server);
exit(1);
}
/* リモートプロシージャの呼び出しに成功 */
if (result->errno != 0) {
/*
* リモートシステムのエラーが発生。エラーメッセージを出力し、終了
*/
}
if (result->errno < sys_nerr)
fprintf (stderr, "%s : %s\n", dir,
sys_enlist[result->errno]);
errno = result->errno;
perror(dir);
exit(1);
}
/* ディレクトリリストの取得に成功。リストを出力 */
for(nl = result->readdir_res_u.list; nl != NULL; nl = nl-
>next) {
printf("%s\n", nl->name);
}
exit(0);