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