rpc_main.c revision 100441
1/*
2 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3 * unrestricted use provided that this legend is included on all tape
4 * media and as a part of the software program in whole or part.  Users
5 * may copy or modify Sun RPC without charge, but are not authorized
6 * to license or distribute it to anyone else except as part of a product or
7 * program developed by the user.
8 *
9 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
12 *
13 * Sun RPC is provided with no support and without any obligation on the
14 * part of Sun Microsystems, Inc. to assist in its use, correction,
15 * modification or enhancement.
16 *
17 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19 * OR ANY PART THEREOF.
20 *
21 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22 * or profits or other special, indirect and consequential damages, even if
23 * Sun has been advised of the possibility of such damages.
24 *
25 * Sun Microsystems, Inc.
26 * 2550 Garcia Avenue
27 * Mountain View, California  94043
28 */
29
30
31#ident	"@(#)rpc_main.c	1.21	94/04/25 SMI"
32
33#if 0
34#ifndef lint
35static char sccsid[] = "@(#)rpc_main.c 1.30 89/03/30 (C) 1987 SMI";
36#endif
37#endif
38
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD: head/usr.bin/rpcgen/rpc_main.c 100441 2002-07-21 12:55:04Z charnier $");
41
42/*
43 * rpc_main.c, Top level of the RPC protocol compiler.
44 * Copyright (C) 1987, Sun Microsystems, Inc.
45 */
46
47#include <err.h>
48#include <ctype.h>
49#include <stdio.h>
50#include <string.h>
51#include <unistd.h>
52#include <sys/types.h>
53#include <sys/param.h>
54#include <sys/file.h>
55#include <sys/stat.h>
56#include "rpc_parse.h"
57#include "rpc_util.h"
58#include "rpc_scan.h"
59
60extern void write_sample_svc( definition * );
61extern int write_sample_clnt( definition * );
62extern void write_sample_clnt_main( void );
63extern void add_sample_msg( void );
64static void c_output( char *, char *, int, char * );
65static void h_output( char *, char *, int, char * );
66static void l_output( char *, char *, int, char * );
67static void t_output( char *, char *, int, char * );
68static void clnt_output( char *, char *, int, char * );
69void c_initialize( void );
70
71#if !defined(__FreeBSD__) && !defined(__NetBSD__)
72char * rindex();
73#endif
74
75static void usage(void);
76static void options_usage(void);
77static int do_registers(int, char **);
78static int parseargs(int, char **, struct commandline *);
79static void svc_output(char *, char *, int, char *);
80static void mkfile_output(struct commandline *);
81static void s_output(int, char **, char *, char *, int, char *, int, int);
82
83#define	EXTEND	1		/* alias for TRUE */
84#define	DONT_EXTEND	0		/* alias for FALSE */
85
86#define	SVR4_CPP "/usr/ccs/lib/cpp"
87#define SUNOS_CPP "/usr/bin/cpp"
88
89static int cppDefined = 0;	/* explicit path for C preprocessor */
90
91static char *svcclosetime = "120";
92static char *CPP = SVR4_CPP;
93static char CPPFLAGS[] = "-C";
94static char pathbuf[MAXPATHLEN + 1];
95static char *allv[] = {
96	"rpcgen", "-s", "udp", "-s", "tcp",
97};
98static int allc = sizeof (allv)/sizeof (allv[0]);
99static char *allnv[] = {
100	"rpcgen", "-s", "netpath",
101};
102static int allnc = sizeof (allnv)/sizeof (allnv[0]);
103
104/*
105 * machinations for handling expanding argument list
106 */
107static void addarg();		/* add another argument to the list */
108static void putarg();		/* put argument at specified location  */
109static void clear_args();	/* clear argument list */
110static void checkfiles();	/* check if out file already exists */
111
112
113
114#define	ARGLISTLEN	20
115#define	FIXEDARGS	2
116
117static char *arglist[ARGLISTLEN];
118static int argcount = FIXEDARGS;
119
120
121int nonfatalerrors;	/* errors */
122int inetdflag = 0;	/* Support for inetd is disabled by default, use -I */
123int pmflag = 0;		/* Support for port monitors is disabled by default */
124int tirpc_socket = 1;	/* TI-RPC on socket, no TLI library */
125int logflag;		/* Use syslog instead of fprintf for errors */
126int tblflag;		/* Support for dispatch table file */
127int mtflag = 0;		/* Support for MT */
128
129#define INLINE 0
130/* length at which to start doing an inline */
131
132int inline = INLINE;
133/*
134 * Length at which to start doing an inline. INLINE = default
135 * if 0, no xdr_inline code
136 */
137
138int indefinitewait;	/* If started by port monitors, hang till it wants */
139int exitnow;		/* If started by port monitors, exit after the call */
140int timerflag;		/* TRUE if !indefinite && !exitnow */
141int newstyle;		/* newstyle of passing arguments (by value) */
142int Cflag = 0;		/* ANSI C syntax */
143int CCflag = 0;		/* C++ files */
144static int allfiles;   /* generate all files */
145int tirpcflag = 1;    /* generating code for tirpc, by default */
146xdrfunc *xdrfunc_head = NULL; /* xdr function list */
147xdrfunc *xdrfunc_tail = NULL; /* xdr function list */
148pid_t childpid;
149
150
151int
152main(argc, argv)
153	int argc;
154	char *argv[];
155{
156	struct commandline cmd;
157
158	(void) memset((char *)&cmd, 0, sizeof (struct commandline));
159	clear_args();
160	if (!parseargs(argc, argv, &cmd))
161		usage();
162	/*
163	 * Only the client and server side stubs are likely to be customized,
164	 *  so in that case only, check if the outfile exists, and if so,
165	 *  print an error message and exit.
166	 */
167	if (cmd.Ssflag || cmd.Scflag || cmd.makefileflag) {
168		checkfiles(cmd.infile, cmd.outfile);
169	}
170	else
171		checkfiles(cmd.infile, NULL);
172
173	if (cmd.cflag) {
174		c_output(cmd.infile, "-DRPC_XDR", DONT_EXTEND, cmd.outfile);
175	} else if (cmd.hflag) {
176		h_output(cmd.infile, "-DRPC_HDR", DONT_EXTEND, cmd.outfile);
177	} else if (cmd.lflag) {
178		l_output(cmd.infile, "-DRPC_CLNT", DONT_EXTEND, cmd.outfile);
179	} else if (cmd.sflag || cmd.mflag || (cmd.nflag)) {
180		s_output(argc, argv, cmd.infile, "-DRPC_SVC", DONT_EXTEND,
181			cmd.outfile, cmd.mflag, cmd.nflag);
182	} else if (cmd.tflag) {
183		t_output(cmd.infile, "-DRPC_TBL", DONT_EXTEND, cmd.outfile);
184	} else if  (cmd.Ssflag) {
185		svc_output(cmd.infile, "-DRPC_SERVER", DONT_EXTEND,
186			cmd.outfile);
187	} else if (cmd.Scflag) {
188		clnt_output(cmd.infile, "-DRPC_CLIENT", DONT_EXTEND,
189			    cmd.outfile);
190	} else if (cmd.makefileflag) {
191		mkfile_output(&cmd);
192	} else {
193		/* the rescans are required, since cpp may effect input */
194		c_output(cmd.infile, "-DRPC_XDR", EXTEND, "_xdr.c");
195		reinitialize();
196		h_output(cmd.infile, "-DRPC_HDR", EXTEND, ".h");
197		reinitialize();
198		l_output(cmd.infile, "-DRPC_CLNT", EXTEND, "_clnt.c");
199		reinitialize();
200		if (inetdflag || !tirpcflag)
201			s_output(allc, allv, cmd.infile, "-DRPC_SVC", EXTEND,
202			"_svc.c", cmd.mflag, cmd.nflag);
203		else
204			s_output(allnc, allnv, cmd.infile, "-DRPC_SVC",
205				EXTEND, "_svc.c", cmd.mflag, cmd.nflag);
206		if (tblflag) {
207			reinitialize();
208		t_output(cmd.infile, "-DRPC_TBL", EXTEND, "_tbl.i");
209		}
210
211		if (allfiles) {
212			reinitialize();
213			svc_output(cmd.infile, "-DRPC_SERVER", EXTEND,
214				"_server.c");
215			reinitialize();
216			clnt_output(cmd.infile, "-DRPC_CLIENT", EXTEND,
217				"_client.c");
218
219		}
220		if (allfiles || (cmd.makefileflag == 1)){
221			reinitialize();
222			mkfile_output(&cmd);
223		}
224
225	}
226	exit(nonfatalerrors);
227	/* NOTREACHED */
228}
229
230
231/*
232 * add extension to filename
233 */
234static char *
235extendfile(path, ext)
236	char *path;
237	char *ext;
238{
239	char *res;
240	char *p;
241	char *file;
242
243	if ((file = rindex(path, '/')) == NULL)
244		file = path;
245	else
246		file++;
247	res = xmalloc(strlen(file) + strlen(ext) + 1);
248	p = strrchr(file, '.');
249	if (p == NULL) {
250		p = file + strlen(file);
251	}
252	(void) strcpy(res, file);
253	(void) strcpy(res + (p - file), ext);
254	return (res);
255}
256
257/*
258 * Open output file with given extension
259 */
260static void
261open_output(infile, outfile)
262	char *infile;
263	char *outfile;
264{
265
266	if (outfile == NULL) {
267		fout = stdout;
268		return;
269	}
270
271	if (infile != NULL && streq(outfile, infile)) {
272		warnx("%s already exists. No output generated", infile);
273		crash();
274	}
275	fout = fopen(outfile, "w");
276	if (fout == NULL) {
277		warn("unable to open %s", outfile);
278		crash();
279	}
280	record_open(outfile);
281
282	return;
283}
284
285static void
286add_warning()
287{
288	f_print(fout, "/*\n");
289	f_print(fout, " * Please do not edit this file.\n");
290	f_print(fout, " * It was generated using rpcgen.\n");
291	f_print(fout, " */\n\n");
292}
293
294/* clear list of arguments */
295static void clear_args()
296{
297	int i;
298	for (i = FIXEDARGS; i < ARGLISTLEN; i++)
299		arglist[i] = NULL;
300	argcount = FIXEDARGS;
301}
302
303/* make sure that a CPP exists */
304static void find_cpp()
305{
306	struct stat buf;
307
308	if (stat(CPP, &buf) < 0)  { /* SVR4 or explicit cpp does not exist */
309		if (cppDefined) {
310			warnx("cannot find C preprocessor: %s", CPP);
311			crash();
312		} else {	/* try the other one */
313			CPP = SUNOS_CPP;
314			if (stat(CPP, &buf) < 0) { /* can't find any cpp */
315				warnx("cannot find C preprocessor: %s", CPP);
316				crash();
317			}
318		}
319	}
320}
321
322/*
323 * Open input file with given define for C-preprocessor
324 */
325static void
326open_input(infile, define)
327	char *infile;
328	char *define;
329{
330	int pd[2];
331
332	infilename = (infile == NULL) ? "<stdin>" : infile;
333	(void) pipe(pd);
334	switch (childpid = fork()) {
335	case 0:
336		find_cpp();
337		putarg(0, CPP);
338		putarg(1, CPPFLAGS);
339		addarg(define);
340		if (infile)
341			addarg(infile);
342		addarg((char *)NULL);
343		(void) close(1);
344		(void) dup2(pd[1], 1);
345		(void) close(pd[0]);
346		execv(arglist[0], arglist);
347		err(1, "execv");
348	case -1:
349		err(1, "fork");
350	}
351	(void) close(pd[1]);
352	fin = fdopen(pd[0], "r");
353	if (fin == NULL) {
354		warn("%s", infilename);
355		crash();
356	}
357}
358
359/* valid tirpc nettypes */
360static char* valid_ti_nettypes[] =
361{
362	"netpath",
363	"visible",
364	"circuit_v",
365	"datagram_v",
366	"circuit_n",
367	"datagram_n",
368	"udp",
369	"tcp",
370	"raw",
371	NULL
372	};
373
374/* valid inetd nettypes */
375static char* valid_i_nettypes[] =
376{
377	"udp",
378	"tcp",
379	NULL
380	};
381
382static int check_nettype(name, list_to_check)
383char* name;
384char* list_to_check[];
385{
386	int i;
387	for (i = 0; list_to_check[i] != NULL; i++) {
388		if (strcmp(name, list_to_check[i]) == 0) {
389			return (1);
390		}
391	}
392	warnx("illegal nettype :\'%s\'", name);
393	return (0);
394}
395
396static char *
397file_name(file, ext)
398char *file;
399char *ext;
400{
401	char *temp;
402	temp = extendfile(file, ext);
403
404	if (access(temp, F_OK) != -1)
405		return (temp);
406	else
407		return ((char *)" ");
408
409}
410
411
412static void
413c_output(infile, define, extend, outfile)
414	char *infile;
415	char *define;
416	int extend;
417	char *outfile;
418{
419	definition *def;
420	char *include;
421	char *outfilename;
422	long tell;
423
424	c_initialize();
425	open_input(infile, define);
426	outfilename = extend ? extendfile(infile, outfile) : outfile;
427	open_output(infile, outfilename);
428	add_warning();
429	if (infile && (include = extendfile(infile, ".h"))) {
430		f_print(fout, "#include \"%s\"\n", include);
431		free(include);
432		/* .h file already contains rpc/rpc.h */
433	} else
434		f_print(fout, "#include <rpc/rpc.h>\n");
435	tell = ftell(fout);
436	while ( (def = get_definition()) ) {
437		emit(def);
438	}
439	if (extend && tell == ftell(fout)) {
440		(void) unlink(outfilename);
441	}
442}
443
444
445void
446c_initialize()
447{
448
449	/* add all the starting basic types */
450	add_type(1, "int");
451	add_type(1, "long");
452	add_type(1, "short");
453	add_type(1, "bool");
454	add_type(1, "u_int");
455	add_type(1, "u_long");
456	add_type(1, "u_short");
457
458}
459
460char rpcgen_table_dcl[] = "struct rpcgen_table {\n\
461	char	*(*proc)(); \n\
462	xdrproc_t	xdr_arg; \n\
463	unsigned	len_arg; \n\
464	xdrproc_t	xdr_res; \n\
465	unsigned	len_res; \n\
466}; \n";
467
468
469char *generate_guard(pathname)
470	char* pathname;
471{
472	char* filename, *guard, *tmp;
473
474	filename = strrchr(pathname, '/');  /* find last component */
475	filename = ((filename == 0) ? pathname : filename+1);
476	guard = xstrdup(filename);
477	/* convert to upper case */
478	tmp = guard;
479	while (*tmp) {
480		if (islower(*tmp))
481			*tmp = toupper(*tmp);
482		tmp++;
483	}
484	guard = extendfile(guard, "_H_RPCGEN");
485	return (guard);
486}
487
488/*
489 * Compile into an XDR header file
490 */
491
492
493static void
494h_output(infile, define, extend, outfile)
495	char *infile;
496	char *define;
497	int extend;
498	char *outfile;
499{
500	definition *def;
501	char *outfilename;
502	long tell;
503	char *guard;
504	list *l;
505	xdrfunc *xdrfuncp;
506	int i;
507
508	open_input(infile, define);
509	outfilename =  extend ? extendfile(infile, outfile) : outfile;
510	open_output(infile, outfilename);
511	add_warning();
512	if (outfilename || infile){
513		guard = generate_guard(outfilename ? outfilename: infile);
514	} else
515		guard = "STDIN_";
516
517	f_print(fout, "#ifndef _%s\n#define	_%s\n\n", guard,
518		guard);
519
520	f_print(fout, "#include <rpc/rpc.h>\n");
521
522	if (mtflag)
523		f_print(fout, "#include <pthread.h>\n");
524
525	/* put the C++ support */
526	if (Cflag && !CCflag){
527		f_print(fout, "\n#ifdef __cplusplus\n");
528		f_print(fout, "extern \"C\" {\n");
529		f_print(fout, "#endif\n\n");
530	}
531
532	/* put in a typedef for quadprecision. Only with Cflag */
533
534	tell = ftell(fout);
535
536	/* print data definitions */
537	while ( (def = get_definition()) ) {
538		print_datadef(def);
539	}
540
541	/*
542	 * print function declarations.
543	 *  Do this after data definitions because they might be used as
544	 *  arguments for functions
545	 */
546	for (l = defined; l != NULL; l = l->next) {
547		print_funcdef(l->val);
548	}
549	/* Now  print all xdr func declarations */
550	if (xdrfunc_head != NULL){
551
552		f_print(fout,
553			"\n/* the xdr functions */\n");
554
555		if (CCflag){
556		f_print(fout, "\n#ifdef __cplusplus\n");
557		f_print(fout, "extern \"C\" {\n");
558		f_print(fout, "#endif\n");
559	}
560
561		if (!Cflag){
562			xdrfuncp = xdrfunc_head;
563			while (xdrfuncp != NULL){
564				print_xdr_func_def(xdrfuncp->name,
565				xdrfuncp->pointerp, 2);
566				xdrfuncp = xdrfuncp->next;
567			}
568		} else {
569
570			for (i = 1; i < 3; i++){
571				if (i == 1)
572	f_print(fout, "\n#if defined(__STDC__) || defined(__cplusplus)\n");
573
574				else
575					f_print(fout, "\n#else /* K&R C */\n");
576
577				xdrfuncp = xdrfunc_head;
578				while (xdrfuncp != NULL){
579					print_xdr_func_def(xdrfuncp->name,
580	xdrfuncp->pointerp, i);
581					xdrfuncp = xdrfuncp->next;
582				}
583			}
584		f_print(fout, "\n#endif /* K&R C */\n");
585		}
586	}
587
588	if (extend && tell == ftell(fout)) {
589		(void) unlink(outfilename);
590	} else if (tblflag) {
591		f_print(fout, rpcgen_table_dcl);
592	}
593
594	if (Cflag){
595		f_print(fout, "\n#ifdef __cplusplus\n");
596		f_print(fout, "}\n");
597		f_print(fout, "#endif\n");
598	}
599
600	f_print(fout, "\n#endif /* !_%s */\n", guard);
601}
602
603/*
604 * Compile into an RPC service
605 */
606static void
607s_output(argc, argv, infile, define, extend, outfile, nomain, netflag)
608	int argc;
609	char *argv[];
610	char *infile;
611	char *define;
612	int extend;
613	char *outfile;
614	int nomain;
615	int netflag;
616{
617	char *include;
618	definition *def;
619	int foundprogram = 0;
620	char *outfilename;
621
622	open_input(infile, define);
623	outfilename = extend ? extendfile(infile, outfile) : outfile;
624	open_output(infile, outfilename);
625	add_warning();
626	if (infile && (include = extendfile(infile, ".h"))) {
627		f_print(fout, "#include \"%s\"\n", include);
628		free(include);
629	} else
630		f_print(fout, "#include <rpc/rpc.h>\n");
631
632	f_print(fout, "#include <stdio.h>\n");
633	f_print(fout, "#include <stdlib.h> /* getenv, exit */\n");
634	if (Cflag) {
635		f_print (fout,
636		"#include <rpc/pmap_clnt.h> /* for pmap_unset */\n");
637		f_print (fout, "#include <string.h> /* strcmp */\n");
638	}
639	if (strcmp(svcclosetime, "-1") == 0)
640		indefinitewait = 1;
641	else if (strcmp(svcclosetime, "0") == 0)
642		exitnow = 1;
643	else if (inetdflag || pmflag) {
644		f_print(fout, "#include <signal.h>\n");
645		timerflag = 1;
646	}
647
648	if (!tirpcflag && inetdflag)
649		f_print(fout, "#include <sys/ttycom.h> /* TIOCNOTTY */\n");
650	if (Cflag && (inetdflag || pmflag)) {
651		f_print(fout, "#ifdef __cplusplus\n");
652		f_print(fout,
653			"#include <sysent.h> /* getdtablesize, open */\n");
654		f_print(fout, "#endif /* __cplusplus */\n");
655	}
656	if (tirpcflag) {
657		f_print(fout, "#include <fcntl.h> /* open */\n");
658		f_print(fout, "#include <unistd.h> /* fork / setsid */\n");
659		f_print(fout, "#include <sys/types.h>\n");
660	}
661
662	f_print(fout, "#include <memory.h>\n");
663	if (inetdflag || !tirpcflag) {
664		f_print(fout, "#include <sys/socket.h>\n");
665		f_print(fout, "#include <netinet/in.h>\n");
666	}
667
668	if ((netflag || pmflag) && tirpcflag && !nomain) {
669		f_print(fout, "#include <netconfig.h>\n");
670	}
671	if (tirpcflag)
672		f_print(fout, "#include <sys/resource.h> /* rlimit */\n");
673	if (logflag || inetdflag || pmflag || tirpcflag)
674		f_print(fout, "#include <syslog.h>\n");
675
676	/* for ANSI-C */
677	if (Cflag)
678		f_print(fout,
679			"\n#ifndef SIG_PF\n#define	SIG_PF void(*)\
680(int)\n#endif\n");
681
682	f_print(fout, "\n#ifdef DEBUG\n#define	RPC_SVC_FG\n#endif\n");
683	if (timerflag)
684		f_print(fout, "\n#define	_RPCSVC_CLOSEDOWN %s\n",
685			svcclosetime);
686	while ( (def = get_definition()) ) {
687		foundprogram |= (def->def_kind == DEF_PROGRAM);
688	}
689	if (extend && !foundprogram) {
690		(void) unlink(outfilename);
691		return;
692	}
693	write_most(infile, netflag, nomain);
694	if (!nomain) {
695		if (!do_registers(argc, argv)) {
696			if (outfilename)
697				(void) unlink(outfilename);
698			usage();
699		}
700		write_rest();
701	}
702}
703
704/*
705 * generate client side stubs
706 */
707static void
708l_output(infile, define, extend, outfile)
709	char *infile;
710	char *define;
711	int extend;
712	char *outfile;
713{
714	char *include;
715	definition *def;
716	int foundprogram = 0;
717	char *outfilename;
718
719	open_input(infile, define);
720	outfilename = extend ? extendfile(infile, outfile) : outfile;
721	open_output(infile, outfilename);
722	add_warning();
723	if (Cflag)
724		f_print (fout, "#include <memory.h> /* for memset */\n");
725	if (infile && (include = extendfile(infile, ".h"))) {
726		f_print(fout, "#include \"%s\"\n", include);
727		free(include);
728	} else
729		f_print(fout, "#include <rpc/rpc.h>\n");
730	while ( (def = get_definition()) ) {
731		foundprogram |= (def->def_kind == DEF_PROGRAM);
732	}
733	if (extend && !foundprogram) {
734		(void) unlink(outfilename);
735		return;
736	}
737	write_stubs();
738}
739
740/*
741 * generate the dispatch table
742 */
743static void
744t_output(infile, define, extend, outfile)
745	char *infile;
746	char *define;
747	int extend;
748	char *outfile;
749{
750	definition *def;
751	int foundprogram = 0;
752	char *outfilename;
753
754	open_input(infile, define);
755	outfilename = extend ? extendfile(infile, outfile) : outfile;
756	open_output(infile, outfilename);
757	add_warning();
758	while ( (def = get_definition()) ) {
759		foundprogram |= (def->def_kind == DEF_PROGRAM);
760	}
761	if (extend && !foundprogram) {
762		(void) unlink(outfilename);
763		return;
764	}
765	write_tables();
766}
767
768/* sample routine for the server template */
769static void
770svc_output(infile, define, extend, outfile)
771	char *infile;
772	char *define;
773	int extend;
774	char *outfile;
775{
776	definition *def;
777	char *include;
778	char *outfilename;
779	long tell;
780	open_input(infile, define);
781	outfilename = extend ? extendfile(infile, outfile) : outfile;
782	checkfiles(infile, outfilename);
783	/*
784	 * Check if outfile already exists.
785	 * if so, print an error message and exit
786	 */
787	open_output(infile, outfilename);
788	add_sample_msg();
789
790	if (infile && (include = extendfile(infile, ".h"))) {
791		f_print(fout, "#include \"%s\"\n", include);
792		free(include);
793	} else
794		f_print(fout, "#include <rpc/rpc.h>\n");
795
796	tell = ftell(fout);
797	while ( (def = get_definition()) ) {
798		write_sample_svc(def);
799	}
800	if (extend && tell == ftell(fout)) {
801		(void) unlink(outfilename);
802	}
803}
804
805/* sample main routine for client */
806static void
807clnt_output(infile, define, extend, outfile)
808	char *infile;
809	char *define;
810	int extend;
811	char *outfile;
812{
813	definition *def;
814	char *include;
815	char *outfilename;
816	long tell;
817	int has_program = 0;
818
819	open_input(infile, define);
820	outfilename = extend ? extendfile(infile, outfile) : outfile;
821	checkfiles(infile, outfilename);
822	/*
823	 * Check if outfile already exists.
824	 * if so, print an error message and exit
825	 */
826
827	open_output(infile, outfilename);
828	add_sample_msg();
829	if (infile && (include = extendfile(infile, ".h"))) {
830		f_print(fout, "#include \"%s\"\n", include);
831		free(include);
832	} else
833		f_print(fout, "#include <rpc/rpc.h>\n");
834	tell = ftell(fout);
835	while ( (def = get_definition()) ) {
836		has_program += write_sample_clnt(def);
837	}
838
839	if (has_program)
840		write_sample_clnt_main();
841
842	if (extend && tell == ftell(fout)) {
843		(void) unlink(outfilename);
844	}
845}
846
847
848static void mkfile_output(cmd)
849struct commandline *cmd;
850{
851	char *mkfilename, *clientname, *clntname, *xdrname, *hdrname;
852	char *servername, *svcname, *servprogname, *clntprogname;
853	char *temp;
854
855	svcname = file_name(cmd->infile, "_svc.c");
856	clntname = file_name(cmd->infile, "_clnt.c");
857	xdrname = file_name(cmd->infile, "_xdr.c");
858	hdrname = file_name(cmd->infile, ".h");
859
860
861	if (allfiles){
862		servername = extendfile(cmd->infile, "_server.c");
863		clientname = extendfile(cmd->infile, "_client.c");
864	}else{
865		servername = " ";
866		clientname = " ";
867	}
868	servprogname = extendfile(cmd->infile, "_server");
869	clntprogname = extendfile(cmd->infile, "_client");
870
871	if (allfiles){
872		mkfilename = xmalloc(strlen("makefile.") +
873		                     strlen(cmd->infile) + 1);
874		temp = (char *)rindex(cmd->infile, '.');
875		strcat(mkfilename, "makefile.");
876		(void) strncat(mkfilename, cmd->infile,
877			(temp - cmd->infile));
878	} else
879		mkfilename = cmd->outfile;
880
881
882	checkfiles(NULL, mkfilename);
883	open_output(NULL, mkfilename);
884
885	f_print(fout, "\n# This is a template makefile generated\
886		by rpcgen \n");
887
888	f_print(fout, "\n# Parameters \n\n");
889
890	f_print(fout, "CLIENT = %s\nSERVER = %s\n\n",
891		clntprogname, servprogname);
892	f_print(fout, "SOURCES_CLNT.c = \nSOURCES_CLNT.h = \n");
893	f_print(fout, "SOURCES_SVC.c = \nSOURCES_SVC.h = \n");
894	f_print(fout, "SOURCES.x = %s\n\n", cmd->infile);
895	f_print(fout, "TARGETS_SVC.c = %s %s %s \n",
896		svcname, servername, xdrname);
897	f_print(fout, "TARGETS_CLNT.c = %s %s %s \n",
898		clntname, clientname, xdrname);
899	f_print(fout, "TARGETS = %s %s %s %s %s %s\n\n",
900		hdrname, xdrname, clntname,
901		svcname, clientname, servername);
902
903	f_print(fout, "OBJECTS_CLNT = $(SOURCES_CLNT.c:%%.c=%%.o) \
904$(TARGETS_CLNT.c:%%.c=%%.o) ");
905
906	f_print(fout, "\nOBJECTS_SVC = $(SOURCES_SVC.c:%%.c=%%.o) \
907$(TARGETS_SVC.c:%%.c=%%.o) ");
908
909
910	f_print(fout, "\n# Compiler flags \n");
911	if (mtflag)
912		f_print(fout, "\nCFLAGS += -D_REENTRANT -D_THEAD_SAFE \nLDLIBS += -pthread\n");
913
914	f_print(fout, "RPCGENFLAGS = \n");
915
916	f_print(fout, "\n# Targets \n\n");
917
918	f_print(fout, "all : $(CLIENT) $(SERVER)\n\n");
919	f_print(fout, "$(TARGETS) : $(SOURCES.x) \n");
920	f_print(fout, "\trpcgen $(RPCGENFLAGS) $(SOURCES.x)\n\n");
921	f_print(fout, "$(OBJECTS_CLNT) : $(SOURCES_CLNT.c) $(SOURCES_CLNT.h) \
922$(TARGETS_CLNT.c) \n\n");
923
924	f_print(fout, "$(OBJECTS_SVC) : $(SOURCES_SVC.c) $(SOURCES_SVC.h) \
925$(TARGETS_SVC.c) \n\n");
926	f_print(fout, "$(CLIENT) : $(OBJECTS_CLNT) \n");
927	f_print(fout, "\t$(CC) -o $(CLIENT) $(OBJECTS_CLNT) \
928$(LDLIBS) \n\n");
929	f_print(fout, "$(SERVER) : $(OBJECTS_SVC) \n");
930	f_print(fout, "\t$(CC) -o $(SERVER) $(OBJECTS_SVC) $(LDLIBS)\n\n ");
931	f_print(fout, "clean:\n\t $(RM) -f core $(TARGETS) $(OBJECTS_CLNT) \
932$(OBJECTS_SVC) $(CLIENT) $(SERVER)\n\n");
933}
934
935
936
937/*
938 * Perform registrations for service output
939 * Return 0 if failed; 1 otherwise.
940 */
941static int
942do_registers(argc, argv)
943	int argc;
944	char *argv[];
945{
946	int i;
947
948	if (inetdflag || !tirpcflag) {
949		for (i = 1; i < argc; i++) {
950			if (streq(argv[i], "-s")) {
951				if (!check_nettype(argv[i + 1],
952						    valid_i_nettypes))
953					return (0);
954				write_inetd_register(argv[i + 1]);
955				i++;
956			}
957		}
958	} else {
959		for (i = 1; i < argc; i++)
960			if (streq(argv[i], "-s")) {
961				if (!check_nettype(argv[i + 1],
962						    valid_ti_nettypes))
963					return (0);
964				write_nettype_register(argv[i + 1]);
965				i++;
966			} else if (streq(argv[i], "-n")) {
967				write_netid_register(argv[i + 1]);
968				i++;
969			}
970	}
971	return (1);
972}
973
974/*
975 * Add another argument to the arg list
976 */
977static void
978addarg(cp)
979	char *cp;
980{
981	if (argcount >= ARGLISTLEN) {
982		warnx("too many defines");
983		crash();
984		/*NOTREACHED*/
985	}
986	arglist[argcount++] = cp;
987
988}
989
990static void
991putarg(where, cp)
992	char *cp;
993	int where;
994{
995	if (where >= ARGLISTLEN) {
996		warnx("arglist coding error");
997		crash();
998		/*NOTREACHED*/
999	}
1000	arglist[where] = cp;
1001}
1002
1003/*
1004 * if input file is stdin and an output file is specified then complain
1005 * if the file already exists. Otherwise the file may get overwritten
1006 * If input file does not exist, exit with an error
1007 */
1008
1009static void
1010checkfiles(infile, outfile)
1011char *infile;
1012char *outfile;
1013{
1014
1015	struct stat buf;
1016
1017	if (infile)		/* infile ! = NULL */
1018		if (stat(infile, &buf) < 0)
1019		{
1020			warn("%s", infile);
1021			crash();
1022		};
1023	if (outfile) {
1024		if (stat(outfile, &buf) < 0)
1025			return;	/* file does not exist */
1026		else {
1027			warnx("file '%s' already exists and may be overwritten", outfile);
1028			crash();
1029		}
1030	}
1031}
1032
1033/*
1034 * Parse command line arguments
1035 */
1036static int
1037parseargs(argc, argv, cmd)
1038	int argc;
1039	char *argv[];
1040	struct commandline *cmd;
1041{
1042	int i;
1043	int j;
1044	char c, ch;
1045	char flag[(1 << 8 * sizeof (char))];
1046	int nflags;
1047
1048	cmd->infile = cmd->outfile = NULL;
1049	if (argc < 2) {
1050		return (0);
1051	}
1052	allfiles = 0;
1053	flag['c'] = 0;
1054	flag['h'] = 0;
1055	flag['l'] = 0;
1056	flag['m'] = 0;
1057	flag['o'] = 0;
1058	flag['s'] = 0;
1059	flag['n'] = 0;
1060	flag['t'] = 0;
1061	flag['S'] = 0;
1062	flag['C'] = 0;
1063	flag['M'] = 0;
1064
1065	for (i = 1; i < argc; i++) {
1066		if (argv[i][0] != '-') {
1067			if (cmd->infile) {
1068				warnx("cannot specify more than one input file");
1069				return (0);
1070			}
1071			cmd->infile = argv[i];
1072		} else {
1073			for (j = 1; argv[i][j] != 0; j++) {
1074				c = argv[i][j];
1075				switch (c) {
1076				case 'a':
1077					allfiles = 1;
1078					break;
1079				case 'c':
1080				case 'h':
1081				case 'l':
1082				case 'm':
1083				case 't':
1084					if (flag[(int)c]) {
1085						return (0);
1086					}
1087					flag[(int)c] = 1;
1088					break;
1089				case 'S':
1090					/*
1091					 * sample flag: Ss or Sc.
1092					 *  Ss means set flag['S'];
1093					 *  Sc means set flag['C'];
1094					 *  Sm means set flag['M'];
1095					 */
1096					ch = argv[i][++j]; /* get next char */
1097					if (ch == 's')
1098						ch = 'S';
1099					else if (ch == 'c')
1100						ch = 'C';
1101					else if (ch == 'm')
1102						ch = 'M';
1103					else
1104						return (0);
1105
1106					if (flag[(int)ch]) {
1107						return (0);
1108					}
1109					flag[(int)ch] = 1;
1110					break;
1111				case 'C': /* ANSI C syntax */
1112					Cflag = 1;
1113					ch = argv[i][j+1]; /* get next char */
1114
1115					if (ch != 'C')
1116						break;
1117					CCflag = 1;
1118					break;
1119				case 'b':
1120					/*
1121					 *  Turn TIRPC flag off for
1122					 *  generating backward compatible
1123					 *  code
1124					 */
1125					tirpcflag = 0;
1126					break;
1127
1128				case 'I':
1129					inetdflag = 1;
1130					break;
1131				case 'N':
1132					newstyle = 1;
1133					break;
1134				case 'L':
1135					logflag = 1;
1136					break;
1137				case 'P':
1138					pmflag = 1;
1139					break;
1140				case 'K':
1141					if (++i == argc) {
1142						return (0);
1143					}
1144					svcclosetime = argv[i];
1145					goto nextarg;
1146				case 'T':
1147					tblflag = 1;
1148					break;
1149				case 'M':
1150					mtflag = 1;
1151					break;
1152				case 'i' :
1153					if (++i == argc) {
1154						return (0);
1155					}
1156					inline = atoi(argv[i]);
1157					goto nextarg;
1158				case 'n':
1159				case 'o':
1160				case 's':
1161					if (argv[i][j - 1] != '-' ||
1162					    argv[i][j + 1] != 0) {
1163						return (0);
1164					}
1165					flag[(int)c] = 1;
1166					if (++i == argc) {
1167						return (0);
1168					}
1169					if (c == 'o') {
1170						if (cmd->outfile) {
1171							return (0);
1172						}
1173						cmd->outfile = argv[i];
1174					}
1175					goto nextarg;
1176				case 'D':
1177					if (argv[i][j - 1] != '-') {
1178						return (0);
1179					}
1180					(void) addarg(argv[i]);
1181					goto nextarg;
1182				case 'Y':
1183					if (++i == argc) {
1184						return (0);
1185					}
1186					(void) strlcpy(pathbuf, argv[i], sizeof(pathbuf));
1187					if (strlcat(pathbuf, "/cpp", sizeof(pathbuf))
1188					    >= sizeof(pathbuf)) {
1189						warnx("argument too long");
1190						return (0);
1191					}
1192					CPP = pathbuf;
1193					cppDefined = 1;
1194					goto nextarg;
1195
1196
1197
1198				default:
1199					return (0);
1200				}
1201			}
1202		nextarg:
1203			;
1204		}
1205	}
1206
1207	cmd->cflag = flag['c'];
1208	cmd->hflag = flag['h'];
1209	cmd->lflag = flag['l'];
1210	cmd->mflag = flag['m'];
1211	cmd->nflag = flag['n'];
1212	cmd->sflag = flag['s'];
1213	cmd->tflag = flag['t'];
1214	cmd->Ssflag = flag['S'];
1215	cmd->Scflag = flag['C'];
1216	cmd->makefileflag = flag['M'];
1217
1218	if (tirpcflag) {
1219		if (inetdflag)
1220			pmflag = 0;
1221		if ((inetdflag && cmd->nflag)) {
1222			/* netid not allowed with inetdflag */
1223			warnx("cannot use netid flag with inetd flag");
1224			return (0);
1225		}
1226	} else {		/* 4.1 mode */
1227		pmflag = 0;	/* set pmflag only in tirpcmode */
1228		if (cmd->nflag) { /* netid needs TIRPC */
1229			warnx("cannot use netid flag without TIRPC");
1230			return (0);
1231		}
1232	}
1233
1234	if (newstyle && (tblflag || cmd->tflag)) {
1235		warnx("cannot use table flags with newstyle");
1236		return (0);
1237	}
1238
1239	/* check no conflicts with file generation flags */
1240	nflags = cmd->cflag + cmd->hflag + cmd->lflag + cmd->mflag +
1241		cmd->sflag + cmd->nflag + cmd->tflag + cmd->Ssflag +
1242			cmd->Scflag + cmd->makefileflag;
1243
1244	if (nflags == 0) {
1245		if (cmd->outfile != NULL || cmd->infile == NULL) {
1246			return (0);
1247		}
1248	} else if (cmd->infile == NULL &&
1249	    (cmd->Ssflag || cmd->Scflag || cmd->makefileflag)) {
1250		warnx("\"infile\" is required for template generation flags");
1251		return (0);
1252	} if (nflags > 1) {
1253		warnx("cannot have more than one file generation flag");
1254		return (0);
1255	}
1256	return (1);
1257}
1258
1259static void
1260usage()
1261{
1262	f_print(stderr, "%s\n%s\n%s\n%s\n%s\n",
1263		"usage: rpcgen infile",
1264		"       rpcgen [-abCLNTM] [-Dname[=value]] [-i size]\
1265[-I -P [-K seconds]] [-Y path] infile",
1266		"       rpcgen [-c | -h | -l | -m | -t | -Sc | -Ss | -Sm]\
1267[-o outfile] [infile]",
1268		"       rpcgen [-s nettype]* [-o outfile] [infile]",
1269		"       rpcgen [-n netid]* [-o outfile] [infile]");
1270	options_usage();
1271	exit(1);
1272}
1273
1274static void
1275options_usage()
1276{
1277	f_print(stderr, "options:\n");
1278	f_print(stderr, "-a\t\tgenerate all files, including samples\n");
1279	f_print(stderr, "-b\t\tbackward compatibility mode (generates code \
1280for FreeBSD 4.X)\n");
1281	f_print(stderr, "-c\t\tgenerate XDR routines\n");
1282	f_print(stderr, "-C\t\tANSI C mode\n");
1283	f_print(stderr, "-Dname[=value]\tdefine a symbol (same as #define)\n");
1284	f_print(stderr, "-h\t\tgenerate header file\n");
1285	f_print(stderr, "-i size\t\tsize at which to start generating\
1286inline code\n");
1287	f_print(stderr, "-I\t\tgenerate code for inetd support in server\n");
1288	f_print(stderr, "-K seconds\tserver exits after K seconds of\
1289inactivity\n");
1290	f_print(stderr, "-l\t\tgenerate client side stubs\n");
1291	f_print(stderr, "-L\t\tserver errors will be printed to syslog\n");
1292	f_print(stderr, "-m\t\tgenerate server side stubs\n");
1293	f_print(stderr, "-M\t\tgenerate MT-safe code\n");
1294	f_print(stderr, "-n netid\tgenerate server code that supports\
1295named netid\n");
1296	f_print(stderr, "-N\t\tsupports multiple arguments and\
1297call-by-value\n");
1298	f_print(stderr, "-o outfile\tname of the output file\n");
1299	f_print(stderr, "-P\t\tgenerate code for port monitoring support in server\n");
1300	f_print(stderr, "-s nettype\tgenerate server code that supports named\
1301nettype\n");
1302	f_print(stderr, "-Sc\t\tgenerate sample client code that uses remote\
1303procedures\n");
1304	f_print(stderr, "-Ss\t\tgenerate sample server code that defines\
1305remote procedures\n");
1306	f_print(stderr, "-Sm \t\tgenerate makefile template \n");
1307
1308	f_print(stderr, "-t\t\tgenerate RPC dispatch table\n");
1309	f_print(stderr, "-T\t\tgenerate code to support RPC dispatch tables\n");
1310	f_print(stderr, "-Y path\t\tpath where cpp is found\n");
1311	exit(1);
1312}
1313