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