xref: /openbsd-src/usr.bin/rpcgen/rpc_main.c (revision 7bbe964f6b7d22ad07ca46292495604f942eba4e)
1 /* $OpenBSD: rpc_main.c,v 1.24 2009/10/27 23:59:42 deraadt Exp $	 */
2 /* $NetBSD: rpc_main.c,v 1.9 1996/02/19 11:12:43 pk Exp $	 */
3 /*
4  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5  * unrestricted use provided that this legend is included on all tape
6  * media and as a part of the software program in whole or part.  Users
7  * may copy or modify Sun RPC without charge, but are not authorized
8  * to license or distribute it to anyone else except as part of a product or
9  * program developed by the user or with the express written consent of
10  * Sun Microsystems, Inc.
11  *
12  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
13  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
14  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
15  *
16  * Sun RPC is provided with no support and without any obligation on the
17  * part of Sun Microsystems, Inc. to assist in its use, correction,
18  * modification or enhancement.
19  *
20  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
21  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
22  * OR ANY PART THEREOF.
23  *
24  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
25  * or profits or other special, indirect and consequential damages, even if
26  * Sun has been advised of the possibility of such damages.
27  *
28  * Sun Microsystems, Inc.
29  * 2550 Garcia Avenue
30  * Mountain View, California  94043
31  */
32 
33 /*
34  * rpc_main.c, Top level of the RPC protocol compiler.
35  */
36 
37 #define RPCGEN_VERSION	"199506"/* This program's version (year & month) */
38 
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <sys/file.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <stdlib.h>
47 #include <ctype.h>
48 #include <sys/stat.h>
49 #include "rpc_parse.h"
50 #include "rpc_util.h"
51 #include "rpc_scan.h"
52 
53 #define EXTEND	1		/* alias for TRUE */
54 #define DONT_EXTEND	0	/* alias for FALSE */
55 
56 #define SVR4_CPP "/usr/ccs/lib/cpp"
57 #define SUNOS_CPP "/lib/cpp"
58 static int      cppDefined = 0;	/* explicit path for C preprocessor */
59 
60 struct commandline {
61 	int cflag;	/* xdr C routines */
62 	int hflag;	/* header file */
63 	int lflag;	/* client side stubs */
64 	int mflag;	/* server side stubs */
65 	int nflag;	/* netid flag */
66 	int sflag;	/* server stubs for the given transport */
67 	int tflag;	/* dispatch Table file */
68 	int Ssflag;	/* produce server sample code */
69 	int Scflag;	/* produce client sample code */
70 	char *infile;	/* input module name */
71 	char *outfile;/* output module name */
72 };
73 
74 static char    *cmdname;
75 
76 static char    *svcclosetime = "120";
77 static char    *CPP = "/usr/bin/cpp";
78 static char     CPPFLAGS[] = "-C";
79 static char     pathbuf[MAXPATHLEN];
80 static char    *allv[] = {
81 	"rpcgen", "-s", "udp", "-s", "tcp",
82 };
83 static int      allc = sizeof(allv) / sizeof(allv[0]);
84 static char    *allnv[] = {
85 	"rpcgen", "-s", "netpath",
86 };
87 static int      allnc = sizeof(allnv) / sizeof(allnv[0]);
88 
89 #define ARGLISTLEN	20
90 #define FIXEDARGS         2
91 
92 static char    *arglist[ARGLISTLEN];
93 static int      argcount = FIXEDARGS;
94 
95 
96 int             nonfatalerrors;	/* errors */
97 int             inetdflag /* = 1 */ ;	/* Support for inetd *//* is now the
98 					 * default */
99 int             pmflag;		/* Support for port monitors */
100 int             logflag;	/* Use syslog instead of fprintf for errors */
101 int             tblflag;	/* Support for dispatch table file */
102 int             callerflag;	/* Generate svc_caller() function */
103 
104 #define INLINE 3
105 /* length at which to start doing an inline */
106 
107 int doinline = INLINE;	/* length at which to start doing an
108 			 * inline. 3 = default if 0, no
109 			 * xdr_inline code */
110 
111 int indefinitewait;	/* If started by port monitors, hang till it
112 			 * wants */
113 int exitnow;	/* If started by port monitors, exit after
114 		 * the call */
115 int timerflag;	/* TRUE if !indefinite && !exitnow */
116 int newstyle;	/* newstyle of passing arguments (by value) */
117 int Cflag = 0;	/* ANSI C syntax */
118 static int allfiles;	/* generate all files */
119 int tirpcflag = 0;	/* generating code for tirpc, by default */
120 
121 static void c_output(char *, char *, int, char *);
122 static void h_output(char *, char *, int, char *);
123 static void s_output(int, char **, char *, char *, int, char *, int, int);
124 static void l_output(char *, char *, int, char *);
125 static void t_output(char *, char *, int, char *);
126 static void svc_output(char *, char *, int, char *);
127 static void clnt_output(char *, char *, int, char *);
128 static int do_registers(int, char **);
129 static void addarg(char *);
130 static void putarg(int, char *);
131 static void clear_args(void);
132 static void checkfiles(char *, char *);
133 static int parseargs(int, char **, struct commandline *);
134 static void usage(void);
135 void c_initialize(void);
136 
137 int
138 main(int argc, char *argv[])
139 {
140 	struct commandline cmd;
141 
142 	(void) memset((char *) &cmd, 0, sizeof(struct commandline));
143 	clear_args();
144 	if (!parseargs(argc, argv, &cmd))
145 		usage();
146 
147 	if (cmd.cflag || cmd.hflag || cmd.lflag || cmd.tflag || cmd.sflag ||
148 	    cmd.mflag || cmd.nflag || cmd.Ssflag || cmd.Scflag) {
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 	} else if (cmd.lflag) {
158 		l_output(cmd.infile, "-DRPC_CLNT", DONT_EXTEND, cmd.outfile);
159 	} else if (cmd.sflag || cmd.mflag || (cmd.nflag)) {
160 		s_output(argc, argv, cmd.infile, "-DRPC_SVC", DONT_EXTEND,
161 			 cmd.outfile, cmd.mflag, cmd.nflag);
162 	} else if (cmd.tflag) {
163 		t_output(cmd.infile, "-DRPC_TBL", DONT_EXTEND, cmd.outfile);
164 	} else if (cmd.Ssflag) {
165 		svc_output(cmd.infile, "-DRPC_SERVER", DONT_EXTEND, cmd.outfile);
166 	} else if (cmd.Scflag) {
167 		clnt_output(cmd.infile, "-DRPC_CLIENT", DONT_EXTEND, cmd.outfile);
168 	} else {
169 		/* the rescans are required, since cpp may effect input */
170 		c_output(cmd.infile, "-DRPC_XDR", EXTEND, "_xdr.c");
171 		reinitialize();
172 		h_output(cmd.infile, "-DRPC_HDR", EXTEND, ".h");
173 		reinitialize();
174 		l_output(cmd.infile, "-DRPC_CLNT", EXTEND, "_clnt.c");
175 		reinitialize();
176 		if (inetdflag || !tirpcflag)
177 			s_output(allc, allv, cmd.infile, "-DRPC_SVC", EXTEND,
178 			    "_svc.c", cmd.mflag, cmd.nflag);
179 		else
180 			s_output(allnc, allnv, cmd.infile, "-DRPC_SVC",
181 			    EXTEND, "_svc.c", cmd.mflag, cmd.nflag);
182 		if (tblflag) {
183 			reinitialize();
184 			t_output(cmd.infile, "-DRPC_TBL", EXTEND, "_tbl.i");
185 		}
186 		if (allfiles) {
187 			reinitialize();
188 			svc_output(cmd.infile, "-DRPC_SERVER", EXTEND, "_server.c");
189 		}
190 		if (allfiles) {
191 			reinitialize();
192 			clnt_output(cmd.infile, "-DRPC_CLIENT", EXTEND, "_client.c");
193 		}
194 	}
195 	exit(nonfatalerrors);
196 	/* NOTREACHED */
197 }
198 
199 /*
200  * add extension to filename
201  */
202 static char *
203 extendfile(char *path, char *ext)
204 {
205 	char *file;
206 	char *res;
207 	char *p;
208 	size_t len;
209 
210 	if ((file = strrchr(path, '/')) == NULL)
211 		file = path;
212 	else
213 		file++;
214 
215 	len = strlen(file) + strlen(ext) + 1;
216 	res = alloc(len);
217 	if (res == NULL) {
218 		fprintf(stderr, "could not allocate memory\n");
219 		exit(1);
220 	}
221 	p = strrchr(file, '.');
222 	if (p == NULL)
223 		p = file + strlen(file);
224 	(void) strlcpy(res, file, len);
225 	(void) strlcpy(res + (p - file), ext, len - (p - file));
226 	return (res);
227 }
228 
229 /*
230  * Open output file with given extension
231  */
232 static void
233 open_output(char *infile, char *outfile)
234 {
235 
236 	if (outfile == NULL) {
237 		fout = stdout;
238 		return;
239 	}
240 	if (infile != NULL && streq(outfile, infile)) {
241 		fprintf(stderr, "%s: output would overwrite %s\n", cmdname,
242 		    infile);
243 		crash();
244 	}
245 	fout = fopen(outfile, "w");
246 	if (fout == NULL) {
247 		fprintf(stderr, "%s: unable to open ", cmdname);
248 		perror(outfile);
249 		crash();
250 	}
251 	record_open(outfile);
252 
253 }
254 
255 static void
256 add_warning(void)
257 {
258 	fprintf(fout, "/*\n");
259 	fprintf(fout, " * Please do not edit this file.\n");
260 	fprintf(fout, " * It was generated using rpcgen.\n");
261 	fprintf(fout, " */\n\n");
262 }
263 
264 /* clear list of arguments */
265 static void
266 clear_args(void)
267 {
268 	int             i;
269 	for (i = FIXEDARGS; i < ARGLISTLEN; i++)
270 		arglist[i] = NULL;
271 	argcount = FIXEDARGS;
272 }
273 
274 /* make sure that a CPP exists */
275 static void
276 find_cpp(void)
277 {
278 	struct stat     buf;
279 
280 	/* SVR4 or explicit cpp does not exist */
281 	if (stat(CPP, &buf) < 0) {
282 		if (cppDefined) {
283 			fprintf(stderr, "cannot find C preprocessor: %s \n", CPP);
284 			crash();
285 		} else {
286 			/* try the other one */
287 			CPP = SUNOS_CPP;
288 			if (stat(CPP, &buf) < 0) {	/* can't find any cpp */
289 				fprintf(stderr,
290 				    "cannot find any C preprocessor: %s\n", CPP);
291 				crash();
292 			}
293 		}
294 	}
295 }
296 
297 /*
298  * Open input file with given define for C-preprocessor
299  */
300 static void
301 open_input(char *infile, char *define)
302 {
303 	int             pd[2];
304 
305 	infilename = (infile == NULL) ? "<stdin>" : infile;
306 	(void) pipe(pd);
307 	switch (fork()) {
308 	case 0:
309 		find_cpp();
310 		putarg(0, CPP);
311 		putarg(1, CPPFLAGS);
312 		addarg(define);
313 		addarg(infile);
314 		addarg((char *) NULL);
315 		(void) close(1);
316 		(void) dup2(pd[1], 1);
317 		(void) close(pd[0]);
318 		execv(arglist[0], arglist);
319 		perror("execv");
320 		exit(1);
321 	case -1:
322 		perror("fork");
323 		exit(1);
324 	}
325 	(void) close(pd[1]);
326 	fin = fdopen(pd[0], "r");
327 	if (fin == NULL) {
328 		fprintf(stderr, "%s: ", cmdname);
329 		perror(infilename);
330 		crash();
331 	}
332 }
333 
334 /* valid tirpc nettypes */
335 static char    *valid_ti_nettypes[] = {
336 	"netpath",
337 	"visible",
338 	"circuit_v",
339 	"datagram_v",
340 	"circuit_n",
341 	"datagram_n",
342 	"udp",
343 	"tcp",
344 	"raw",
345 	NULL
346 };
347 
348 /* valid inetd nettypes */
349 static char    *valid_i_nettypes[] = {
350 	"udp",
351 	"tcp",
352 	NULL
353 };
354 
355 static int
356 check_nettype(char *name, char *list_to_check[])
357 {
358 	int             i;
359 	for (i = 0; list_to_check[i] != NULL; i++) {
360 		if (strcmp(name, list_to_check[i]) == 0)
361 			return 1;
362 	}
363 	fprintf(stderr, "illegal nettype :\'%s\'\n", name);
364 	return 0;
365 }
366 
367 /*
368  * Compile into an XDR routine output file
369  */
370 
371 static void
372 c_output(infile, define, extend, outfile)
373 	char           *infile;
374 	char           *define;
375 	int             extend;
376 	char           *outfile;
377 {
378 	definition     *def;
379 	char           *include;
380 	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 		fprintf(fout, "#include \"%s\"\n", include);
390 		free(include);
391 		/* .h file already contains rpc/rpc.h */
392 	} else
393 		fprintf(fout, "#include <rpc/rpc.h>\n");
394 	tell = ftell(fout);
395 	while ((def = get_definition())) {
396 		emit(def);
397 	}
398 	if (extend && tell == ftell(fout)) {
399 		(void) unlink(outfilename);
400 	}
401 }
402 
403 
404 void
405 c_initialize(void)
406 {
407 
408 	/* add all the starting basic types */
409 
410 	add_type(1, "int");
411 	add_type(1, "long");
412 	add_type(1, "short");
413 	add_type(1, "bool");
414 
415 	add_type(1, "u_int");
416 	add_type(1, "u_long");
417 	add_type(1, "u_short");
418 
419 }
420 
421 char            rpcgen_table_dcl[] = "struct rpcgen_table {\n\
422 	char	*(*proc)();\n\
423 	xdrproc_t	xdr_arg;\n\
424 	unsigned int	len_arg;\n\
425 	xdrproc_t	xdr_res;\n\
426 	unsigned int	len_res;\n\
427 };\n";
428 
429 
430 static char *
431 generate_guard(char *pathname)
432 {
433 	char           *filename, *guard, *tmp, *tmp2;
434 
435 	filename = strrchr(pathname, '/');	/* find last component */
436 	filename = ((filename == 0) ? pathname : filename + 1);
437 	guard = strdup(filename);
438 	if (guard == NULL) {
439 		fprintf(stderr, "out of memory while processing %s\n", filename);
440 		crash();
441 	}
442 
443 	/* convert to upper case */
444 	tmp = guard;
445 	while (*tmp) {
446 		if (islower(*tmp))
447 			*tmp = toupper(*tmp);
448 		tmp++;
449 	}
450 
451 	tmp2 = extendfile(guard, "_H_RPCGEN");
452 	free(guard);
453 	guard = tmp2;
454 
455 	return (guard);
456 }
457 
458 /*
459  * Compile into an XDR header file
460  */
461 
462 static void
463 h_output(infile, define, extend, outfile)
464 	char           *infile;
465 	char           *define;
466 	int             extend;
467 	char           *outfile;
468 {
469 	definition     *def;
470 	char           *outfilename;
471 	long            tell;
472 	char           *guard;
473 	list           *l;
474 
475 	open_input(infile, define);
476 	outfilename = extend ? extendfile(infile, outfile) : outfile;
477 	open_output(infile, outfilename);
478 	add_warning();
479 	guard = generate_guard(outfilename ? outfilename : infile);
480 
481 	fprintf(fout, "#ifndef _%s\n#define _%s\n\n", guard,
482 		guard);
483 
484 	fprintf(fout, "#define RPCGEN_VERSION\t%s\n\n", RPCGEN_VERSION);
485 	fprintf(fout, "#include <rpc/rpc.h>\n\n");
486 
487 	tell = ftell(fout);
488 	/* print data definitions */
489 	while ((def = get_definition())) {
490 		print_datadef(def);
491 	}
492 
493 	/*
494 	 * print function declarations. Do this after data definitions
495 	 * because they might be used as arguments for functions
496 	 */
497 	for (l = defined; l != NULL; l = l->next) {
498 		print_funcdef(l->val);
499 	}
500 	if (extend && tell == ftell(fout)) {
501 		(void) unlink(outfilename);
502 	} else if (tblflag) {
503 		fprintf(fout, rpcgen_table_dcl);
504 	}
505 	fprintf(fout, "\n#endif /* !_%s */\n", guard);
506 
507 	free(guard);
508 }
509 
510 /*
511  * Compile into an RPC service
512  */
513 static void
514 s_output(argc, argv, infile, define, extend, outfile, nomain, netflag)
515 	int             argc;
516 	char           *argv[];
517 	char           *infile;
518 	char           *define;
519 	int             extend;
520 	char           *outfile;
521 	int             nomain;
522 	int             netflag;
523 {
524 	char           *include;
525 	definition     *def;
526 	int             foundprogram = 0;
527 	char           *outfilename;
528 
529 	open_input(infile, define);
530 	outfilename = extend ? extendfile(infile, outfile) : outfile;
531 	open_output(infile, outfilename);
532 	add_warning();
533 	if (infile && (include = extendfile(infile, ".h"))) {
534 		fprintf(fout, "#include \"%s\"\n", include);
535 		free(include);
536 	} else
537 		fprintf(fout, "#include <rpc/rpc.h>\n");
538 
539 	fprintf(fout, "#include <unistd.h>\n");
540 	fprintf(fout, "#include <stdio.h>\n");
541 	fprintf(fout, "#include <stdlib.h>/* getenv, exit */\n");
542 	if (Cflag) {
543 		fprintf(fout,
544 			"#include <rpc/pmap_clnt.h> /* for pmap_unset */\n");
545 		fprintf(fout, "#include <string.h> /* strcmp */ \n");
546 	}
547 	fprintf(fout, "#include <netdb.h>\n");	/* evas */
548 	if (strcmp(svcclosetime, "-1") == 0)
549 		indefinitewait = 1;
550 	else if (strcmp(svcclosetime, "0") == 0)
551 		exitnow = 1;
552 	else if (inetdflag || pmflag) {
553 		fprintf(fout, "#include <signal.h>\n");
554 		timerflag = 1;
555 	}
556 	if (!tirpcflag && inetdflag)
557 		fprintf(fout, "#include <sys/ttycom.h>/* TIOCNOTTY */\n");
558 	if (Cflag && (inetdflag || pmflag)) {
559 		fprintf(fout, "#ifdef __cplusplus\n");
560 		fprintf(fout, "#include <sysent.h> /* getdtablesize, open */\n");
561 		fprintf(fout, "#endif /* __cplusplus */\n");
562 
563 		if (tirpcflag)
564 			fprintf(fout, "#include <unistd.h> /* setsid */\n");
565 	}
566 	if (tirpcflag)
567 		fprintf(fout, "#include <sys/types.h>\n");
568 
569 	fprintf(fout, "#include <memory.h>\n");
570 	if (tirpcflag)
571 		fprintf(fout, "#include <stropts.h>\n");
572 
573 	if (inetdflag || !tirpcflag) {
574 		fprintf(fout, "#include <sys/socket.h>\n");
575 		fprintf(fout, "#include <netinet/in.h>\n");
576 	}
577 	if ((netflag || pmflag) && tirpcflag) {
578 		fprintf(fout, "#include <netconfig.h>\n");
579 	}
580 	if (/* timerflag && */ tirpcflag)
581 		fprintf(fout, "#include <sys/resource.h> /* rlimit */\n");
582 	if (logflag || inetdflag || pmflag) {
583 		fprintf(fout, "#include <syslog.h>\n");
584 		fprintf(fout, "#include <errno.h>\n");
585 	}
586 	/* for ANSI-C */
587 	fprintf(fout, "\n#ifdef __STDC__\n#define SIG_PF void(*)(int)\n#endif\n");
588 
589 	fprintf(fout, "\n#ifdef DEBUG\n#define RPC_SVC_FG\n#endif\n");
590 	if (timerflag)
591 		fprintf(fout, "\n#define _RPCSVC_CLOSEDOWN %s\n", svcclosetime);
592 	while ((def = get_definition())) {
593 		foundprogram |= (def->def_kind == DEF_PROGRAM);
594 	}
595 	if (extend && !foundprogram) {
596 		(void) unlink(outfilename);
597 		return;
598 	}
599 	if (callerflag)		/* EVAS */
600 		fprintf(fout, "\nstatic SVCXPRT *caller;\n");	/* EVAS */
601 	write_most(infile, netflag, nomain);
602 	if (!nomain) {
603 		if (!do_registers(argc, argv)) {
604 			if (outfilename)
605 				(void) unlink(outfilename);
606 			usage();
607 		}
608 		write_rest();
609 	}
610 }
611 
612 /*
613  * generate client side stubs
614  */
615 static void
616 l_output(infile, define, extend, outfile)
617 	char           *infile;
618 	char           *define;
619 	int             extend;
620 	char           *outfile;
621 {
622 	char           *include;
623 	definition     *def;
624 	int             foundprogram = 0;
625 	char           *outfilename;
626 
627 	open_input(infile, define);
628 	outfilename = extend ? extendfile(infile, outfile) : outfile;
629 	open_output(infile, outfilename);
630 	add_warning();
631 	if (Cflag)
632 		fprintf(fout, "#include <memory.h> /* for memset */\n");
633 	if (infile && (include = extendfile(infile, ".h"))) {
634 		fprintf(fout, "#include \"%s\"\n", include);
635 		free(include);
636 	} else
637 		fprintf(fout, "#include <rpc/rpc.h>\n");
638 	while ((def = get_definition()))
639 		foundprogram |= (def->def_kind == DEF_PROGRAM);
640 
641 	if (extend && !foundprogram) {
642 		(void) unlink(outfilename);
643 		return;
644 	}
645 	write_stubs();
646 }
647 
648 /*
649  * generate the dispatch table
650  */
651 static void
652 t_output(infile, define, extend, outfile)
653 	char           *infile;
654 	char           *define;
655 	int             extend;
656 	char           *outfile;
657 {
658 	definition     *def;
659 	int             foundprogram = 0;
660 	char           *outfilename;
661 
662 	open_input(infile, define);
663 	outfilename = extend ? extendfile(infile, outfile) : outfile;
664 	open_output(infile, outfilename);
665 	add_warning();
666 	while ((def = get_definition()))
667 		foundprogram |= (def->def_kind == DEF_PROGRAM);
668 
669 	if (extend && !foundprogram) {
670 		(void) unlink(outfilename);
671 		return;
672 	}
673 	write_tables();
674 }
675 
676 /* sample routine for the server template */
677 static void
678 svc_output(infile, define, extend, outfile)
679 	char           *infile;
680 	char           *define;
681 	int             extend;
682 	char           *outfile;
683 {
684 	definition     *def;
685 	char           *include;
686 	char           *outfilename;
687 	long            tell;
688 
689 	open_input(infile, define);
690 	outfilename = extend ? extendfile(infile, outfile) : outfile;
691 	checkfiles(infile, outfilename);	/* check if outfile already
692 						 * exists. if so, print an
693 						 * error message and exit */
694 	open_output(infile, outfilename);
695 	add_sample_msg();
696 
697 	if (infile && (include = extendfile(infile, ".h"))) {
698 		fprintf(fout, "#include \"%s\"\n", include);
699 		free(include);
700 	} else
701 		fprintf(fout, "#include <rpc/rpc.h>\n");
702 
703 	tell = ftell(fout);
704 	while ((def = get_definition()))
705 		write_sample_svc(def);
706 
707 	if (extend && tell == ftell(fout))
708 		(void) unlink(outfilename);
709 }
710 
711 
712 /* sample main routine for client */
713 static void
714 clnt_output(infile, define, extend, outfile)
715 	char           *infile;
716 	char           *define;
717 	int             extend;
718 	char           *outfile;
719 {
720 	definition *def;
721 	char *include, *outfilename;
722 	long tell;
723 	int has_program = 0;
724 
725 	open_input(infile, define);
726 	outfilename = extend ? extendfile(infile, outfile) : outfile;
727 
728 	/*
729 	 * check if outfile already exists. if so,
730 	 * print an error message and exit
731 	 */
732 	checkfiles(infile, outfilename);
733 
734 	open_output(infile, outfilename);
735 	add_sample_msg();
736 	if (infile && (include = extendfile(infile, ".h"))) {
737 		fprintf(fout, "#include \"%s\"\n", include);
738 		free(include);
739 	} else
740 		fprintf(fout, "#include <rpc/rpc.h>\n");
741 	tell = ftell(fout);
742 	while ((def = get_definition()))
743 		has_program += write_sample_clnt(def);
744 
745 	if (has_program)
746 		write_sample_clnt_main();
747 
748 	if (extend && tell == ftell(fout))
749 		(void) unlink(outfilename);
750 }
751 
752 /*
753  * Perform registrations for service output
754  * Return 0 if failed; 1 otherwise.
755  */
756 static int
757 do_registers(argc, argv)
758 	int             argc;
759 	char           *argv[];
760 {
761 	int             i;
762 
763 	if (inetdflag || !tirpcflag) {
764 		for (i = 1; i < argc; i++) {
765 			if (streq(argv[i], "-s")) {
766 				if (!check_nettype(argv[i + 1], valid_i_nettypes))
767 					return 0;
768 				write_inetd_register(argv[i + 1]);
769 				i++;
770 			}
771 		}
772 	} else {
773 		for (i = 1; i < argc; i++)
774 			if (streq(argv[i], "-s")) {
775 				if (!check_nettype(argv[i + 1], valid_ti_nettypes))
776 					return 0;
777 				write_nettype_register(argv[i + 1]);
778 				i++;
779 			} else if (streq(argv[i], "-n")) {
780 				write_netid_register(argv[i + 1]);
781 				i++;
782 			}
783 	}
784 	return 1;
785 }
786 
787 /*
788  * Add another argument to the arg list
789  */
790 static void
791 addarg(cp)
792 	char           *cp;
793 {
794 	if (argcount >= ARGLISTLEN) {
795 		fprintf(stderr, "rpcgen: too many defines\n");
796 		crash();
797 		/* NOTREACHED */
798 	}
799 	arglist[argcount++] = cp;
800 
801 }
802 
803 static void
804 putarg(where, cp)
805 	char           *cp;
806 	int             where;
807 {
808 	if (where >= ARGLISTLEN) {
809 		fprintf(stderr, "rpcgen: arglist coding error\n");
810 		crash();
811 		/* NOTREACHED */
812 	}
813 	arglist[where] = cp;
814 }
815 
816 /*
817  * if input file is stdin and an output file is specified then complain
818  * if the file already exists. Otherwise the file may get overwritten
819  * If input file does not exist, exit with an error
820  */
821 static void
822 checkfiles(infile, outfile)
823 	char           *infile;
824 	char           *outfile;
825 {
826 	struct stat     buf;
827 
828 	if (infile)		/* infile ! = NULL */
829 		if (stat(infile, &buf) < 0) {
830 			perror(infile);
831 			crash();
832 		}
833 #if 0
834 	if (outfile) {
835 		if (stat(outfile, &buf) < 0)
836 			return;	/* file does not exist */
837 		else {
838 			fprintf(stderr,
839 			    "file '%s' already exists and may be overwritten\n",
840 			    outfile);
841 			crash();
842 		}
843 	}
844 #endif
845 }
846 
847 /*
848  * Parse command line arguments
849  */
850 static int
851 parseargs(argc, argv, cmd)
852 	int argc;
853 	char *argv[];
854 	struct commandline *cmd;
855 {
856 	int i, j, nflags;
857 	char c, flag[(1 << 8 * sizeof(char))];
858 
859 	cmdname = argv[0];
860 	cmd->infile = cmd->outfile = NULL;
861 	if (argc < 2)
862 		return (0);
863 
864 	allfiles = 0;
865 	flag['c'] = 0;
866 	flag['h'] = 0;
867 	flag['l'] = 0;
868 	flag['m'] = 0;
869 	flag['o'] = 0;
870 	flag['s'] = 0;
871 	flag['n'] = 0;
872 	flag['t'] = 0;
873 	flag['S'] = 0;
874 	flag['C'] = 0;
875 	for (i = 1; i < argc; i++) {
876 		if (argv[i][0] != '-') {
877 			if (cmd->infile) {
878 				fprintf(stderr,
879 				    "Cannot specify more than one input file!\n");
880 				return (0);
881 			}
882 			cmd->infile = argv[i];
883 		} else {
884 			for (j = 1; argv[i][j] != 0; j++) {
885 				c = argv[i][j];
886 				switch (c) {
887 				case 'A':
888 					callerflag = 1;
889 					break;
890 				case 'a':
891 					allfiles = 1;
892 					break;
893 				case 'c':
894 				case 'h':
895 				case 'l':
896 				case 'm':
897 				case 't':
898 					if (flag[(unsigned char)c])
899 						return (0);
900 					flag[(unsigned char)c] = 1;
901 					break;
902 				case 'S':
903 					/*
904 					 * sample flag: Ss or Sc. Ss means
905 					 * set flag['S']; Sc means set
906 					 * flag['C'];
907 					 */
908 					c = argv[i][++j];	/* get next char */
909 					if (c == 's')
910 						c = 'S';
911 					else if (c == 'c')
912 						c = 'C';
913 					else
914 						return (0);
915 
916 					if (flag[(unsigned char)c])
917 						return (0);
918 					flag[(unsigned char)c] = 1;
919 					break;
920 				case 'C':	/* ANSI C syntax */
921 					Cflag = 1;
922 					break;
923 
924 				case 'b':
925 					/*
926 					 * turn TIRPC flag off for
927 					 * generating backward compatible
928 					 */
929 					tirpcflag = 0;
930 					break;
931 
932 				case 'I':
933 					inetdflag = 1;
934 					break;
935 				case 'N':
936 					newstyle = 1;
937 					break;
938 				case 'L':
939 					logflag = 1;
940 					break;
941 				case 'K':
942 					if (++i == argc)
943 						return (0);
944 					svcclosetime = argv[i];
945 					goto nextarg;
946 				case 'T':
947 					tblflag = 1;
948 					break;
949 				case 'i':
950 					if (++i == argc)
951 						return (0);
952 					doinline = atoi(argv[i]);
953 					goto nextarg;
954 				case 'n':
955 				case 'o':
956 				case 's':
957 					if (argv[i][j - 1] != '-' ||
958 					    argv[i][j + 1] != 0)
959 						return (0);
960 					flag[(unsigned char)c] = 1;
961 					if (++i == argc)
962 						return (0);
963 					if (c == 's') {
964 						if (!streq(argv[i], "udp") &&
965 						    !streq(argv[i], "tcp"))
966 							return (0);
967 					} else if (c == 'o') {
968 						if (cmd->outfile)
969 							return (0);
970 						cmd->outfile = argv[i];
971 					}
972 					goto nextarg;
973 				case 'D':
974 					if (argv[i][j - 1] != '-')
975 						return (0);
976 					(void) addarg(argv[i]);
977 					goto nextarg;
978 				case 'Y':
979 					if (++i == argc)
980 						return (0);
981 					if (snprintf(pathbuf, sizeof pathbuf,
982 					    "%s/cpp", argv[i]) >= sizeof pathbuf)
983 						usage();
984 					CPP = pathbuf;
985 					cppDefined = 1;
986 					goto nextarg;
987 				default:
988 					return (0);
989 				}
990 			}
991 	nextarg:
992 			;
993 		}
994 	}
995 
996 	cmd->cflag = flag['c'];
997 	cmd->hflag = flag['h'];
998 	cmd->lflag = flag['l'];
999 	cmd->mflag = flag['m'];
1000 	cmd->nflag = flag['n'];
1001 	cmd->sflag = flag['s'];
1002 	cmd->tflag = flag['t'];
1003 	cmd->Ssflag = flag['S'];
1004 	cmd->Scflag = flag['C'];
1005 
1006 	if (tirpcflag) {
1007 		pmflag = inetdflag ? 0 : 1;	/* pmflag or inetdflag is
1008 						 * always TRUE */
1009 		if (inetdflag && cmd->nflag) {
1010 			/* netid not allowed with inetdflag */
1011 			fprintf(stderr, "Cannot use netid flag with inetd flag!\n");
1012 			return (0);
1013 		}
1014 	} else {
1015 		/* 4.1 mode */
1016 		pmflag = 0;	/* set pmflag only in tirpcmode */
1017 		inetdflag = 1;	/* inetdflag is TRUE by default */
1018 		if (cmd->nflag) {
1019 			/* netid needs TIRPC */
1020 			fprintf(stderr, "Cannot use netid flag without TIRPC!\n");
1021 			return (0);
1022 		}
1023 	}
1024 
1025 	if (newstyle && (tblflag || cmd->tflag)) {
1026 		fprintf(stderr, "Cannot use table flags with newstyle!\n");
1027 		return (0);
1028 	}
1029 	/* check no conflicts with file generation flags */
1030 	nflags = cmd->cflag + cmd->hflag + cmd->lflag + cmd->mflag +
1031 	    cmd->sflag + cmd->nflag + cmd->tflag + cmd->Ssflag + cmd->Scflag;
1032 
1033 	if (nflags == 0) {
1034 		if (cmd->outfile != NULL || cmd->infile == NULL)
1035 			return (0);
1036 	} else if (nflags > 1) {
1037 		fprintf(stderr, "Cannot have more than one file generation flag!\n");
1038 		return (0);
1039 	}
1040 	return (1);
1041 }
1042 
1043 static void
1044 usage(void)
1045 {
1046 	fprintf(stderr, "usage: %s [-abACILNT] [-Dname[=value]] [-i lines] "
1047 	    "[-K seconds] infile\n", cmdname);
1048 	fprintf(stderr, "       %s [-c | -h | -l | -m | -t | -Sc | -Ss] "
1049 	    "[-o outfile] [infile]\n", cmdname);
1050 	fprintf(stderr, "       %s [-s nettype]* [-o outfile] [infile]\n", cmdname);
1051 	exit(1);
1052 }
1053