v13i083: Sun RPC, release 3.9, Part06/15
Rich Salz
rsalz at bbn.com
Thu Mar 3 09:18:16 AEST 1988
Submitted-by: Stephen X. Nahm <sxn at Sun.COM>
Posting-number: Volume 13, Issue 83
Archive-name: rpc3.9/part06
#! /bin/sh
# This is a shell archive. To extract, remove the header and type "sh filename"
#
echo x - etc
echo creating directory etc
mkdir etc
cd etc
echo x - Makefile
cat > Makefile <<'Funky_Stuff'
#
# @(#)Makefile 1.5 87/11/20 3.9 RPCSRC
#
# Files and programs for /etc. rpclib must have already been installed.
#
DESTDIR=
CFLAGS= -O
LIB = -lrpclib
LDFLAGS= $(LIB)
BIN = portmap rpcinfo
MISC= rpc
all: ${BIN}
portmap:
${CC} ${CFLAGS} -o $@ $@.c ${LDFLAGS}
rpcinfo: getopt.o
${CC} ${CFLAGS} -o $@ $@.c getopt.o ${LDFLAGS}
install: ${BIN}
-mkdir ${DESTDIR}/etc && chown bin ${DESTDIR}/etc && \
chmod 755 ${DESTDIR}/etc
@echo "Installing RPC utility files in ${DESTDIR}/etc"
@set -x;for i in ${BIN}; do \
(install -s $$i ${DESTDIR}/etc/$$i); done
@echo "Installing ${DESTDIR}/etc/rpc"
@set -x;for i in ${MISC}; do \
(install -c -m 644 $$i ${DESTDIR}/etc/$$i); done
clean:
rm -f core *.o
rm -f ${BIN}
depend: ${BIN}
rm -f makedep
for i in ${BIN}; do \
${CC} -M ${INCPATH} $$i.c | sed 's/\.o//' | \
awk ' { if ($$1 != prev) { print rec; rec = $$0; prev = $$1; } \
else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \
else rec = rec " " $$2 } } \
END { print rec } ' >> makedep; done
echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep
echo '$$r makedep' >>eddep
echo 'w' >>eddep
cp Makefile Makefile.bak
ed - Makefile < eddep
rm eddep makedep
echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile
echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile
echo '# see make depend above' >> Makefile
depend.42BSD depend.42bsd:
cp /dev/null x.c
for i in $(BIN) ; do \
(/bin/grep '^#[ ]*include' x.c $$i.c | sed \
-e 's,<\(.*\)>,"/usr/include/\1",' \
-e 's/:[^"]*"\([^"]*\)".*/: \1/' \
-e 's/\.c/\.o/' >>makedep); done
echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep
echo '$$r makedep' >>eddep
echo 'w' >>eddep
cp Makefile Makefile.bak
ed - Makefile < eddep
rm eddep makedep x.c
echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile
echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile
echo '# see make depend above' >> Makefile
# DO NOT DELETE THIS LINE -- make depend uses it
Funky_Stuff
len=`wc -c < Makefile`
if [ $len != 2046 ] ; then
echo error: Makefile was $len bytes long, should have been 2046
fi
echo x - getopt.c
cat > getopt.c <<'Funky_Stuff'
/* @(#)getopt.c 1.2 87/11/30 3.9 RPCSRC */
/* this is a public domain version of getopt */
/*LINTLIBRARY*/
#ifndef NULL
#define NULL 0
#endif NULL
#ifndef EOF
#define EOF (-1)
#endif EOF
#define ERR(s, c) if(opterr){\
extern int strlen(), write();\
char errbuf[2];\
errbuf[0] = c; errbuf[1] = '\n';\
(void) write(2, argv[0], strlen(argv[0]));\
(void) write(2, s, strlen(s));\
(void) write(2, errbuf, 2);}
#define strchr index
extern int strcmp();
extern char *strchr();
int opterr = 1;
int optind = 1;
int optopt;
char *optarg;
int
getopt(argc, argv, opts)
int argc;
char **argv, *opts;
{
static int sp = 1;
register int c;
register char *cp;
if(sp == 1)
if(optind >= argc ||
argv[optind][0] != '-' || argv[optind][1] == '\0')
return(EOF);
else if(strcmp(argv[optind], "--") == NULL) {
optind++;
return(EOF);
}
optopt = c = argv[optind][sp];
if(c == ':' || (cp=strchr(opts, c)) == NULL) {
ERR(": unknown option, -", c);
if(argv[optind][++sp] == '\0') {
optind++;
sp = 1;
}
return('?');
}
if(*++cp == ':') {
if(argv[optind][sp+1] != '\0')
optarg = &argv[optind++][sp+1];
else if(++optind >= argc) {
ERR(": argument missing for -", c);
sp = 1;
return('?');
} else
optarg = argv[optind++];
sp = 1;
} else {
if(argv[optind][++sp] == '\0') {
sp = 1;
optind++;
}
optarg = NULL;
}
return(c);
}
Funky_Stuff
len=`wc -c < getopt.c`
if [ $len != 1381 ] ; then
echo error: getopt.c was $len bytes long, should have been 1381
fi
echo x - portmap.c
cat > portmap.c <<'Funky_Stuff'
/* @(#)portmap.c 1.1 87/11/04 3.9 RPCSRC */
#ifndef lint
static char sccsid[] = "@(#)portmap.c 1.32 87/08/06 Copyr 1984 Sun Micro";
#endif
/*
* Copyright (c) 1984 by Sun Microsystems, Inc.
*/
/*
* portmap.c, Implements the program,version to port number mapping for
* rpc.
*/
/*
* Sun RPC is a product of Sun Microsystems, Inc. and is provided for
* unrestricted use provided that this legend is included on all tape
* media and as a part of the software program in whole or part. Users
* may copy or modify Sun RPC without charge, but are not authorized
* to license or distribute it to anyone else except as part of a product or
* program developed by the user.
*
* SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
* WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
*
* Sun RPC is provided with no support and without any obligation on the
* part of Sun Microsystems, Inc. to assist in its use, correction,
* modification or enhancement.
*
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
* OR ANY PART THEREOF.
*
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
* or profits or other special, indirect and consequential damages, even if
* Sun has been advised of the possibility of such damages.
*
* Sun Microsystems, Inc.
* 2550 Garcia Avenue
* Mountain View, California 94043
*/
#include <rpc/rpc.h>
#include <rpc/pmap_prot.h>
#include <stdio.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
char *malloc();
int reg_service();
struct pmaplist *pmaplist;
static int debugging = 0;
main()
{
SVCXPRT *xprt;
int sock, pid, t;
struct sockaddr_in addr;
int len = sizeof(struct sockaddr_in);
register struct pmaplist *pml;
#ifndef DEBUG
pid = fork();
if (pid < 0) {
perror("portmap: fork");
exit(1);
}
if (pid != 0)
exit(0);
for (t = 0; t < 20; t++)
close(t);
open("/", 0);
dup2(0, 1);
dup2(0, 2);
t = open("/dev/tty", 2);
if (t >= 0) {
ioctl(t, TIOCNOTTY, (char *)0);
close(t);
}
#endif
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("portmap cannot create socket");
exit(1);
}
addr.sin_addr.s_addr = 0;
addr.sin_family = AF_INET;
addr.sin_port = htons(PMAPPORT);
if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
perror("portmap cannot bind");
exit(1);
}
if ((xprt = svcudp_create(sock)) == (SVCXPRT *)NULL) {
fprintf(stderr, "couldn't do udp_create\n");
exit(1);
}
/* make an entry for ourself */
pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist));
pml->pml_next = 0;
pml->pml_map.pm_prog = PMAPPROG;
pml->pml_map.pm_vers = PMAPVERS;
pml->pml_map.pm_prot = IPPROTO_UDP;
pml->pml_map.pm_port = PMAPPORT;
pmaplist = pml;
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
perror("portmap cannot create socket");
exit(1);
}
if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
perror("portmap cannot bind");
exit(1);
}
if ((xprt = svctcp_create(sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE))
== (SVCXPRT *)NULL) {
fprintf(stderr, "couldn't do tcp_create\n");
exit(1);
}
/* make an entry for ourself */
pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist));
pml->pml_map.pm_prog = PMAPPROG;
pml->pml_map.pm_vers = PMAPVERS;
pml->pml_map.pm_prot = IPPROTO_TCP;
pml->pml_map.pm_port = PMAPPORT;
pml->pml_next = pmaplist;
pmaplist = pml;
(void)svc_register(xprt, PMAPPROG, PMAPVERS, reg_service, FALSE);
svc_run();
fprintf(stderr, "run_svc returned unexpectedly\n");
abort();
}
static struct pmaplist *
find_service(prog, vers, prot)
u_long prog;
u_long vers;
{
register struct pmaplist *hit = NULL;
register struct pmaplist *pml;
for (pml = pmaplist; pml != NULL; pml = pml->pml_next) {
if ((pml->pml_map.pm_prog != prog) ||
(pml->pml_map.pm_prot != prot))
continue;
hit = pml;
if (pml->pml_map.pm_vers == vers)
break;
}
return (hit);
}
/*
* 1 OK, 0 not
*/
reg_service(rqstp, xprt)
struct svc_req *rqstp;
SVCXPRT *xprt;
{
struct pmap reg;
struct pmaplist *pml, *prevpml, *fnd;
int ans, port;
caddr_t t;
#ifdef DEBUG
fprintf(stderr, "server: about do a switch\n");
#endif
switch (rqstp->rq_proc) {
case PMAPPROC_NULL:
/*
* Null proc call
*/
if ((!svc_sendreply(xprt, xdr_void, NULL)) && debugging) {
abort();
}
break;
case PMAPPROC_SET:
/*
* Set a program,version to port mapping
*/
if (!svc_getargs(xprt, xdr_pmap, ®))
svcerr_decode(xprt);
else {
/*
* check to see if already used
* find_service returns a hit even if
* the versions don't match, so check for it
*/
fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot);
if (fnd && fnd->pml_map.pm_vers == reg.pm_vers) {
if (fnd->pml_map.pm_port == reg.pm_port) {
ans = 1;
goto done;
}
else {
ans = 0;
goto done;
}
} else {
/*
* add to END of list
*/
pml = (struct pmaplist *)
malloc((u_int)sizeof(struct pmaplist));
pml->pml_map = reg;
pml->pml_next = 0;
if (pmaplist == 0) {
pmaplist = pml;
} else {
for (fnd= pmaplist; fnd->pml_next != 0;
fnd = fnd->pml_next);
fnd->pml_next = pml;
}
ans = 1;
}
done:
if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) &&
debugging) {
fprintf(stderr, "svc_sendreply\n");
abort();
}
}
break;
case PMAPPROC_UNSET:
/*
* Remove a program,version to port mapping.
*/
if (!svc_getargs(xprt, xdr_pmap, ®))
svcerr_decode(xprt);
else {
ans = 0;
for (prevpml = NULL, pml = pmaplist; pml != NULL; ) {
if ((pml->pml_map.pm_prog != reg.pm_prog) ||
(pml->pml_map.pm_vers != reg.pm_vers)) {
/* both pml & prevpml move forwards */
prevpml = pml;
pml = pml->pml_next;
continue;
}
/* found it; pml moves forward, prevpml stays */
ans = 1;
t = (caddr_t)pml;
pml = pml->pml_next;
if (prevpml == NULL)
pmaplist = pml;
else
prevpml->pml_next = pml;
free(t);
}
if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) &&
debugging) {
fprintf(stderr, "svc_sendreply\n");
abort();
}
}
break;
case PMAPPROC_GETPORT:
/*
* Lookup the mapping for a program,version and return its port
*/
if (!svc_getargs(xprt, xdr_pmap, ®))
svcerr_decode(xprt);
else {
fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot);
if (fnd)
port = fnd->pml_map.pm_port;
else
port = 0;
if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&port)) &&
debugging) {
fprintf(stderr, "svc_sendreply\n");
abort();
}
}
break;
case PMAPPROC_DUMP:
/*
* Return the current set of mapped program,version
*/
if (!svc_getargs(xprt, xdr_void, NULL))
svcerr_decode(xprt);
else {
if ((!svc_sendreply(xprt, xdr_pmaplist,
(caddr_t)&pmaplist)) && debugging) {
fprintf(stderr, "svc_sendreply\n");
abort();
}
}
break;
case PMAPPROC_CALLIT:
/*
* Calls a procedure on the local machine. If the requested
* procedure is not registered this procedure does not return
* error information!!
* This procedure is only supported on rpc/udp and calls via
* rpc/udp. It passes null authentication parameters.
*/
callit(rqstp, xprt);
break;
default:
svcerr_noproc(xprt);
break;
}
}
/*
* Stuff for the rmtcall service
*/
#define ARGSIZE 9000
typedef struct encap_parms {
u_long arglen;
char *args;
};
static bool_t
xdr_encap_parms(xdrs, epp)
XDR *xdrs;
struct encap_parms *epp;
{
return (xdr_bytes(xdrs, &(epp->args), &(epp->arglen), ARGSIZE));
}
typedef struct rmtcallargs {
u_long rmt_prog;
u_long rmt_vers;
u_long rmt_port;
u_long rmt_proc;
struct encap_parms rmt_args;
};
static bool_t
xdr_rmtcall_args(xdrs, cap)
register XDR *xdrs;
register struct rmtcallargs *cap;
{
/* does not get a port number */
if (xdr_u_long(xdrs, &(cap->rmt_prog)) &&
xdr_u_long(xdrs, &(cap->rmt_vers)) &&
xdr_u_long(xdrs, &(cap->rmt_proc))) {
return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
}
return (FALSE);
}
static bool_t
xdr_rmtcall_result(xdrs, cap)
register XDR *xdrs;
register struct rmtcallargs *cap;
{
if (xdr_u_long(xdrs, &(cap->rmt_port)))
return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
return (FALSE);
}
/*
* only worries about the struct encap_parms part of struct rmtcallargs.
* The arglen must already be set!!
*/
static bool_t
xdr_opaque_parms(xdrs, cap)
XDR *xdrs;
struct rmtcallargs *cap;
{
return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen));
}
/*
* This routine finds and sets the length of incoming opaque paraters
* and then calls xdr_opaque_parms.
*/
static bool_t
xdr_len_opaque_parms(xdrs, cap)
register XDR *xdrs;
struct rmtcallargs *cap;
{
register u_int beginpos, lowpos, highpos, currpos, pos;
beginpos = lowpos = pos = xdr_getpos(xdrs);
highpos = lowpos + ARGSIZE;
while ((int)(highpos - lowpos) >= 0) {
currpos = (lowpos + highpos) / 2;
if (xdr_setpos(xdrs, currpos)) {
pos = currpos;
lowpos = currpos + 1;
} else {
highpos = currpos - 1;
}
}
xdr_setpos(xdrs, beginpos);
cap->rmt_args.arglen = pos - beginpos;
return (xdr_opaque_parms(xdrs, cap));
}
/*
* Call a remote procedure service
* This procedure is very quiet when things go wrong.
* The proc is written to support broadcast rpc. In the broadcast case,
* a machine should shut-up instead of complain, less the requestor be
* overrun with complaints at the expense of not hearing a valid reply ...
*
* This now forks so that the program & process that it calls can call
* back to the portmapper.
*/
static
callit(rqstp, xprt)
struct svc_req *rqstp;
SVCXPRT *xprt;
{
struct rmtcallargs a;
struct pmaplist *pml;
u_short port;
struct sockaddr_in me;
int pid, socket = -1;
CLIENT *client;
struct authunix_parms *au = (struct authunix_parms *)rqstp->rq_clntcred;
struct timeval timeout;
union wait pinfo;
char buf[ARGSIZE];
timeout.tv_sec = 5;
timeout.tv_usec = 0;
a.rmt_args.args = buf;
if (!svc_getargs(xprt, xdr_rmtcall_args, &a))
return;
if ((pml = find_service(a.rmt_prog, a.rmt_vers, IPPROTO_UDP)) == NULL)
return;
/*
* fork a child to do the work. Parent immediately returns.
* Child exits upon completion.
*/
if ((pid = fork()) != 0) {
if (debugging && (pid < 0)) {
fprintf(stderr, "portmap CALLIT: cannot fork.\n");
}
/* reap previous forks. */
for (; pid>0; pid = wait3(&pinfo, WNOHANG, (struct rusage *)0));
return;
}
port = pml->pml_map.pm_port;
get_myaddress(&me);
me.sin_port = htons(port);
client = clntudp_create(&me, a.rmt_prog, a.rmt_vers, timeout, &socket);
if (client != (CLIENT *)NULL) {
if (rqstp->rq_cred.oa_flavor == AUTH_UNIX) {
client->cl_auth = authunix_create(au->aup_machname,
au->aup_uid, au->aup_gid, au->aup_len, au->aup_gids);
}
a.rmt_port = (u_long)port;
if (clnt_call(client, a.rmt_proc, xdr_opaque_parms, &a,
xdr_len_opaque_parms, &a, timeout) == RPC_SUCCESS) {
svc_sendreply(xprt, xdr_rmtcall_result, &a);
}
AUTH_DESTROY(client->cl_auth);
clnt_destroy(client);
}
(void)close(socket);
exit(0);
}
Funky_Stuff
len=`wc -c < portmap.c`
if [ $len != 11403 ] ; then
echo error: portmap.c was $len bytes long, should have been 11403
fi
echo x - rpc
cat > rpc <<'Funky_Stuff'
#
# rpc 87/12/02 3.9 RPCSRC
#
portmapper 100000 portmap sunrpc
rstat_svc 100001 rstatd rstat rup perfmeter
rusersd 100002 rusers
nfs 100003 nfsprog
ypserv 100004 ypprog
mountd 100005 mount showmount
ypbind 100007
walld 100008 rwall shutdown
yppasswdd 100009 yppasswd
etherstatd 100010 etherstat
rquotad 100011 rquotaprog quota rquota
sprayd 100012 spray
3270_mapper 100013
rje_mapper 100014
selection_svc 100015 selnsvc
database_svc 100016
rexd 100017 rex
alis 100018
sched 100019
llockmgr 100020
nlockmgr 100021
x25.inr 100022
statmon 100023
status 100024
bootparam 100026
ypupdated 100028 ypupdate
keyserv 100029 keyserver
Funky_Stuff
len=`wc -c < rpc`
if [ $len != 787 ] ; then
echo error: rpc was $len bytes long, should have been 787
fi
echo x - rpcinfo.c
cat > rpcinfo.c <<'Funky_Stuff'
/* @(#)rpcinfo.c 1.5 87/11/20 3.9 RPCSRC */
#ifndef lint
static char sccsid[] = "@(#)rpcinfo.c 1.22 87/08/12 SMI";
#endif
/*
* Copyright (C) 1986, Sun Microsystems, Inc.
*/
/*
* rpcinfo: ping a particular rpc program
* or dump the portmapper
*/
/*
* Sun RPC is a product of Sun Microsystems, Inc. and is provided for
* unrestricted use provided that this legend is included on all tape
* media and as a part of the software program in whole or part. Users
* may copy or modify Sun RPC without charge, but are not authorized
* to license or distribute it to anyone else except as part of a product or
* program developed by the user.
*
* SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
* WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
*
* Sun RPC is provided with no support and without any obligation on the
* part of Sun Microsystems, Inc. to assist in its use, correction,
* modification or enhancement.
*
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
* OR ANY PART THEREOF.
*
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
* or profits or other special, indirect and consequential damages, even if
* Sun has been advised of the possibility of such damages.
*
* Sun Microsystems, Inc.
* 2550 Garcia Avenue
* Mountain View, California 94043
*/
#include <rpc/rpc.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netdb.h>
#include <rpc/pmap_prot.h>
#include <rpc/pmap_clnt.h>
#include <signal.h>
#include <ctype.h>
#define MAXHOSTLEN 256
#define MIN_VERS ((u_long) 0)
#define MAX_VERS ((u_long) 4294967295L)
static void udpping(/*u_short portflag, int argc, char **argv*/);
static void tcpping(/*u_short portflag, int argc, char **argv*/);
static int pstatus(/*CLIENT *client, u_long prognum, u_long vers*/);
static void pmapdump(/*int argc, char **argv*/);
static bool_t reply_proc(/*void *res, struct sockaddr_in *who*/);
static void brdcst(/*int argc, char **argv*/);
static void usage(/*void*/);
static u_long getprognum(/*char *arg*/);
static u_long getvers(/*char *arg*/);
static void get_inet_address(/*struct sockaddr_in *addr, char *host*/);
extern u_long inet_addr(); /* in 4.2BSD, arpa/inet.h called that a in_addr */
extern char *inet_ntoa();
/*
* Functions to be performed.
*/
#define NONE 0 /* no function */
#define PMAPDUMP 1 /* dump portmapper registrations */
#define TCPPING 2 /* ping TCP service */
#define UDPPING 3 /* ping UDP service */
#define BRDCST 4 /* ping broadcast UDP service */
int
main(argc, argv)
int argc;
char **argv;
{
register int c;
extern char *optarg;
extern int optind;
int errflg;
int function;
u_short portnum;
function = NONE;
portnum = 0;
errflg = 0;
while ((c = getopt(argc, argv, "ptubn:")) != EOF) {
switch (c) {
case 'p':
if (function != NONE)
errflg = 1;
else
function = PMAPDUMP;
break;
case 't':
if (function != NONE)
errflg = 1;
else
function = TCPPING;
break;
case 'u':
if (function != NONE)
errflg = 1;
else
function = UDPPING;
break;
case 'b':
if (function != NONE)
errflg = 1;
else
function = BRDCST;
break;
case 'n':
portnum = (u_short) atoi(optarg); /* hope we don't get bogus # */
break;
case '?':
errflg = 1;
}
}
if (errflg || function == NONE) {
usage();
return (1);
}
switch (function) {
case PMAPDUMP:
if (portnum != 0) {
usage();
return (1);
}
pmapdump(argc - optind, argv + optind);
break;
case UDPPING:
udpping(portnum, argc - optind, argv + optind);
break;
case TCPPING:
tcpping(portnum, argc - optind, argv + optind);
break;
case BRDCST:
if (portnum != 0) {
usage();
return (1);
}
brdcst(argc - optind, argv + optind);
break;
}
return (0);
}
static void
udpping(portnum, argc, argv)
u_short portnum;
int argc;
char **argv;
{
struct timeval to;
struct sockaddr_in addr;
enum clnt_stat rpc_stat;
CLIENT *client;
u_long prognum, vers, minvers, maxvers;
int sock = RPC_ANYSOCK;
struct rpc_err rpcerr;
int failure;
if (argc < 2 || argc > 3) {
usage();
exit(1);
}
prognum = getprognum(argv[1]);
get_inet_address(&addr, argv[0]);
/* Open the socket here so it will survive calls to clnt_destroy */
sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock < 0) {
perror("rpcinfo: socket");
exit(1);
}
failure = 0;
if (argc == 2) {
/*
* A call to version 0 should fail with a program/version
* mismatch, and give us the range of versions supported.
*/
addr.sin_port = htons(portnum);
to.tv_sec = 5;
to.tv_usec = 0;
if ((client = clntudp_create(&addr, prognum, (u_long)0,
to, &sock)) == NULL) {
clnt_pcreateerror("rpcinfo");
printf("program %lu is not available\n",
prognum);
exit(1);
}
to.tv_sec = 10;
to.tv_usec = 0;
rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL,
xdr_void, (char *)NULL, to);
if (rpc_stat == RPC_PROGVERSMISMATCH) {
clnt_geterr(client, &rpcerr);
minvers = rpcerr.re_vers.low;
maxvers = rpcerr.re_vers.high;
} else if (rpc_stat == RPC_SUCCESS) {
/*
* Oh dear, it DOES support version 0.
* Let's try version MAX_VERS.
*/
addr.sin_port = htons(portnum);
to.tv_sec = 5;
to.tv_usec = 0;
if ((client = clntudp_create(&addr, prognum, MAX_VERS,
to, &sock)) == NULL) {
clnt_pcreateerror("rpcinfo");
printf("program %lu version %lu is not available\n",
prognum, MAX_VERS);
exit(1);
}
to.tv_sec = 10;
to.tv_usec = 0;
rpc_stat = clnt_call(client, NULLPROC, xdr_void,
(char *)NULL, xdr_void, (char *)NULL, to);
if (rpc_stat == RPC_PROGVERSMISMATCH) {
clnt_geterr(client, &rpcerr);
minvers = rpcerr.re_vers.low;
maxvers = rpcerr.re_vers.high;
} else if (rpc_stat == RPC_SUCCESS) {
/*
* It also supports version MAX_VERS.
* Looks like we have a wise guy.
* OK, we give them information on all
* 4 billion versions they support...
*/
minvers = 0;
maxvers = MAX_VERS;
} else {
(void) pstatus(client, prognum, MAX_VERS);
exit(1);
}
} else {
(void) pstatus(client, prognum, (u_long)0);
exit(1);
}
clnt_destroy(client);
for (vers = minvers; vers <= maxvers; vers++) {
addr.sin_port = htons(portnum);
to.tv_sec = 5;
to.tv_usec = 0;
if ((client = clntudp_create(&addr, prognum, vers,
to, &sock)) == NULL) {
clnt_pcreateerror("rpcinfo");
printf("program %lu version %lu is not available\n",
prognum, vers);
exit(1);
}
to.tv_sec = 10;
to.tv_usec = 0;
rpc_stat = clnt_call(client, NULLPROC, xdr_void,
(char *)NULL, xdr_void, (char *)NULL, to);
if (pstatus(client, prognum, vers) < 0)
failure = 1;
clnt_destroy(client);
}
}
else {
vers = getvers(argv[2]);
addr.sin_port = htons(portnum);
to.tv_sec = 5;
to.tv_usec = 0;
if ((client = clntudp_create(&addr, prognum, vers,
to, &sock)) == NULL) {
clnt_pcreateerror("rpcinfo");
printf("program %lu version %lu is not available\n",
prognum, vers);
exit(1);
}
to.tv_sec = 10;
to.tv_usec = 0;
rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
xdr_void, (char *)NULL, to);
if (pstatus(client, prognum, vers) < 0)
failure = 1;
}
(void) close(sock); /* Close it up again */
if (failure)
exit(1);
}
static void
tcpping(portnum, argc, argv)
u_short portnum;
int argc;
char **argv;
{
struct timeval to;
struct sockaddr_in addr;
enum clnt_stat rpc_stat;
CLIENT *client;
u_long prognum, vers, minvers, maxvers;
int sock = RPC_ANYSOCK;
struct rpc_err rpcerr;
int failure;
if (argc < 2 || argc > 3) {
usage();
exit(1);
}
prognum = getprognum(argv[1]);
get_inet_address(&addr, argv[0]);
failure = 0;
if (argc == 2) {
/*
* A call to version 0 should fail with a program/version
* mismatch, and give us the range of versions supported.
*/
addr.sin_port = htons(portnum);
if ((client = clnttcp_create(&addr, prognum, MIN_VERS,
&sock, 0, 0)) == NULL) {
clnt_pcreateerror("rpcinfo");
printf("program %lu is not available\n",
prognum);
exit(1);
}
to.tv_sec = 10;
to.tv_usec = 0;
rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL,
xdr_void, (char *)NULL, to);
if (rpc_stat == RPC_PROGVERSMISMATCH) {
clnt_geterr(client, &rpcerr);
minvers = rpcerr.re_vers.low;
maxvers = rpcerr.re_vers.high;
} else if (rpc_stat == RPC_SUCCESS) {
/*
* Oh dear, it DOES support version 0.
* Let's try version MAX_VERS.
*/
addr.sin_port = htons(portnum);
if ((client = clnttcp_create(&addr, prognum, MAX_VERS,
&sock, 0, 0)) == NULL) {
clnt_pcreateerror("rpcinfo");
printf("program %lu version %lu is not available\n",
prognum, MAX_VERS);
exit(1);
}
to.tv_sec = 10;
to.tv_usec = 0;
rpc_stat = clnt_call(client, NULLPROC, xdr_void,
(char *)NULL, xdr_void, (char *)NULL, to);
if (rpc_stat == RPC_PROGVERSMISMATCH) {
clnt_geterr(client, &rpcerr);
minvers = rpcerr.re_vers.low;
maxvers = rpcerr.re_vers.high;
} else if (rpc_stat == RPC_SUCCESS) {
/*
* It also supports version MAX_VERS.
* Looks like we have a wise guy.
* OK, we give them information on all
* 4 billion versions they support...
*/
minvers = 0;
maxvers = MAX_VERS;
} else {
(void) pstatus(client, prognum, MAX_VERS);
exit(1);
}
} else {
(void) pstatus(client, prognum, MIN_VERS);
exit(1);
}
clnt_destroy(client);
(void) close(sock);
sock = RPC_ANYSOCK; /* Re-initialize it for later */
for (vers = minvers; vers <= maxvers; vers++) {
addr.sin_port = htons(portnum);
if ((client = clnttcp_create(&addr, prognum, vers,
&sock, 0, 0)) == NULL) {
clnt_pcreateerror("rpcinfo");
printf("program %lu version %lu is not available\n",
prognum, vers);
exit(1);
}
to.tv_usec = 0;
to.tv_sec = 10;
rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
xdr_void, (char *)NULL, to);
if (pstatus(client, prognum, vers) < 0)
failure = 1;
clnt_destroy(client);
(void) close(sock);
sock = RPC_ANYSOCK;
}
}
else {
vers = getvers(argv[2]);
addr.sin_port = htons(portnum);
if ((client = clnttcp_create(&addr, prognum, vers, &sock,
0, 0)) == NULL) {
clnt_pcreateerror("rpcinfo");
printf("program %lu version %lu is not available\n",
prognum, vers);
exit(1);
}
to.tv_usec = 0;
to.tv_sec = 10;
rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
xdr_void, (char *)NULL, to);
if (pstatus(client, prognum, vers) < 0)
failure = 1;
}
if (failure)
exit(1);
}
/*
* This routine should take a pointer to an "rpc_err" structure, rather than
* a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
* a CLIENT structure rather than a pointer to an "rpc_err" structure.
* As such, we have to keep the CLIENT structure around in order to print
* a good error message.
*/
static int
pstatus(client, prognum, vers)
register CLIENT *client;
u_long prognum;
u_long vers;
{
struct rpc_err rpcerr;
clnt_geterr(client, &rpcerr);
if (rpcerr.re_status != RPC_SUCCESS) {
clnt_perror(client, "rpcinfo");
printf("program %lu version %lu is not available\n",
prognum, vers);
return (-1);
} else {
printf("program %lu version %lu ready and waiting\n",
prognum, vers);
return (0);
}
}
static void
pmapdump(argc, argv)
int argc;
char **argv;
{
struct sockaddr_in server_addr;
register struct hostent *hp;
struct pmaplist *head = NULL;
int socket = RPC_ANYSOCK;
struct timeval minutetimeout;
register CLIENT *client;
struct rpcent *rpc;
if (argc > 1) {
usage();
exit(1);
}
if (argc == 1)
get_inet_address(&server_addr, argv[0]);
else {
bzero((char *)&server_addr, sizeof server_addr);
server_addr.sin_family = AF_INET;
if ((hp = gethostbyname("localhost")) != NULL)
bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr,
hp->h_length);
else
server_addr.sin_addr.s_addr = inet_addr("0.0.0.0");
}
minutetimeout.tv_sec = 60;
minutetimeout.tv_usec = 0;
server_addr.sin_port = htons(PMAPPORT);
if ((client = clnttcp_create(&server_addr, PMAPPROG,
PMAPVERS, &socket, 50, 500)) == NULL) {
clnt_pcreateerror("rpcinfo: can't contact portmapper");
exit(1);
}
if (clnt_call(client, PMAPPROC_DUMP, xdr_void, NULL,
xdr_pmaplist, &head, minutetimeout) != RPC_SUCCESS) {
fprintf(stderr, "rpcinfo: can't contact portmapper: ");
clnt_perror(client, "rpcinfo");
exit(1);
}
if (head == NULL) {
printf("No remote programs registered.\n");
} else {
printf(" program vers proto port\n");
for (; head != NULL; head = head->pml_next) {
printf("%10ld%5ld",
head->pml_map.pm_prog,
head->pml_map.pm_vers);
if (head->pml_map.pm_prot == IPPROTO_UDP)
printf("%6s", "udp");
else if (head->pml_map.pm_prot == IPPROTO_TCP)
printf("%6s", "tcp");
else
printf("%6ld", head->pml_map.pm_prot);
printf("%7ld", head->pml_map.pm_port);
rpc = getrpcbynumber(head->pml_map.pm_prog);
if (rpc)
printf(" %s\n", rpc->r_name);
else
printf("\n");
}
}
}
/*
* reply_proc collects replies from the broadcast.
* to get a unique list of responses the output of rpcinfo should
* be piped through sort(1) and then uniq(1).
*/
/*ARGSUSED*/
static bool_t
reply_proc(res, who)
void *res; /* Nothing comes back */
struct sockaddr_in *who; /* Who sent us the reply */
{
register struct hostent *hp;
hp = gethostbyaddr((char *) &who->sin_addr, sizeof who->sin_addr,
AF_INET);
printf("%s %s\n", inet_ntoa(who->sin_addr),
(hp == NULL) ? "(unknown)" : hp->h_name);
return(FALSE);
}
static void
brdcst(argc, argv)
int argc;
char **argv;
{
enum clnt_stat rpc_stat;
u_long prognum, vers;
if (argc != 2) {
usage();
exit(1);
}
prognum = getprognum(argv[0]);
vers = getvers(argv[1]);
rpc_stat = clnt_broadcast(prognum, vers, NULLPROC, xdr_void,
(char *)NULL, xdr_void, (char *)NULL, reply_proc);
if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT)) {
fprintf(stderr, "rpcinfo: broadcast failed: %s\n",
clnt_sperrno(rpc_stat));
exit(1);
}
exit(0);
}
static void
usage()
{
fprintf(stderr, "Usage: rpcinfo [ -n portnum ] -u host prognum [ versnum ]\n");
fprintf(stderr, " rpcinfo [ -n portnum ] -t host prognum [ versnum ]\n");
fprintf(stderr, " rpcinfo -p [ host ]\n");
fprintf(stderr, " rpcinfo -b prognum versnum\n");
}
static u_long
getprognum(arg)
char *arg;
{
register struct rpcent *rpc;
register u_long prognum;
if (isalpha(*arg)) {
rpc = getrpcbyname(arg);
if (rpc == NULL) {
fprintf(stderr, "rpcinfo: %s is unknown service\n",
arg);
exit(1);
}
prognum = rpc->r_number;
} else {
prognum = (u_long) atoi(arg);
}
return (prognum);
}
static u_long
getvers(arg)
char *arg;
{
register u_long vers;
vers = (int) atoi(arg);
return (vers);
}
static void
get_inet_address(addr, host)
struct sockaddr_in *addr;
char *host;
{
register struct hostent *hp;
bzero((char *)addr, sizeof *addr);
addr->sin_addr.s_addr = (u_long) inet_addr(host);
if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0) {
if ((hp = gethostbyname(host)) == NULL) {
fprintf(stderr, "rpcinfo: %s is unknown host\n", host);
exit(1);
}
bcopy(hp->h_addr, (char *)&addr->sin_addr, hp->h_length);
}
addr->sin_family = AF_INET;
}
Funky_Stuff
len=`wc -c < rpcinfo.c`
if [ $len != 15727 ] ; then
echo error: rpcinfo.c was $len bytes long, should have been 15727
fi
cd ..
echo done with directory etc
echo x - demo
echo creating directory demo
mkdir demo
cd demo
echo x - Makefile
cat > Makefile <<'Funky_Stuff'
#
# @(#)Makefile 1.4 87/11/30 3.9 RPCSRC
#
#
# Build all demo services
#
MAKE = make
LIB=-lrpclib
SUBDIR= dir msg sort
all: ${SUBDIR}
clean cleanup:
cd dir; $(MAKE) ${MFLAGS} cleanup
cd msg; $(MAKE) ${MFLAGS} cleanup
cd sort; $(MAKE) ${MFLAGS} cleanup
install:
@echo "No installations done."
${SUBDIR}: FRC
cd $@; $(MAKE) ${MFLAGS} LIB=$(LIB)
FRC:
Funky_Stuff
len=`wc -c < Makefile`
if [ $len != 361 ] ; then
echo error: Makefile was $len bytes long, should have been 361
fi
echo x - dir
echo creating directory dir
mkdir dir
cd dir
echo x - Makefile
cat > Makefile <<'Funky_Stuff'
#
# @(#)Makefile 1.3 87/11/30 3.9 RPCSRC
#
BIN = dir_svc rls
GEN = dir_clnt.c dir_svc.c dir_xdr.c dir.h
LIB = -lrpclib
RPCCOM = rpcgen
all: $(BIN)
$(GEN): dir.x
$(RPCCOM) dir.x
dir_svc: dir_proc.o dir_svc.o dir_xdr.o
$(CC) -o $@ dir_proc.o dir_svc.o dir_xdr.o $(LIB)
rls: rls.o dir_clnt.o dir_xdr.o
$(CC) -o $@ rls.o dir_clnt.o dir_xdr.o $(LIB)
rls.o: rls.c dir.h
dir_proc.o: dir_proc.c dir.h
clean cleanup:
rm -f $(GEN) *.o $(BIN)
Funky_Stuff
len=`wc -c < Makefile`
if [ $len != 444 ] ; then
echo error: Makefile was $len bytes long, should have been 444
fi
echo x - dir.x
cat > dir.x <<'Funky_Stuff'
/* @(#)dir.x 1.1 87/11/04 3.9 RPCSRC */
/*
* dir.x: Remote directory listing protocol
*/
const MAXNAMELEN = 255; /* maximum length of a directory entry */
typedef string nametype<MAXNAMELEN>; /* a directory entry */
typedef struct namenode *namelist; /* a link in the listing */
/*
* A node in the directory listing
*/
struct namenode {
nametype name; /* name of directory entry */
namelist next; /* next entry */
};
/*
* The result of a READDIR operation.
*/
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;
} = 76;
Funky_Stuff
len=`wc -c < dir.x`
if [ $len != 780 ] ; then
echo error: dir.x was $len bytes long, should have been 780
fi
echo x - dir_proc.c
cat > dir_proc.c <<'Funky_Stuff'
/* @(#)dir_proc.c 1.3 87/11/16 3.9 RPCSRC */
/*
* dir_proc.c: remote readdir implementation
*/
#include <rpc/rpc.h>
#include <sys/dir.h>
#include "dir.h"
extern int errno;
extern char *malloc();
extern char *strcpy();
readdir_res *
readdir_1(dirname)
nametype *dirname;
{
DIR *dirp;
struct direct *d;
namelist nl;
namelist *nlp;
static readdir_res res; /* must be static! */
/*
* Open directory
*/
dirp = opendir(*dirname);
if (dirp == NULL) {
res.errno = errno;
return (&res);
}
/*
* Free previous result
*/
xdr_free(xdr_readdir_res, &res);
/*
* Collect directory entries
*/
nlp = &res.readdir_res_u.list;
while (d = readdir(dirp)) {
nl = *nlp = (namenode *) malloc(sizeof(namenode));
nl->name = malloc(strlen(d->d_name)+1);
strcpy(nl->name, d->d_name);
nlp = &nl->next;
}
*nlp = NULL;
/*
* Return the result
*/
res.errno = 0;
closedir(dirp);
return (&res);
}
Funky_Stuff
len=`wc -c < dir_proc.c`
if [ $len != 919 ] ; then
echo error: dir_proc.c was $len bytes long, should have been 919
fi
echo x - rls.c
cat > rls.c <<'Funky_Stuff'
/* @(#)rls.c 1.1 87/11/04 3.9 RPCSRC */
/*
* rls.c: Remote directory listing client
*/
#include <stdio.h>
#include <rpc/rpc.h> /* always need this */
#include "dir.h" /* need this too: will be 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);
}
/*
* Remember what our command line arguments refer to
*/
server = argv[1];
dir = argv[2];
/*
* Create client "handle" used for calling MESSAGEPROG on the
* server designated on the command line. We tell the rpc package
* to use the "tcp" protocol when contacting the server.
*/
cl = clnt_create(server, DIRPROG, DIRVERS, "tcp");
if (cl == NULL) {
/*
* Couldn't establish connection with server.
* Print error message and die.
*/
clnt_pcreateerror(server);
exit(1);
}
/*
* Call the remote procedure "readdir" on the server
*/
result = readdir_1(&dir, cl);
if (result == NULL) {
/*
* An error occurred while calling the server.
* Print error message and die.
*/
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.
*/
errno = result->errno;
perror(dir);
exit(1);
}
/*
* Successfuly got a directory listing.
* Print it out.
*/
for (nl = result->readdir_res_u.list; nl != NULL; nl = nl->next) {
printf("%s\n", nl->name);
}
}
Funky_Stuff
len=`wc -c < rls.c`
if [ $len != 1611 ] ; then
echo error: rls.c was $len bytes long, should have been 1611
fi
cd ..
echo done with directory dir
echo x - msg
echo creating directory msg
mkdir msg
cd msg
echo x - Makefile
cat > Makefile <<'Funky_Stuff'
#
# @(#)Makefile 1.4 87/11/30 3.9 RPCSRC
#
BIN = printmsg msg_svc rprintmsg
GEN = msg_clnt.c msg_svc.c msg.h
LIB = -lrpclib
RPCCOM = rpcgen
all: $(BIN)
#
# This is the non-networked version of the program
#
printmsg: printmsg.o
$(CC) -o $@ printmsg.o
#
# note: no xdr routines are generated here, due this service's
# use of basic data types.
#
$(GEN): msg.x
$(RPCCOM) msg.x
msg_svc: msg_proc.o msg_svc.o
$(CC) -o $@ msg_proc.o msg_svc.o $(LIB)
rprintmsg: rprintmsg.o msg_clnt.o
$(CC) -o $@ rprintmsg.o msg_clnt.o $(LIB)
rprintmsg.o: rprintmsg.c msg.h
msg_proc.o: msg_proc.c msg.h
clean cleanup:
rm -f $(GEN) *.o $(BIN)
Funky_Stuff
len=`wc -c < Makefile`
if [ $len != 640 ] ; then
echo error: Makefile was $len bytes long, should have been 640
fi
echo x - msg.x
cat > msg.x <<'Funky_Stuff'
/* @(#)msg.x 1.1 87/11/04 3.9 RPCSRC */
/*
* msg.x: Remote message printing protocol
*/
program MESSAGEPROG {
version MESSAGEVERS {
int PRINTMESSAGE(string) = 1;
} = 1;
} = 99;
Funky_Stuff
len=`wc -c < msg.x`
if [ $len != 183 ] ; then
echo error: msg.x was $len bytes long, should have been 183
fi
echo x - msg_proc.c
cat > msg_proc.c <<'Funky_Stuff'
/* @(#)msg_proc.c 1.1 87/11/04 3.9 RPCSRC */
/*
* msg_proc.c: implementation of the remote procedure "printmessage"
*/
#include <stdio.h>
#include <rpc/rpc.h> /* always need this here */
#include "msg.h" /* need this too: msg.h will be generated by rpcgen */
/*
* Remote verson of "printmessage"
*/
int *
printmessage_1(msg)
char **msg;
{
static int result; /* must be static! */
FILE *f;
f = fopen("/dev/console", "w");
if (f == NULL) {
result = 0;
return (&result);
}
fprintf(f, "%s\n", *msg);
fclose(f);
result = 1;
return (&result);
}
Funky_Stuff
len=`wc -c < msg_proc.c`
if [ $len != 562 ] ; then
echo error: msg_proc.c was $len bytes long, should have been 562
fi
echo x - printmsg.c
cat > printmsg.c <<'Funky_Stuff'
/* @(#)printmsg.c 1.1 87/11/04 3.9 RPCSRC */
/*
* printmsg.c: print a message on the console
*/
#include <stdio.h>
main(argc, argv)
int argc;
char *argv[];
{
char *message;
if (argc < 2) {
fprintf(stderr, "usage: %s <message>\n", argv[0]);
exit(1);
}
message = argv[1];
if (!printmessage(message)) {
fprintf(stderr, "%s: sorry, couldn't print your message\n",
argv[0]);
exit(1);
}
printf("Message delivered!\n");
}
/*
* Print a message to the console.
* Return a boolean indicating whether the message was actually printed.
*/
printmessage(msg)
char *msg;
{
FILE *f;
f = fopen("/dev/console", "w");
if (f == NULL) {
return (0);
}
fprintf(f, "%s\n", msg);
fclose(f);
return(1);
}
Funky_Stuff
len=`wc -c < printmsg.c`
if [ $len != 720 ] ; then
echo error: printmsg.c was $len bytes long, should have been 720
fi
echo x - rprintmsg.c
cat > rprintmsg.c <<'Funky_Stuff'
/* @(#)rprintmsg.c 1.1 87/11/04 3.9 RPCSRC */
/*
* rprintmsg.c: remote version of "printmsg.c"
*/
#include <stdio.h>
#include <rpc/rpc.h> /* always need this */
#include "msg.h" /* need this too: will be generated by rpcgen*/
main(argc, argv)
int argc;
char *argv[];
{
CLIENT *cl;
int *result;
char *server;
char *message;
if (argc < 3) {
fprintf(stderr, "usage: %s host message\n", argv[0]);
exit(1);
}
/*
* Remember what our command line arguments refer to
*/
server = argv[1];
message = argv[2];
/*
* Create client "handle" used for calling MESSAGEPROG on the
* server designated on the command line. We tell the rpc package
* to use the "tcp" protocol when contacting the server.
*/
cl = clnt_create(server, MESSAGEPROG, MESSAGEVERS, "tcp");
if (cl == NULL) {
/*
* Couldn't establish connection with server.
* Print error message and die.
*/
clnt_pcreateerror(server);
exit(1);
}
/*
* Call the remote procedure "printmessage" on the server
*/
result = printmessage_1(&message, cl);
if (result == NULL) {
/*
* An error occurred while calling the server.
* Print error message and die.
*/
clnt_perror(cl, server);
exit(1);
}
/*
* Okay, we successfully called the remote procedure.
*/
if (*result == 0) {
/*
* Server was unable to print our message.
* Print error message and die.
*/
fprintf(stderr, "%s: sorry, %s couldn't print your message\n",
argv[0], server);
exit(1);
}
/*
* The message got printed on the server's console
*/
printf("Message delivered to %s!\n", server);
}
Funky_Stuff
len=`wc -c < rprintmsg.c`
if [ $len != 1599 ] ; then
echo error: rprintmsg.c was $len bytes long, should have been 1599
fi
cd ..
echo done with directory msg
echo x - sort
echo creating directory sort
mkdir sort
cd sort
echo x - Makefile
cat > Makefile <<'Funky_Stuff'
#
# @(#)Makefile 1.4 87/11/30 3.9 RPCSRC
#
BIN = rsort sort_svc
GEN = sort_clnt.c sort_svc.c sort_xdr.c sort.h
LIB = -lrpclib
RPCCOM = rpcgen
all: $(BIN)
rsort: rsort.o sort_clnt.o sort_xdr.o
$(CC) $(LDFLAGS) -o $@ rsort.o sort_clnt.o sort_xdr.o $(LIB)
rsort.o: rsort.c sort.h
sort_clnt.c:
$(RPCCOM) -l sort.x >$@
sort_svc: sort_proc.o sort_svc.o sort_xdr.o
$(CC) $(LDFLAGS) -o $@ sort_proc.o sort_svc.o sort_xdr.o $(LIB)
sort_proc.o: sort_proc.c sort.h
sort_svc.c:
$(RPCCOM) -s udp sort.x >$@
sort_xdr.c:
$(RPCCOM) -c sort.x >$@
sort.h:
$(RPCCOM) -h sort.x >$@
clean cleanup:
rm -f $(GEN) *.o $(BIN)
Funky_Stuff
len=`wc -c < Makefile`
if [ $len != 621 ] ; then
echo error: Makefile was $len bytes long, should have been 621
fi
echo x - rsort.c
cat > rsort.c <<'Funky_Stuff'
/* @(#)rsort.c 1.2 87/11/24 3.9 RPCSRC */
/*
* rsort.c
* Client side application which sorts argc, argv.
*/
#include <stdio.h>
#include <rpc/rpc.h>
#include "sort.h"
main(argc, argv)
int argc;
char **argv;
{
char *machinename;
struct sortstrings args, res;
int i;
if (argc < 3) {
fprintf(stderr, "usage: %s machinename [s1 ...]\n", argv[0]);
exit(1);
}
machinename = argv[1];
args.ss.ss_len = argc - 2; /* substract off progname, machinename */
args.ss.ss_val = &argv[2];
res.ss.ss_val = (char **)NULL;
if ((i = callrpc(machinename, SORTPROG, SORTVERS, SORT,
xdr_sortstrings, &args, xdr_sortstrings, &res)))
{
fprintf(stderr, "%s: call to sort service failed. ", argv[0]);
clnt_perrno(i);
fprintf(stderr, "\n");
exit(1);
}
for (i = 0; i < res.ss.ss_len; i++) {
printf("%s\n", res.ss.ss_val[i]);
}
/* should free res here */
exit(0);
}
Funky_Stuff
len=`wc -c < rsort.c`
if [ $len != 897 ] ; then
echo error: rsort.c was $len bytes long, should have been 897
fi
echo x - sort.x
cat > sort.x <<'Funky_Stuff'
/* @(#)sort.x 1.1 87/11/04 3.9 RPCSRC */
/*
* The sort procedure receives an array of strings and returns an array
* of strings. This toy service handles a maximum of 64 strings.
*/
const MAXSORTSIZE = 64;
const MAXSTRINGLEN = 64;
typedef string str<MAXSTRINGLEN>; /* the string itself */
struct sortstrings {
str ss<MAXSORTSIZE>;
};
program SORTPROG {
version SORTVERS {
sortstrings SORT(sortstrings) = 1;
} = 1;
} = 22855;
Funky_Stuff
len=`wc -c < sort.x`
if [ $len != 455 ] ; then
echo error: sort.x was $len bytes long, should have been 455
fi
echo x - sort_proc.c
cat > sort_proc.c <<'Funky_Stuff'
/* @(#)sort_proc.c 1.2 87/11/24 3.9 RPCSRC */
#include <rpc/rpc.h>
#include "sort.h"
static int
comparestrings(sp1, sp2)
char **sp1, **sp2;
{
return (strcmp(*sp1, *sp2));
}
struct sortstrings *
sort_1(ssp)
struct sortstrings *ssp;
{
static struct sortstrings ss_res;
if (ss_res.ss.ss_val != (str *)NULL)
free(ss_res.ss.ss_val);
qsort(ssp->ss.ss_val, ssp->ss.ss_len, sizeof (char *), comparestrings);
ss_res.ss.ss_len = ssp->ss.ss_len;
ss_res.ss.ss_val = (str *)malloc(ssp->ss.ss_len * sizeof(str *));
bcopy(ssp->ss.ss_val, ss_res.ss.ss_val,
ssp->ss.ss_len * sizeof(str *));
return(&ss_res);
}
Funky_Stuff
len=`wc -c < sort_proc.c`
if [ $len != 653 ] ; then
echo error: sort_proc.c was $len bytes long, should have been 653
fi
cd ..
echo done with directory sort
cd ..
echo done with directory demo
exit
--
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
More information about the Comp.sources.unix
mailing list