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