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