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