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