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