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