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