ONC+ 開発ガイド

NIS+ サンプルプログラム

サンプルプログラムでは次のタスクを実行します。

サンプルプログラムは典型的なアプリケーションとはいえません。通常は、ディレクトリとテーブルの作成と削除はコマンド行インタフェースで行い、アプリケーションでは NIS+ エントリオブジェクトの操作だけを行います。

サポートされないマクロの使用

サンプルプログラムでは <rpcsvc/nis.h> ファイルで定義されているマクロを使用しています。ここで定義されているマクロは、サポートが保証されている正式な API ではなく、将来変更されたりなくなったりする可能性があります。ここではサンプルプログラムで使用方法を説明するために使用していますが、実際のプログラムで使用するときはユーザー自身の責任で使用してください。サンプルプログラムで使用しているマクロを次に示します。

サンプルプログラムで使用する関数

サンプルプログラムでは、次の NIS+ API 関数を C 言語で使用する方法を示します。

プログラムのコンパイル

このアプリケーションを動作させる NIS+ 主体はローカルドメイン内にディレクトリオブジェクトの作成権を持ちます。次のように入力してプログラムを編集します。


% cc -o example.c example -lnsl

次のように入力して呼び出します。


% example [dir]

ここで、dir には NIS+ ディレクトリを指定します。サンプルプログラムは、すべての NIS+ オブジェクトをそのディレクトリに作成します。引数 dir を指定しないと、ローカルドメインの親ディレクトリにオブジェクトが作成されます。nis_lookup() の呼び出しでは、ディレクトリを指定する文字列に空白とローカルドメイン名が追加されることに注意してください。引数で指定するのは、作成した NIS+ オブジェクトを入れるための NIS+ ディレクトリ名です。このプログラムを実行する主体は、そのディレクトリ内でのオブジェクト作成権を持っている必要があります。

次のサンプルコードは、ディレクトリオブジェクトを作成するため main() が呼び出すルーチンを示しています。


例 9–1 ディレクトリオブジェクトを作成する NIS+ ルーチン

void
dir_create (dir_name, dirobj)
	nis_name			dir_name;
	nis_object			*dirobj;
{
	nis_result 	*cres;
	nis_error			err;

	printf ("\n Adding Directory %s to namespace ... \n",
dir_name);
	cres = nis_add (dir_name, dirobj);

	if (cres->status != NIS_SUCCESS) {
		nis_perror (cres->status, "unable to add directory foo.");
		exit (1);
	}

	(void) nis_freeresult (cres);

	/*
	 * 注: nis_mkdir を実行して、作成するディレクトリの内容を保存する
	 * テーブルを作成する必要がある。
	 */
	err = nis_mkdir (dir_name,

						dirobj->DI_data.do_servers.do_servers_val);
	if (err != NIS_SUCCESS) {
		(void) nis_remove (dir_name, 0);

		nis_perror (err,
				"unable to create table for  directory object foo.");
		exit (1);
	}
}

次のルーチンは main() から呼び出され、グループオブジェクトを作成します。nis_creategroup() はグループオブジェクトだけを対象としているので、グループ名には groups_dir というリテラルは必要ありません。


例 9–2 グループオブジェクトを作成する NIS+ ルーチン

void
grp_create (grp_name)
	nis_name			grp_name;
{
	nis_error			err;

	printf ("\n Adding %s group to namespace ... \n", grp_name);
	err = nis_creategroup (grp_name, 0);
	if (err != NIS_SUCCESS) {
		nis_perror (err, "unable to create group.");
		exit (1);
	}
}

main () は次の例に示すルーチンを呼び出し、テーブルオブジェクトを次の表のようなレイアウトで作成します。

表 9–3 NIS+ テーブルオブジェクト

 

カラム 1 

カラム 2 

名前 

id 

name 

属性 

検索可能、テキスト 

検索可能、テキスト 

アクセス権 

----rmcdr---r---

----rmcdr---r---

定数 TA_SEARCHABLE を指定すると、サービスでカラムが検索可能となります。TEXT カラム (デフォルト属性) だけが検索可能です。TA_CASE を指定すると、サービスは、カラムの値を検索するときに大文字小文字を区別しません。


例 9–3 テーブルオブジェクトを作成する NIS+ ルーチン

#define			TABLE_MAXCOLS 2
#define			TABLE_COLSEP ':'
#define			TABLE_PATH 0

void
tbl_create (dirobj, table_name)
	nis_object 	*dirobj;		/* フィールドによっては必要 */
	nis_name			table_name;
{
	nis_result				*cres;
	static nis_object					tblobj;
	static table_col					tbl_cols[TABLE_MAXCOLS] = {
		{"Id", TA_SEARCHABLE | TA_CASE, DEFAULT_RIGHTS},
		{"Name", TA_SEARCHABLE | TA_CASE, DEFAULT_RIGHTS}
	};

	tblobj.zo_owner = dirobj->zo_owner;
	tblobj.zo_group = dirobj->zo_group;
	tblobj.zo_access = DEFAULT_RIGHTS;    /* nis.h で定義されたマクロ  */
	tblobj.zo_data.zo_type = TABLE_OBJ;   /* nis.h で定義された列挙型 */
	tblobj.TA_data.ta_type = TABLE_TYPE;
	tblobj.TA_data.ta_maxcol = TABLE_MAXCOLS;
	tblobj.TA_data.ta_sep = TABLE_COLSEP;
	tblobj.TA_data.ta_path = TABLE_PATH;
	tblobj.TA_data.ta_cols.ta_cols_len =
		tblobj.TA_data.ta_maxcol;				 /* 常にこの指定 */
	tblobj.TA_data.ta_cols.ta_cols_val = tbl_cols;

/*
 * 完全指定のテーブル名、すなわち、org_dir というリテラルが埋め込まれた
 * テーブル名を使用する。nis_add はあらゆるタイプの NIS+ オブジェクトを
 * 操作するからであり、テーブルが作成済みならばそのフルパス名も必要である。
 */
	printf ("\n Creating table %s ... \n", table_name);
	cres = nis_add (table_name, &tblobj);
	if (cres->status != NIS_SUCCESS) {
		nis_perror (cres->status, "unable to add table.");
		exit (1);
	}
	(void) nis_freeresult (cres);
}

main() は次の例のようなルーチンを呼び出し、テーブルオブジェクトへエントリオブジェクトを追加します。 2 つのエントリがテーブルオブジェクトに追加されます。どちらのエントリのカラム幅も、文字列のターミネータとしての NULL 文字を含む値で設定することに注意してください。


例 9–4 テーブルにオブジェクトを追加する NIS+ ルーチン

#define			MAXENTRIES 2
void
stuff_table(table_name)
	nis_name 	table_name;
{
	int			i;
	nis_object			entdata;
	nis_result			*cres;
	static entry_col ent_col_data[MAXENTRIES][TABLE_MAXCOLS] = {
			{0, 2, "1", 0, 5, "John"},
			{0, 2, "2", 0, 5, "Mary"}
	};

	printf ("\n Adding entries to table ... \n");

	/*
	 * テーブルに追加するエントリは、テーブルと同じ所有者、グループ所有者、
	 * アクセス権を持たなければならないので、はじめにテーブルオブジェクトを
	 * 調べる。
	 */
	cres = nis_lookup (table_name, 0);

	if (cres->status != NIS_SUCCESS) {
		nis_perror (cres->status, "Unable to lookup table");
		exit(1);
	}
	entdata.zo_owner = NIS_RES_OBJECT (cres)->zo_owner;
	entdata.zo_group = NIS_RES_OBJECT (cres)->zo_group;
	entdata.zo_access = NIS_RES_OBJECT (cres)->zo_access;
	
	/* cres を解放して再利用できるようにする。 */
	(void) nis_freeresult (cres);

	entdata.zo_data.zo_type = ENTRY_OBJ; /* nis.h で定義された列挙型 */
	entdata.EN_data.en_type = TABLE_TYPE;
	entdata.EN_data.en_cols.en_cols_len = TABLE_MAXCOLS;
	for (i = 0; i < MAXENTRIES; ++i) {
		entdata.EN_data.en_cols.en_cols_val = &ent_col_data[i][0];
		cres = nis_add_entry (table_name, &entdata, 0);

		if (cres->status != NIS_SUCCESS) {
			nis_perror (cres->status, "unable to add entry.");
			exit (1);
		}
		(void) nis_freeresult (cres);
	}
}

次の例に示すルーチンは nis_list() の呼び出しで使用する出力関数です。 list_objs()nis_list() を呼び出すときに、引数の 1 つとして print_info() へのポインタを渡します。サービスが print_info() を呼び出すたびに、エントリオブジェクトの内容が出力されます。戻り値は、ライブラリに対して、テーブルの次のエントリを呼び出すように指示します。


例 9–5 nis_list を呼び出す NIS+ ルーチン

int
print_info (name, entry, cbdata)
	nis_name			name;			/* 未使用 */
	nis_object			*entry;			/* NIS+ エントリオブジェクト */
	void			*cbdata;			/* 未使用 */
{
	static u_int				firsttime = 1;
	entry_col	*tmp;      /* ソースを読みやすくするためだけに使用 */
	u_int				i, terminal;

	if (firsttime) {
		printf ("\tId.\t\t\tName\n");
		printf ("\t---\t\t\t----\n");
		firsttime = 0;
	}
	for (i = 0; i < entry->EN_data.en_cols.en_cols_len; ++i) {
		tmp = &entry->EN_data.en_cols.en_cols_val[i];
		terminal = tmp->ec_value.ec_value_len;
		tmp->ec_value.ec_value_val[terminal] = '\0';
	}

	/*
	 * ENTRY_VAL は、指定したエントリの特定カラムの値を返すマクロ
	 */
	printf("\t%s\t\t\t%s\n", ENTRY_VAL (entry, 0),
								ENTRY_VAL (entry, 1));
	return (0); /* さらに呼出しを行う */
}

main () は次の例に示すルーチンを呼び出し、グループ、テーブル、ディレクトリオブジェクトの内容を一覧表示します。 次のルーチンで、コールバックの使用方法を示します。グループのメンバーを取り出して表示します。グループのメンバーリストは、オブジェクトの中に保存されていないので、nis_list() コールではなく、nis_lookup () で調べます。nis_lookup() は、グループだけでなくあらゆるタイプの NIS+ オブジェクトを扱うため、グループは groups_dir を付けた形式で指定しなければなりません。


例 9–6 オブジェクトを一覧表示する NIS+ ルーチン

void
list_objs(dir_name, table_name, grp_name)
         nis_name   dir_name, table_name, grp_name;
{
	group_obj	*tmp; /* ソースを読みやすくするためだけに使用 */
	u_int			i;
	char			grp_obj_name [NIS_MAXNAMELEN];
	nis_result			*cres;
	char			index_name [BUFFER_SIZE];

	sprintf (grp_obj_name, "%s.groups_dir.%s",
				nis_leaf_of (grp_name), nis_domain_of (grp_name));
	printf ("\nGroup %s membership is: \n", grp_name);

	cres = nis_lookup(grp_obj_name, 0);

	if (cres->status != NIS_SUCCESS) {
		nis_perror (cres->status, "Unable to lookup group object.");
		exit(1);
	}

	tmp = &(NIS_RES_OBJECT(cres)->GR_data);
	for (i = 0; i < tmp->gr_members.gr_members_len; ++i)
		printf ("\t %s\n", tmp->gr_members.gr_members_val[i]);
	(void) nis_freeresult (cres);

	/*
	 * ドメイン foo の内容を、コールバックを使用しないで表示する。
	 */
	printf ("\nContents of Directory %s are: \n", dir_name);
	cres = nis_list (dir_name, 0, 0, 0);
	if (cres->status != NIS_SUCCESS) {
		nis_perror (cres->status,
                                "Unable to list Contents of
Directory foo.");
		exit(1);
	}
	for (i = 0; i < NIS_RES_NUMOBJ(cres); ++i)
		printf("\t%s\n", NIS_RES_OBJECT(cres)[i].zo_name);
	(void) nis_freeresult (cres);

	/*
	 * 作成したテーブルの内容を、nis_list() でコールバックを使用してリスト
	 * する。
	 * of nis_list().
	 */
	printf ("\n Contents of Table %s are: \n", table_name);
	cres = nis_list (table_name, 0, print_info, 0);
	if(cres->status != NIS_CBRESULTS && cres->status !=
NIS_NOTFOUND){
		nis_perror (cres->status,
			"Listing entries using callback failed");
		exit(1);
	}
	(void) nis_freeresult (cres);

	/*

	 * 作成したテーブルの 1 エントリだけをリストする。
         * エントリの取り出しには、
	 * インデックスの付いた名前を使用する。
	 */

	printf("\n Entry corresponding to id 1 is:\n");
	/*
	 * 通常、カラム名はテーブルオブジェクトから抽出できるので、
	 * 始めにそれを取り出す。
	 */
	sprintf(index_name, "[Id=1],%s", table_name);
	cres = nis_list (index_name, 0, print_info, 0);
	if(cres->status != NIS_CBRESULTS && cres->status !=
NIS_NOTFOUND){
		nis_perror (cres->status,
		"Listing entry using indexed names and callback failed");
		exit(1);
	}
	(void) nis_freeresult (cres);
}

cleanup() は次の例に示すルーチンを呼び出し、名前空間からディレクトリオブジェクトを削除します。このルーチンはまた、このディレクトリを管理しているサーバーにも、名前空間から削除したことを通知します。ポインタ cres が指している戻り値の構造体が入ったメモリーは、戻り値が使用済みになってから解放しなければならないことに注意してください。


例 9–7 ディレクトリオブジェクトを削除する NIS+ ルーチン

void
dir_remove(dir_name, srv_list, numservers)
	nis_name			dir_name;
	nis_server			*srv_list;
	u_int			numservers;
{
	nis_result			*cres;
	nis_error			err;
	u_int			i;

	printf ("\nRemoving %s directory object from namespace ...
\n",
								dir_name);
	cres = nis_remove (dir_name, 0);
	if (cres->status != NIS_SUCCESS) {
		nis_perror (cres->status, "unable to remove directory");
		exit (1);
	}
	(void) nis_freeresult (cres);

	for (i = 0; i < numservers; ++i) {
		err = nis_rmdir (dir_name, &srv_list[i]);
		if (err != NIS_SUCCESS) {
			nis_perror (err,
			"unable to remove server from directory");
			exit (1);
		}
	}
}

main() が呼び出す次のルーチンは、このサンプルプログラムで作成したすべてのオブジェクトを削除します。nis_remove_entry() を呼び出すときのフラグ REM_MULTIPLE の使用法に注意してください。必ずテーブルからすべてのエントリを削除してから、テーブル自体を削除します。


例 9–8 オブジェクトをすべて削除する NIS+ ルーチン

void
cleanup(local_princip, grp_name, table_name, dir_name, dirobj)
	nis_name			local_princip, grp_name, table_name, dir_name;
	nis_object			*dirobj;
{
	char		grp_dir_name [NIS_MAXNAMELEN];
	char		org_dir_name [NIS_MAXNAMELEN];
	nis_error			err;
	nis_result			*cres;

	sprintf(grp_dir_name, "%s.%s", "groups_dir", dir_name);
	sprintf(org_dir_name, "%s.%s", "org_dir", dir_name);

	printf("\n\n\nStarting to Clean up ... \n");
	printf("\n\nRemoving principal %s from group %s \n",
						local_princip, grp_name);
	err = nis_removemember (local_princip, grp_name);

	if (err != NIS_SUCCESS) {
		nis_perror (err,
		"unable to delete local principal from group.");
		exit (1);
	}

	/*
	 * admins グループを削除する。グループ削除のAPI は、グループだけを
	 * 対象にしているので、グループ名にgroup_dir は不要。
	 * グループ名には、自動的にリテラルgroup_dir が埋め込まれる。
	 */
	printf("\nRemoving %s group from namespace ... \n",
grp_name);
	err = nis_destroygroup (grp_name);
	if (err != NIS_SUCCESS) {
		nis_perror (err, "unable to delete group.");
		exit (1);
	}


	printf("\n Deleting all entries from table %s ... \n",
table_name);

	cres = nis_remove_entry(table_name, 0, REM_MULTIPLE);
	switch (cres->status) {
		case NIS_SUCCESS:
		case NIS_NOTFOUND:
			break;
		default:
			nis_perror(cres->status, "Could not delete entries from
										table");
			exit(1);
	}
	(void) nis_freeresult (cres);

	printf("\n Deleting table %s itself ... \n", table_name);
	cres = nis_remove(table_name, 0);

	if (cres->status != NIS_SUCCESS) {
		nis_perror(cres->status, "Could not delete table.");
	exit(1);
	}
	(void) nis_freeresult (cres);

	/* groups_dir、org_dir、foo の各ディレクトリオブジェクトを削除する。
*/

	dir_remove (grp_dir_name,
						dirobj->DI_data.do_servers.do_servers_val,
						dirobj->DI_data.do_servers.do_servers_len);
	dir_remove (org_dir_name,
						dirobj->DI_data.do_servers.do_servers_val,
						dirobj->DI_data.do_servers.do_servers_len);
	dir_remove (dir_name, dirobj-
>DI_data.do_servers.do_servers_val,
						  dirobj->DI_data.do_servers.do_servers_len);
}

プログラムを実行すると、画面上に次のように表示されます。


例 9–9 NIS+ プログラムの実行

myhost% domainname  sun.com
 myhost% ./sample  
 Adding Directory foo.sun.com. to namespace ...
 Adding Directory groups_dir.foo.sun.com. to namespace ...
 Adding Directory org_dir.foo.sun.com. to namespace ...
 Adding admins.foo.sun.com. group to namespace ...
 Adding principal myhost.sun.com. to group admins.foo.sun.com. ...
 Creating table test_table.org_dir.foo.sun.com. ...
 Adding entries to table ...
 Group admins.foo.sun.com. membership is:
         myhost.sun.com.
 Contents of Directory foo.sun.com. are:
         groups_dir
         org_dir
 Contents of Table test_table.org_dir.foo.sun.com. are:
         Id.                     Name
         ---                     ----
         1                       John
         2                       Mary
 
Entry corresponding to id 1 is:
         1                       John
 
Starting to Clean up ...
 
Removing principal myhost.sun.com. from group admins.foo.sun.com.
Removing admins.foo.sun.com. group from namespace ...
Deleting all entries from table test_table.org_dir.foo.sun.com. ...
Deleting table test_table.org_dir.foo.sun.com. itself ...
Removing groups_dir.foo.sun.com. directory object from namespace ...
Removing org_dir.foo.sun.com. directory object from namespace ...
Removing foo.sun.com. directory object from namespace ...
myhost%

デバッグのために、次の一連のコマンドを入力して、これと同じ操作を実行することもできます。最初のコマンドはマスターサーバーの名前を表示します。

変数 master と表示されている部分には、マスターサーバー名を入力してください。

% niscat -o domainname .
% nismkdir -m master foo.`domainname`.
 
 # 指定されたマスターでサブディレクトリ org_dir.foo を作成します。
 % nismkdir -m master org_dir.foo.`domainname`.
 # 指定されたマスターでサブディレクトリ groups_dir.foo を作成します。
 % nismkdir -m master groups_dir.foo.`domainname`.
 # グループ admins を作成します。
 % nisgrpadm -c admins.foo.`domainname`.
 
 # 自分自身をこのグループのメンバーとして追加します。
 % nisgrpadm -a admins.foo.`domainname`. `nisdefaults -p`
 
 # Id と Name の 2 つのカラムで test_table を作成します。
 % nistbladm -c test_data id=SI Name=SI \
 test_table.org_dir.foo.`domainname`
 
 # そのテーブルにエントリを 1 つ追加します。
 % nistbladm -a id=1 Name=John test_table.org_dir.foo.`domainname`.
 # そのテーブルに別のエントリを追加します。
 % nistbladm -a id=2 Name=Mary test_table.org_dir.foo.`domainname`.
 
 # グループ admins のメンバーをリストする。
 % nisgrpadm -l admins.foo.`domainname`.
 # ディレクトリ foo の内容をリストする。 % nisls foo.`domainname`.
 # test_table の内容とヘッダーをリストする。
 % niscat -h test_table.org_dir.foo.`domainname`.
 
 # test_table から id が 1 のエントリを取り出す
 % nismatch id=1 test_table.org_dir.foo.`domainname`.
 
 # 作成したものをすべて削除する。
 # 初めに、グループ admins から自分自身を削除する。
 % nisgrpadm -r admins.foo.`domainname`. `nisdefaults -p`
 # グループ admins を削除する。
 % nisgrpadm -d admins.foo.`domainname`.
 # test_table からすべてのエントリを削除する。
 % nistbladm -r “[],test_table.org_dir.foo.`domainname`.”
 # test_table を削除する。
 % nistbladm -d test_table.org_dir.foo.`domainname`.
 # 作成した 3 つのディレクトリをすべて削除する。
 % nisrmdir groups_dir.foo.`domainname`.
 % nisrmdir org_dir.foo.`domainname`.
 % nisrmdir foo.`domainname`.