]> git.decadent.org.uk Git - nfs-utils.git/blob - tools/rpcgen/rpc_main.c
nfs-iostat.py: divide by zero with fresh mount
[nfs-utils.git] / tools / rpcgen / rpc_main.c
1 /*
2  * Copyright (c) 2009, Sun Microsystems, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * - Redistributions of source code must retain the above copyright notice,
8  *   this list of conditions and the following disclaimer.
9  * - Redistributions in binary form must reproduce the above copyright notice,
10  *   this list of conditions and the following disclaimer in the documentation
11  *   and/or other materials provided with the distribution.
12  * - Neither the name of Sun Microsystems, Inc. nor the names of its
13  *   contributors may be used to endorse or promote products derived
14  *   from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #if 0
30 static char sccsid[] = "@(#)rpc_main.c 1.30 89/03/30 (C) 1987 SMI";
31 #endif
32
33 /*
34  * rpc_main.c, Top level of the RPC protocol compiler. 
35  */
36
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/file.h>
40 #include <sys/stat.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <stdlib.h>
44 #include <unistd.h>
45 #include <ctype.h>
46 #include <errno.h>
47 #include "rpc_parse.h"
48 #include "rpc_util.h"
49 #include "rpc_scan.h"
50
51 struct commandline {
52         int cflag;              /* xdr C routines */
53         int hflag;              /* header file */
54         int lflag;              /* client side stubs */
55         int mflag;              /* server side stubs */
56         int nflag;              /* netid flag */
57         int sflag;              /* server stubs for the given transport */
58         int tflag;              /* dispatch Table file */
59         int Ssflag;             /* produce server sample code */
60         int Scflag;             /* produce client sample code */
61         char *infile;           /* input module name */
62         char *outfile;          /* output module name */
63 };
64
65 static char *   extendfile(char *file, char *ext);
66 static void     open_output(char *infile, char *outfile);
67 static void     add_warning(void);
68 static void     clear_args(void);
69 static void     open_input(char *infile, char *define);
70 static int      check_nettype(char *name, char **list_to_check);
71 static void     c_output(char *infile, char *define, int extend, char *outfile);
72 static void     c_initialize(void);
73 static char *   generate_guard(char *pathname);
74 static void     h_output(char *infile, char *define, int extend, char *outfile);
75 static void     s_output(int argc, char **argv, char *infile,
76                         char *define, int extend, char *outfile,
77                         int nomain, int netflag);
78 static void     l_output(char *infile, char *define, int extend, char *outfile);
79 static void     t_output(char *infile, char *define, int extend, char *outfile);
80 static void     svc_output(char *, char *, int, char *);
81 static void     clnt_output(char *, char *, int, char *);
82 static int      do_registers(int argc, char **argv);
83 static void     addarg(char *cp);
84 static void     putarg(int where, char *cp);
85 static void     checkfiles(char *infile, char *outfile);
86 static int      parseargs(int argc, char **argv, struct commandline *cmd);
87 static void     usage(void);
88 static void     options_usage(void);
89
90 /*
91 extern void  write_sample_svc();
92 int write_sample_clnt();
93 void write_sample_clnt_main();
94
95 static svc_output();
96  */
97
98 #define EXTEND  1               /* alias for TRUE */
99 #define DONT_EXTEND     0               /* alias for FALSE */
100
101 #define SVR4_CPP "/usr/ccs/lib/cpp"
102 #define SUNOS_CPP "/lib/cpp"
103 static int cppDefined = 0;          /* explicit path for C preprocessor */
104
105
106 static char *cmdname;
107
108 static char *svcclosetime = "120";
109 static char *CPP = SVR4_CPP;
110 static char CPPFLAGS[] = "-C";
111 static char pathbuf[MAXPATHLEN + 1];
112 static char *allv[] = {
113         "rpcgen", "-s", "udp", "-s", "tcp",
114 };
115 static int allc = sizeof(allv)/sizeof(allv[0]);
116 static char *allnv[] = {
117         "rpcgen", "-s", "netpath",
118 };
119 static int allnc = sizeof(allnv)/sizeof(allnv[0]);
120
121 /*
122  * machinations for handling expanding argument list
123  */
124 #if 0
125 static void addarg();           /* add another argument to the list */
126 static void putarg();           /* put argument at specified location  */
127 static void clear_args();       /* clear argument list */
128 static void checkfiles();       /* check if out file already exists */
129 #endif
130
131
132
133 #define ARGLISTLEN      20
134 #define FIXEDARGS         2
135
136 static char *arglist[ARGLISTLEN];
137 static int argcount = FIXEDARGS;
138
139
140 int nonfatalerrors;     /* errors */
141 int inetdflag/* = 1*/;  /* Support for inetd */ /* is now the default */
142 int pmflag;             /* Support for port monitors */
143 int logflag;            /* Use syslog instead of fprintf for errors */
144 int tblflag;            /* Support for dispatch table file */
145
146 /* length at which to start doing an inline */
147 #define INLINE 3
148
149 int Inline = INLINE;    /* length at which to start doing an inline. 3 = default
150                          * if 0, no xdr_inline code */
151
152 int indefinitewait;     /* If started by port monitors, hang till it wants */
153 int exitnow;            /* If started by port monitors, exit after the call */
154 int timerflag;          /* TRUE if !indefinite && !exitnow */
155 int newstyle;           /* newstyle of passing arguments (by value) */
156 int Cflag = 0 ;         /* ANSI C syntax */
157 static int allfiles;    /* generate all files */
158 #ifdef linux
159 int tirpcflag = 0;      /* no tirpc by default */
160 #else
161 int tirpcflag = 1;      /* generating code for tirpc, by default */
162 #endif
163
164 int
165 main(int argc, char **argv)
166 {
167         struct commandline cmd;
168
169         (void) memset((char *) &cmd, 0, sizeof(struct commandline));
170         clear_args();
171         if (!parseargs(argc, argv, &cmd))
172                 usage();
173
174         if (cmd.cflag || cmd.hflag || cmd.lflag || cmd.tflag || cmd.sflag ||
175                 cmd.mflag || cmd.nflag || cmd.Ssflag || cmd.Scflag) {
176                 checkfiles(cmd.infile, cmd.outfile);
177         } else
178                 checkfiles(cmd.infile, NULL);
179
180         if (cmd.cflag) {
181                 c_output(cmd.infile, "-DRPC_XDR", DONT_EXTEND, cmd.outfile);
182         } else if (cmd.hflag) {
183                 h_output(cmd.infile, "-DRPC_HDR", DONT_EXTEND, cmd.outfile);
184         } else if (cmd.lflag) {
185                 l_output(cmd.infile, "-DRPC_CLNT", DONT_EXTEND, cmd.outfile);
186         } else if (cmd.sflag || cmd.mflag || (cmd.nflag)) {
187                 s_output(argc, argv, cmd.infile, "-DRPC_SVC", DONT_EXTEND,
188                         cmd.outfile, cmd.mflag, cmd.nflag);
189         } else if (cmd.tflag) {
190                 t_output(cmd.infile, "-DRPC_TBL", DONT_EXTEND, cmd.outfile);
191         } else if (cmd.Ssflag) {
192                 svc_output(cmd.infile, "-DRPC_SERVER", DONT_EXTEND, cmd.outfile);
193         } else if (cmd.Scflag) {
194                 clnt_output(cmd.infile, "-DRPC_CLIENT", DONT_EXTEND, cmd.outfile);
195         } else {
196                 /* the rescans are required, since cpp may effect input */
197                 c_output(cmd.infile, "-DRPC_XDR", EXTEND, "_xdr.c");
198                 reinitialize();
199                 h_output(cmd.infile, "-DRPC_HDR", EXTEND, ".h");
200                 reinitialize();
201                 l_output(cmd.infile, "-DRPC_CLNT", EXTEND, "_clnt.c");
202                 reinitialize();
203                 if (inetdflag || !tirpcflag)
204                         s_output(allc, allv, cmd.infile, "-DRPC_SVC", EXTEND,
205                                 "_svc.c", cmd.mflag, cmd.nflag);
206                 else
207                         s_output(allnc, allnv, cmd.infile, "-DRPC_SVC",
208                                 EXTEND, "_svc.c", cmd.mflag, cmd.nflag);
209                 if (tblflag) {
210                         reinitialize();
211                         t_output(cmd.infile, "-DRPC_TBL", EXTEND, "_tbl.i");
212                 }
213                 if (allfiles) {
214                         reinitialize();
215                         svc_output(cmd.infile, "-DRPC_SERVER", EXTEND, "_server.c");
216                 }
217                 if (allfiles) {
218                         reinitialize();
219                         clnt_output(cmd.infile, "-DRPC_CLIENT", EXTEND, "_client.c");
220                 }
221         }
222         exit(nonfatalerrors);
223         /* NOTREACHED */
224 }
225
226 /*
227  * add extension to filename 
228  */
229 static char *
230 extendfile(char *file, char *ext)
231 {
232         char *res;
233         char *p;
234
235         res = alloc(strlen(file) + strlen(ext) + 1);
236         if (res == NULL) {
237                 abort();
238         }
239         p = strrchr(file, '.');
240         if (p == NULL) {
241                 p = file + strlen(file);
242         }
243         (void) strcpy(res, file);
244         (void) strcpy(res + (p - file), ext);
245         return (res);
246 }
247
248 /*
249  * Open output file with given extension 
250  */
251 static void
252 open_output(char *infile, char *outfile)
253 {
254
255         if (outfile == NULL) {
256                 fout = stdout;
257                 return;
258         }
259
260         if (infile != NULL && streq(outfile, infile)) {
261                 f_print(stderr, "%s: output would overwrite %s\n", cmdname,
262                         infile);
263                 crash();
264         }
265         fout = fopen(outfile, "w");
266         if (fout == NULL) {
267                 f_print(stderr, "%s: unable to open ", cmdname);
268                 perror(outfile);
269                 crash();
270         }
271         record_open(outfile);
272
273 }
274
275 static void
276 add_warning(void)
277 {
278         f_print(fout, "/*\n");
279         f_print(fout, " * Please do not edit this file.\n");
280         f_print(fout, " * It was generated using rpcgen.\n");
281         f_print(fout, " */\n\n");
282 }
283
284 /* clear list of arguments */
285 static void
286 clear_args(void)
287 {
288   int i;
289   for( i=FIXEDARGS; i<ARGLISTLEN; i++ )
290     arglist[i] = NULL;
291   argcount = FIXEDARGS;
292 }
293
294 /*
295  * Open input file with given define for C-preprocessor 
296  */
297 static void
298 open_input(char *infile, char *define)
299 {
300         int pd[2];
301
302         infilename = (infile == NULL) ? "<stdin>" : infile;
303         (void) pipe(pd);
304         switch (fork()) {
305         case 0:
306                 putarg(0, "cpp");
307                 putarg(1, CPPFLAGS);
308                 addarg(define);
309                 addarg(infile);
310                 addarg((char *)NULL);
311                 (void) close(1);
312                 (void) dup2(pd[1], 1);
313                 (void) close(pd[0]);
314                 if (cppDefined)
315                         execv(CPP, arglist);
316                 else {
317                         execvp("cpp", arglist);
318                         if (errno == ENOENT)
319                                 execvp(SVR4_CPP, arglist);
320                         if (errno == ENOENT)
321                                 execvp(SUNOS_CPP, arglist);
322                 }
323                 perror("execv");
324                 exit(1);
325         case -1:
326                 perror("fork");
327                 exit(1);
328         }
329         (void) close(pd[1]);
330         fin = fdopen(pd[0], "r");
331         if (fin == NULL) {
332                 f_print(stderr, "%s: ", cmdname);
333                 perror(infilename);
334                 crash();
335         }
336 }
337
338 /* valid tirpc nettypes */
339 static char*    valid_ti_nettypes[] =
340 {
341         "netpath",
342         "visible",
343         "circuit_v",
344         "datagram_v",
345         "circuit_n",
346         "datagram_n",
347         "udp",
348         "tcp",
349         "raw",
350         NULL
351 };
352
353 /* valid inetd nettypes */
354 static char* valid_i_nettypes[] =
355 {
356         "udp",
357         "tcp",
358         NULL
359 };
360
361 static int
362 check_nettype(char *name, char **list_to_check)
363 {
364   int i;
365   for( i = 0; list_to_check[i] != NULL; i++ ) {
366           if( strcmp( name, list_to_check[i] ) == 0 ) {
367             return 1;
368           }
369   }
370   f_print( stderr, "illegal nettype :\'%s\'\n", name );
371   return 0;
372 }
373
374 /*
375  * Compile into an XDR routine output file
376  */
377
378 static void
379 c_output(char *infile, char *define, int extend, char *outfile)
380 {
381         definition *def;
382         char *include;
383         char *outfilename;
384         long tell;
385
386         c_initialize();
387         open_input(infile, define);     
388         outfilename = extend ? extendfile(infile, outfile) : outfile;
389         open_output(infile, outfilename);
390         add_warning();
391         if (infile && (include = extendfile(infile, ".h"))) {
392                 f_print(fout, "#include \"%s\"\n", include);
393                 free(include);
394                 /* .h file already contains rpc/rpc.h */
395         } else
396           f_print(fout, "#include <rpc/rpc.h>\n");
397         tell = ftell(fout);
398         while ((def = get_definition()) != NULL) {
399                 emit(def);
400         }
401         if (extend && tell == ftell(fout)) {
402                 (void) unlink(outfilename);
403         }
404 }
405
406
407 static void
408 c_initialize(void)
409 {
410
411   /* add all the starting basic types */
412
413   add_type(1,"int");
414   add_type(1,"int32_t");
415   add_type(1,"short");
416   add_type(1,"bool");
417
418   add_type(1,"u_int");
419   add_type(1,"u_int32_t");
420   add_type(1,"u_short");
421
422 }
423
424 char rpcgen_table_dcl[] = "struct rpcgen_table {\n\
425         char    *(*proc)();\n\
426         xdrproc_t       xdr_arg;\n\
427         unsigned        len_arg;\n\
428         xdrproc_t       xdr_res;\n\
429         unsigned        len_res;\n\
430 };\n";
431
432
433 static char *
434 generate_guard(char *pathname)
435 {
436         char* filename, *guard, *tmp;
437
438         filename = strrchr(pathname, '/' );  /* find last component */
439         filename = ((filename == 0) ? pathname : filename+1);
440         guard = strdup(filename);
441         /* convert to upper case */
442         tmp = guard;
443         while (*tmp) {
444                 if (islower(*tmp))
445                         *tmp = toupper(*tmp);
446                 tmp++;
447         }
448                 
449         guard = extendfile(guard, "_H_RPCGEN");
450         return( guard );
451 }
452
453 /*
454  * Compile into an XDR header file
455  */
456 static void
457 h_output(char *infile, char *define, int extend, char *outfile)
458 {
459         definition *def;
460         char *outfilename;
461         long tell;
462         char *guard;
463         list *l;
464
465         open_input(infile, define);
466         outfilename =  extend ? extendfile(infile, outfile) : outfile;
467         open_output(infile, outfilename);
468         add_warning();
469         guard = generate_guard(  outfilename ? outfilename: infile );
470
471         f_print(fout,"#ifndef _%s\n#define _%s\n\n", guard,
472                 guard);
473
474         f_print(fout, "#include <rpc/rpc.h>\n\n");
475
476         f_print(fout, "#ifndef IXDR_GET_INT32\n");
477         f_print(fout, "#define IXDR_GET_INT32(buf) IXDR_GET_LONG((buf))\n");
478         f_print(fout, "#endif\n");
479         f_print(fout, "#ifndef IXDR_PUT_INT32\n");
480         f_print(fout, "#define IXDR_PUT_INT32(buf, v) IXDR_PUT_LONG((buf), (v))\n");
481         f_print(fout, "#endif\n");
482         f_print(fout, "#ifndef IXDR_GET_U_INT32\n");
483         f_print(fout, "#define IXDR_GET_U_INT32(buf) IXDR_GET_U_LONG((buf))\n");
484         f_print(fout, "#endif\n");
485         f_print(fout, "#ifndef IXDR_PUT_U_INT32\n");
486         f_print(fout, "#define IXDR_PUT_U_INT32(buf, v) IXDR_PUT_U_LONG((buf), (v))\n");
487         f_print(fout, "#endif\n");
488
489         tell = ftell(fout);
490         /* print data definitions */
491         while ((def = get_definition()) != NULL) {
492                 print_datadef(def);
493         }
494
495         /* print function declarations.  
496            Do this after data definitions because they might be used as
497            arguments for functions */
498         for (l = defined; l != NULL; l = l->next) {
499                 print_funcdef(l->val);
500         }
501         if (extend && tell == ftell(fout)) {
502                 (void) unlink(outfilename);
503         } else if (tblflag) {
504                 f_print(fout, rpcgen_table_dcl);
505         }
506         f_print(fout, "\n#endif /* !_%s */\n", guard);
507 }
508
509 /*
510  * Compile into an RPC service
511  */
512 static void
513 s_output(int argc, char **argv, char *infile, char *define, int extend,
514                         char *outfile, int nomain, int netflag)
515 {
516         char *include;
517         definition *def;
518         int foundprogram = 0;
519         char *outfilename;
520
521         open_input(infile, define);
522         outfilename = extend ? extendfile(infile, outfile) : outfile;
523         open_output(infile, outfilename);
524         add_warning();
525         if (infile && (include = extendfile(infile, ".h"))) {
526                 f_print(fout, "#include \"%s\"\n", include);
527                 free(include);
528         } else
529           f_print(fout, "#include <rpc/rpc.h>\n");
530
531         f_print(fout, "#include <stdio.h>\n");
532         f_print(fout, "#include <stdlib.h>/* getenv, exit */\n"); 
533         if (Cflag) {
534                 f_print (fout, "#include <rpc/pmap_clnt.h> /* for pmap_unset */\n");
535                 f_print (fout, "#include <string.h> /* strcmp */ \n"); 
536         }
537         if (strcmp(svcclosetime, "-1") == 0)
538                 indefinitewait = 1;
539         else if (strcmp(svcclosetime, "0") == 0)
540                 exitnow = 1;
541         else if (inetdflag || pmflag) {
542                 f_print(fout, "#include <signal.h>\n");
543           timerflag = 1;
544         }
545
546 #ifndef linux
547         if( !tirpcflag && inetdflag )
548           f_print(fout, "#include <sys/ttycom.h>/* TIOCNOTTY */\n");
549 #else
550         if( !tirpcflag )
551           f_print(fout, "#include <sys/ioctl.h>/* TIOCNOTTY */\n");
552 #endif
553         if( Cflag && (inetdflag || pmflag ) ) {
554           f_print(fout, "#ifdef __cplusplus\n");
555           f_print(fout, "#include <sysent.h> /* getdtablesize, open */\n"); 
556           f_print(fout, "#endif /* __cplusplus */\n");
557           
558           if( tirpcflag )
559             f_print(fout, "#include <unistd.h> /* setsid */\n");
560         }
561         if( tirpcflag )
562           f_print(fout, "#include <sys/types.h>\n");
563
564         f_print(fout, "#include <memory.h>\n");
565 #ifndef linux
566         f_print(fout, "#include <stropts.h>\n");
567 #endif
568         if (inetdflag || !tirpcflag ) {
569                 f_print(fout, "#include <sys/socket.h>\n");
570                 f_print(fout, "#include <netinet/in.h>\n");
571         } 
572
573         if ( (netflag || pmflag) && tirpcflag ) {
574                 f_print(fout, "#include <netconfig.h>\n");
575         }
576         if (/*timerflag &&*/ tirpcflag)
577                 f_print(fout, "#include <sys/resource.h> /* rlimit */\n");
578         if (logflag || inetdflag || pmflag) {
579 #ifdef linux
580                 f_print(fout, "#include <syslog.h>\n");
581 #else
582                 f_print(fout, "#ifdef SYSLOG\n");
583                 f_print(fout, "#include <syslog.h>\n");
584                 f_print(fout, "#else\n");
585                 f_print(fout, "#define LOG_ERR 1\n");
586                 f_print(fout, "#define openlog(a, b, c)\n");
587                 f_print(fout, "#endif\n");
588 #endif
589         }
590
591         /* for ANSI-C */
592         f_print(fout, "\n#ifdef __STDC__\n#define SIG_PF void(*)(int)\n#endif\n");
593
594         f_print(fout, "\n#ifdef DEBUG\n#define RPC_SVC_FG\n#endif\n");
595         if (timerflag)
596                 f_print(fout, "\n#define _RPCSVC_CLOSEDOWN %s\n", svcclosetime);
597         while ((def = get_definition()) != NULL) {
598                 foundprogram |= (def->def_kind == DEF_PROGRAM);
599         }
600         if (extend && !foundprogram) {
601                 (void) unlink(outfilename);
602                 return;
603         }
604         write_most(infile, netflag, nomain);
605         if (!nomain) {
606                 if( !do_registers(argc, argv) ) {
607                   if (outfilename)
608                     (void) unlink(outfilename);
609                   usage();
610                 }
611                 write_rest();
612         }
613 }
614
615 /*
616  * generate client side stubs
617  */
618 static void
619 l_output(char *infile, char *define, int extend, char *outfile)
620 {
621         char *include;
622         definition *def;
623         int foundprogram = 0;
624         char *outfilename;
625
626         open_input(infile, define);
627         outfilename = extend ? extendfile(infile, outfile) : outfile;
628         open_output(infile, outfilename);
629         add_warning();
630         if (Cflag)
631           f_print (fout, "#include <memory.h> /* for memset */\n");
632         if (infile && (include = extendfile(infile, ".h"))) {
633                 f_print(fout, "#include \"%s\"\n", include);
634                 free(include);
635         } else
636           f_print(fout, "#include <rpc/rpc.h>\n");
637         while ((def = get_definition()) != NULL) {
638                 foundprogram |= (def->def_kind == DEF_PROGRAM);
639         }
640         if (extend && !foundprogram) {
641                 (void) unlink(outfilename);
642                 return;
643         }
644         write_stubs();
645 }
646
647 /*
648  * generate the dispatch table
649  */
650 static void
651 t_output(char *infile, char *define, int extend, char *outfile)
652 {
653         definition *def;
654         int foundprogram = 0;
655         char *outfilename;
656
657         open_input(infile, define);
658         outfilename = extend ? extendfile(infile, outfile) : outfile;
659         open_output(infile, outfilename);
660         add_warning();
661         while ((def = get_definition()) != NULL) {
662                 foundprogram |= (def->def_kind == DEF_PROGRAM);
663         }
664         if (extend && !foundprogram) {
665                 (void) unlink(outfilename);
666                 return;
667         }
668         write_tables();
669 }
670
671 /* sample routine for the server template */
672 static  void
673 svc_output(char *infile, char *define, int extend, char *outfile)
674 {
675   definition *def;
676   char *include;
677   char *outfilename;
678   long tell;
679   
680   open_input(infile, define);   
681   outfilename = extend ? extendfile(infile, outfile) : outfile;
682   checkfiles(infile,outfilename); /*check if outfile already exists.
683                                   if so, print an error message and exit*/
684   open_output(infile, outfilename);
685   add_sample_msg();
686
687   if (infile && (include = extendfile(infile, ".h"))) {
688     f_print(fout, "#include \"%s\"\n", include);
689     free(include);
690   } else
691     f_print(fout, "#include <rpc/rpc.h>\n");
692
693   tell = ftell(fout);
694   while ((def = get_definition()) != NULL) {
695           write_sample_svc(def);
696   }
697   if (extend && tell == ftell(fout)) {
698           (void) unlink(outfilename);
699   }
700 }
701
702
703 /* sample main routine for client */
704 static  void
705 clnt_output(char *infile, char *define, int extend, char *outfile)
706 {
707         definition     *def;
708         char           *include;
709         char           *outfilename;
710         long            tell;
711         int             has_program = 0;
712
713         open_input(infile, define);
714         outfilename = extend ? extendfile(infile, outfile) : outfile;
715         checkfiles(infile, outfilename);        /*check if outfile already exists.
716                                   if so, print an error message and exit*/
717
718         open_output(infile, outfilename);
719         add_sample_msg();
720         if (infile && (include = extendfile(infile, ".h"))) {
721                 f_print(fout, "#include \"%s\"\n", include);
722                 free(include);
723         } else
724                 f_print(fout, "#include <rpc/rpc.h>\n");
725         tell = ftell(fout);
726         while ((def = get_definition()) != NULL) {
727                 has_program += write_sample_clnt(def);
728         }
729
730         if (has_program)
731                 write_sample_clnt_main();
732
733         if (extend && tell == ftell(fout)) {
734                 (void) unlink(outfilename);
735         }
736 }
737
738 /*
739  * Perform registrations for service output 
740  * Return 0 if failed; 1 otherwise.
741  */
742 static int
743 do_registers(int argc, char **argv)
744 {
745         int             i;
746
747         if (inetdflag || !tirpcflag) {
748                 for (i = 1; i < argc; i++) {
749                         if (streq(argv[i], "-s")) {
750                                 if (!check_nettype(argv[i + 1], valid_i_nettypes))
751                                         return 0;
752                                 write_inetd_register(argv[i + 1]);
753                                 i++;
754                         }
755                 }
756         } else {
757                 for (i = 1; i < argc; i++)
758                         if (streq(argv[i], "-s")) {
759                                 if (!check_nettype(argv[i + 1], valid_ti_nettypes))
760                                         return 0;
761                                 write_nettype_register(argv[i + 1]);
762                                 i++;
763                         } else if (streq(argv[i], "-n")) {
764                                 write_netid_register(argv[i + 1]);
765                                 i++;
766                         }
767         }
768         return 1;
769 }
770
771 /*
772  * Add another argument to the arg list
773  */
774 static void
775 addarg(char *cp)
776 {
777         if (argcount >= ARGLISTLEN) {
778                 f_print(stderr, "rpcgen: too many defines\n");
779                 crash();
780                 /*NOTREACHED*/
781         }
782         arglist[argcount++] = cp;
783
784 }
785
786 static void
787 putarg(int where, char *cp)
788 {
789         if (where >= ARGLISTLEN) {
790                 f_print(stderr, "rpcgen: arglist coding error\n");
791                 crash();
792                 /*NOTREACHED*/
793         }
794         arglist[where] = cp;
795         
796 }
797
798 /*
799  * if input file is stdin and an output file is specified then complain
800  * if the file already exists. Otherwise the file may get overwritten
801  * If input file does not exist, exit with an error 
802  */
803
804 static void
805 checkfiles(char *infile, char *outfile) 
806 {
807
808   struct stat buf;
809
810   if(infile)                    /* infile ! = NULL */
811     if(stat(infile,&buf) < 0)
812       {
813         perror(infile);
814         crash();
815       };
816   if (outfile) {
817     if (stat(outfile, &buf) < 0) 
818       return;                   /* file does not exist */
819     else {
820       f_print(stderr, 
821               "file '%s' already exists and may be overwritten\n", outfile);
822       crash();
823     }
824   }
825 }
826
827 /*
828  * Parse command line arguments 
829  */
830 static int
831 parseargs(int argc, char **argv, struct commandline *cmd)
832 {
833         int i;
834         int j;
835         char c;
836         char flag[(1 << 8 * sizeof(char))];
837         int nflags;
838
839         cmdname = argv[0];
840         cmd->infile = cmd->outfile = NULL;
841         if (argc < 2) {
842                 return (0);
843         }
844         allfiles = 0;
845         flag['c'] = 0;
846         flag['h'] = 0;
847         flag['l'] = 0;
848         flag['m'] = 0;
849         flag['o'] = 0;
850         flag['s'] = 0;
851         flag['n'] = 0;
852         flag['t'] = 0;
853         flag['S'] = 0;
854         flag['C'] = 0;
855         for (i = 1; i < argc; i++) {
856                 if (argv[i][0] != '-') {
857                         if (cmd->infile) {
858                                 f_print( stderr, "Cannot specify more than one input file!\n");
859
860                                 return (0);
861                         }
862                         cmd->infile = argv[i];
863                 } else {
864                         for (j = 1; argv[i][j] != 0; j++) {
865                                 c = argv[i][j];
866                                 switch (c) {
867                                 case 'a':
868                                         allfiles = 1;
869                                         break;
870                                 case 'c':
871                                 case 'h':
872                                 case 'l':
873                                 case 'm':
874                                 case 't':
875                                         if (flag[(int) c]) {
876                                                 return (0);
877                                         }
878                                         flag[(int) c] = 1;
879                                         break;
880                                 case 'S':  
881                                         /* sample flag: Ss or Sc.
882                                            Ss means set flag['S'];
883                                            Sc means set flag['C']; */
884                                         c = argv[i][++j];  /* get next char */
885                                         if( c == 's' )
886                                           c = 'S';
887                                         else if( c == 'c' )
888                                           c = 'C';
889                                         else
890                                           return( 0 );
891
892                                         if (flag[(int) c]) {
893                                                 return (0);
894                                         }
895                                         flag[(int) c] = 1;
896                                         break;
897                                 case 'C':  /* ANSI C syntax */
898                                         Cflag = 1;
899                                         break;
900
901                                 case 'b':  /* turn TIRPC flag off for
902                                             generating backward compatible
903                                             */
904                                         tirpcflag = 0;
905                                         break;
906
907                                 case 'I':
908                                         inetdflag = 1;
909                                         break;
910                                 case 'N':
911                                         newstyle = 1;
912                                         break;
913                                 case 'L':
914                                         logflag = 1;
915                                         break;
916                                 case 'K':
917                                         if (++i == argc) {
918                                                 return (0);
919                                         }
920                                         svcclosetime = argv[i];
921                                         goto nextarg;
922                                 case 'T':
923                                         tblflag = 1;
924                                         break;
925                                 case 'i' :
926                                         if (++i == argc) {
927                                                 return (0);
928                                         }
929                                         Inline = atoi(argv[i]);
930                                         goto nextarg;
931                                 case 'n':
932                                 case 'o':
933                                 case 's':
934                                         if (argv[i][j - 1] != '-' || 
935                                             argv[i][j + 1] != 0) {
936                                                 return (0);
937                                         }
938                                         flag[(int) c] = 1;
939                                         if (++i == argc) {
940                                                 return (0);
941                                         }
942                                         if (c == 's') {
943                                                 if (!streq(argv[i], "udp") &&
944                                                     !streq(argv[i], "tcp")) {
945                                                         return (0);
946                                                 }
947                                         } else if (c == 'o') {
948                                                 if (cmd->outfile) {
949                                                         return (0);
950                                                 }
951                                                 cmd->outfile = argv[i];
952                                         }
953                                         goto nextarg;
954                                 case 'D':
955                                         if (argv[i][j - 1] != '-') {
956                                                 return (0);
957                                         }
958                                         (void) addarg(argv[i]);
959                                         goto nextarg;
960                                 case 'Y':
961                                         if (++i == argc) {
962                                                 return (0);
963                                         }
964                                         (void) strcpy(pathbuf, argv[i]);
965                                         (void) strcat(pathbuf, "/cpp");
966                                         CPP = pathbuf;
967                                         cppDefined = 1;
968                                         goto nextarg;
969
970
971
972                                 default:
973                                         return (0);
974                                 }
975                         }
976         nextarg:
977                         ;
978                 }
979         }
980
981         cmd->cflag = flag['c'];
982         cmd->hflag = flag['h'];
983         cmd->lflag = flag['l'];
984         cmd->mflag = flag['m'];
985         cmd->nflag = flag['n'];
986         cmd->sflag = flag['s'];
987         cmd->tflag = flag['t'];
988         cmd->Ssflag = flag['S'];
989         cmd->Scflag = flag['C'];
990
991         if( tirpcflag ) {
992           pmflag = inetdflag ? 0 : 1;     /* pmflag or inetdflag is always TRUE */
993           if( (inetdflag && cmd->nflag)) { /* netid not allowed with inetdflag */
994             f_print(stderr, "Cannot use netid flag with inetd flag!\n");
995             return (0);
996           }
997         } else {  /* 4.1 mode */
998           pmflag = 0;               /* set pmflag only in tirpcmode */
999           inetdflag = 1;            /* inetdflag is TRUE by default */
1000           if( cmd->nflag ) {          /* netid needs TIRPC */
1001             f_print( stderr, "Cannot use netid flag without TIRPC!\n");
1002             return( 0 );
1003           }
1004         }
1005
1006         if( newstyle && ( tblflag || cmd->tflag) ) {
1007           f_print( stderr, "Cannot use table flags with newstyle!\n");
1008           return( 0 );
1009         }
1010
1011         /* check no conflicts with file generation flags */
1012         nflags = cmd->cflag + cmd->hflag + cmd->lflag + cmd->mflag +
1013                 cmd->sflag + cmd->nflag + cmd->tflag + cmd->Ssflag + cmd->Scflag;
1014
1015         if (nflags == 0) {
1016                 if (cmd->outfile != NULL || cmd->infile == NULL) {
1017                         return (0);
1018                 }
1019         } else if (nflags > 1) {
1020                 f_print( stderr, "Cannot have more than one file generation flag!\n");
1021                 return (0);
1022         }
1023         return (1);
1024 }
1025
1026 static void
1027 usage(void)
1028 {
1029         f_print(stderr, "usage:  %s infile\n", cmdname);
1030         f_print(stderr, "\t%s [-a][-b][-C][-Dname[=value]] -i size  [-I [-K seconds]] [-L][-N][-T] infile\n",
1031                         cmdname);
1032         f_print(stderr, "\t%s [-c | -h | -l | -m | -t | -Sc | -Ss] [-o outfile] [infile]\n",
1033                         cmdname);
1034         f_print(stderr, "\t%s [-s nettype]* [-o outfile] [infile]\n", cmdname);
1035         f_print(stderr, "\t%s [-n netid]* [-o outfile] [infile]\n", cmdname);
1036         options_usage();
1037         exit(1);
1038 }
1039
1040 static void
1041 options_usage(void)
1042 {
1043         f_print(stderr, "options:\n");
1044         f_print(stderr, "-a\t\tgenerate all files, including samples\n");
1045         f_print(stderr, "-b\t\tbackward compatibility mode (generates code for SunOS 4.1)\n");
1046         f_print(stderr, "-c\t\tgenerate XDR routines\n");
1047         f_print(stderr, "-C\t\tANSI C mode\n");
1048         f_print(stderr, "-Dname[=value]\tdefine a symbol (same as #define)\n");
1049         f_print(stderr, "-h\t\tgenerate header file\n");
1050         f_print(stderr, "-i size\t\tsize at which to start generating inline code\n");
1051         f_print(stderr, "-I\t\tgenerate code for inetd support in server (for SunOS 4.1)\n");
1052         f_print(stderr, "-K seconds\tserver exits after K seconds of inactivity\n");
1053         f_print(stderr, "-l\t\tgenerate client side stubs\n");
1054         f_print(stderr, "-L\t\tserver errors will be printed to syslog\n");
1055         f_print(stderr, "-m\t\tgenerate server side stubs\n");
1056         f_print(stderr, "-n netid\tgenerate server code that supports named netid\n");
1057         f_print(stderr, "-N\t\tsupports multiple arguments and call-by-value\n");
1058         f_print(stderr, "-o outfile\tname of the output file\n");
1059         f_print(stderr, "-s nettype\tgenerate server code that supports named nettype\n");
1060         f_print(stderr, "-Sc\t\tgenerate sample client code that uses remote procedures\n");
1061         f_print(stderr, "-Ss\t\tgenerate sample server code that defines remote procedures\n");
1062         f_print(stderr, "-t\t\tgenerate RPC dispatch table\n");
1063         f_print(stderr, "-T\t\tgenerate code to support RPC dispatch tables\n");
1064         f_print(stderr, "-Y path\t\tdirectory name to find C preprocessor (cpp)\n");
1065
1066         exit(1);
1067 }