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