ONC+ Developer's Guide

Directory Listing Program and Support Routines (rpcgen)


Example D–1 rpcgen Program: dir.x

/*
 * 	dir.x: Remote directory listing
 *	protocol
 *
 *	This source module is a rpcgen source module
 *	used to demonstrate the functions of the rpcgen
 *	tool.
 *
 *	It is compiled with the rpcgen -h -T switches to
 *	generate both the header (.h) file and the
 *	accompanying data structures.
 *
 */
const MAXNAMELEN = 255;	/*maxlengthofadirectoryentry*/

typedef string nametype<MAXNAMELEN>; /* directory entry */
typedef struct namenode *namelist;   /*linkinthelisting*/
/*
 * A node in the directory listing
 */
struct namenode {
 	nametype name;       /* name of directory entry */
 	namelist next;       /* next entry */
 };

/*
 * The result of a READDIR operation:
 *	a truly portable application would use an agreed upon list of
 *	error codes rather than, as this sample program does, rely
upon
 *	passing UNIX errno's back. In this example the union is used
to
 *	 discriminate between successful and unsuccessful remote
calls.
 */
union readdir_res switch (int errno) {
	case 0:
		namelist list; /*no error: return directory listing*/
	default:
		void;      /*error occurred: nothing else to return*/
};

/*
 * The directory program definition
 */
program DIRPROG {
 	version DIRVERS {
 		readdir_res
 		READDIR(nametype) = 1;
 	} = 1;
 } = 0x20000076;


Example D–2 Remote dir_proc.c

/*
 * dir_proc.c: remote readdir implementation
 */
#include <rpc/rpc.h>      /* Always needed */
#include <dirent.h>
#include "dir.h"          /* Created by 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; /* must be static! */

	/*
	 * Open directory
	 */
	dirp = opendir(*dirname);
	if (dirp == (DIR *)NULL) {
 		res.errno = errno;
 		return (&res);
 	}
	/*
	 * Free previous result
	 */
	xdr_free(xdr_readdir_res, &res);
	/*
	 * Collect directory entries. Memory allocated here is freed
by
	 * xdr_free the next time readdir_1 is called.
	 */

 	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;
 	/* Return the result */
 	res.errno = 0;
 	closedir(dirp);
 	return (&res);
}


Example D–3 rls.c Client

/*
 * rls.c: Remote directory listing client
 */

#include <stdio.h>
#include <rpc/rpc.h>	/* always need this */
#include "dir.h"	    /* generated by 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];
/*
 * Create client "handle" used for calling MESSAGEPROG on the
server
 * designated on the command line.
 */
	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);
 	}

/* Okay, we successfully called the remote procedure. */

	if (result->errno != 0) {
	/*
	 * A remote system error occurred. Print error message and
die.
	 */
	}
	if (result->errno < sys_nerr)
 		fprintf (stderr, "%s : %s\n", dir,
 		sys_enlist[result->errno]);
 		errno = result->errno;
 		perror(dir);
 		exit(1);
 	}

/* Successfully got a directory listing. Print it out. */
	for(nl = result->readdir_res_u.list; nl != NULL; nl = nl-
>next) {
		printf("%s\n", nl->name);
	}
exit(0);