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