]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/rpcgen/rpc_main.c
zfs: merge openzfs/zfs@41e55b476
[FreeBSD/FreeBSD.git] / usr.bin / rpcgen / rpc_main.c
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
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 *
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
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
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
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
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
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 *
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }