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