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