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