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