Update to 2.17
[platform/upstream/glibc.git] / sunrpc / rpc_main.c
1 /*
2  * From @(#)rpc_main.c 1.30 89/03/30
3  *
4  * Copyright (c) 2010, Oracle America, Inc.
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  *       notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  *       copyright notice, this list of conditions and the following
13  *       disclaimer in the documentation and/or other materials
14  *       provided with the distribution.
15  *     * Neither the name of the "Oracle America, Inc." nor the names of its
16  *       contributors may be used to endorse or promote products derived
17  *       from this software without specific prior written permission.
18  *
19  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24  *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
26  *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 /*
34  * rpc_main.c, Top level of the RPC protocol compiler.
35  */
36
37 #include <errno.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <libintl.h>
42 #include <locale.h>
43 #include <ctype.h>
44 #include <sys/types.h>
45 #include <sys/param.h>
46 #include <sys/file.h>
47 #include <sys/stat.h>
48 #include <sys/wait.h>
49 #include "rpc_parse.h"
50 #include "rpc_util.h"
51 #include "rpc_scan.h"
52 #include "proto.h"
53
54 #include "../version.h"
55 #define PACKAGE _libc_intl_domainname
56
57 #define EXTEND  1               /* alias for TRUE */
58 #define DONT_EXTEND     0       /* alias for FALSE */
59
60 struct commandline
61   {
62     int cflag;                  /* xdr C routines */
63     int hflag;                  /* header file */
64     int lflag;                  /* client side stubs */
65     int mflag;                  /* server side stubs */
66     int nflag;                  /* netid flag */
67     int sflag;                  /* server stubs for the given transport */
68     int tflag;                  /* dispatch Table file */
69     int Ssflag;                 /* produce server sample code */
70     int Scflag;                 /* produce client sample code */
71     int makefileflag;           /* Generate a template Makefile */
72     const char *infile;         /* input module name */
73     const char *outfile;        /* output module name */
74   };
75
76
77 static const char *cmdname;
78
79 static const char *svcclosetime = "120";
80 static int cppDefined;  /* explicit path for C preprocessor */
81 static const char *CPP = "/lib/cpp";
82 static const char CPPFLAGS[] = "-C";
83 static char *pathbuf;
84 static int cpp_pid;
85 static const char *allv[] =
86 {
87   "rpcgen", "-s", "udp", "-s", "tcp"
88 };
89 static int allc = sizeof (allv) / sizeof (allv[0]);
90 static const char *allnv[] =
91 {
92   "rpcgen", "-s", "netpath",
93 };
94 static int allnc = sizeof (allnv) / sizeof (allnv[0]);
95
96 /*
97  * machinations for handling expanding argument list
98  */
99 static void addarg (const char *);      /* add another argument to the list */
100 static void putarg (int, const char *);         /* put argument at specified location */
101 static void clear_args (void);  /* clear argument list */
102 static void checkfiles (const char *, const char *);
103                                        /* check if out file already exists */
104
105 static void clear_args (void);
106 static char *extendfile (const char *file, const char *ext);
107 static void open_output (const char *infile, const char *outfile);
108 static void add_warning (void);
109 static void clear_args (void);
110 static void find_cpp (void);
111 static void open_input (const char *infile, const char *define);
112 static int check_nettype (const char *name, const char *list_to_check[]);
113 static void c_output (const char *infile, const char *define,
114                       int extend, const char *outfile);
115 static void h_output (const char *infile, const char *define,
116                       int extend, const char *outfile);
117 static void s_output (int argc, const char *argv[], const char *infile,
118                       const char *define, int extend,
119                       const char *outfile, int nomain, int netflag);
120 static void l_output (const char *infile, const char *define,
121                       int extend, const char *outfile);
122 static void t_output (const char *infile, const char *define,
123                       int extend, const char *outfile);
124 static void svc_output (const char *infile, const char *define,
125                         int extend, const char *outfile);
126 static void clnt_output (const char *infile, const char *define,
127                          int extend, const char *outfile);
128 static void mkfile_output (struct commandline *cmd);
129 static int do_registers (int argc, const char *argv[]);
130 static void addarg (const char *cp);
131 static void putarg (int whereto, const char *cp);
132 static void checkfiles (const char *infile, const char *outfile);
133 static int parseargs (int argc, const char *argv[], struct commandline *cmd);
134 static void usage (FILE *stream, int status) __attribute__ ((noreturn));
135 static void options_usage (FILE *stream, int status) __attribute__ ((noreturn));
136 static void print_version (void);
137 static void c_initialize (void);
138 static char *generate_guard (const char *pathname);
139
140
141 #define ARGLISTLEN      20
142 #define FIXEDARGS         2
143
144 static const char *arglist[ARGLISTLEN];
145 static int argcount = FIXEDARGS;
146
147
148 int nonfatalerrors;             /* errors */
149 int inetdflag /* = 1 */ ;       /* Support for inetd *//* is now the default */
150 int pmflag;                     /* Support for port monitors */
151 int logflag;                    /* Use syslog instead of fprintf for errors */
152 int tblflag;                    /* Support for dispatch table file */
153 int mtflag;                     /* Support for MT */
154
155 #define INLINE 3
156 /*length at which to start doing an inline */
157
158 int inlineflag = INLINE;        /* length at which to start doing an inline. 3 = default
159                                    if 0, no xdr_inline code */
160
161 int indefinitewait;             /* If started by port monitors, hang till it wants */
162 int exitnow;                    /* If started by port monitors, exit after the call */
163 int timerflag;                  /* TRUE if !indefinite && !exitnow */
164 int newstyle;                   /* newstyle of passing arguments (by value) */
165 int Cflag = 1;                  /* ANSI C syntax */
166 int CCflag;                     /* C++ files */
167 static int allfiles;            /* generate all files */
168 int tirpcflag;                  /* generating code for tirpc, by default */
169 xdrfunc *xdrfunc_head;          /* xdr function list */
170 xdrfunc *xdrfunc_tail;          /* xdr function list */
171
172 int
173 main (int argc, const char *argv[])
174 {
175   struct commandline cmd;
176
177   setlocale (LC_ALL, "");
178   textdomain (_libc_intl_domainname);
179
180   (void) memset ((char *) &cmd, 0, sizeof (struct commandline));
181   clear_args ();
182   if (!parseargs (argc, argv, &cmd))
183     usage (stderr, 1);
184
185   if (cmd.cflag || cmd.hflag || cmd.lflag || cmd.tflag || cmd.sflag ||
186       cmd.mflag || cmd.nflag || cmd.Ssflag || cmd.Scflag)
187     {
188       checkfiles (cmd.infile, cmd.outfile);
189     }
190   else
191     checkfiles (cmd.infile, NULL);
192
193   if (cmd.cflag)
194     c_output (cmd.infile, "-DRPC_XDR", DONT_EXTEND, cmd.outfile);
195   else if (cmd.hflag)
196     h_output (cmd.infile, "-DRPC_HDR", DONT_EXTEND, cmd.outfile);
197   else if (cmd.lflag)
198     l_output (cmd.infile, "-DRPC_CLNT", DONT_EXTEND, cmd.outfile);
199   else if (cmd.sflag || cmd.mflag || (cmd.nflag))
200     s_output (argc, argv, cmd.infile, "-DRPC_SVC", DONT_EXTEND,
201               cmd.outfile, cmd.mflag, cmd.nflag);
202   else if (cmd.tflag)
203     t_output (cmd.infile, "-DRPC_TBL", DONT_EXTEND, cmd.outfile);
204   else if (cmd.Ssflag)
205     svc_output (cmd.infile, "-DRPC_SERVER", DONT_EXTEND, cmd.outfile);
206   else if (cmd.Scflag)
207     clnt_output (cmd.infile, "-DRPC_CLIENT", DONT_EXTEND, cmd.outfile);
208   else if (cmd.makefileflag)
209     mkfile_output (&cmd);
210   else
211     {
212       /* the rescans are required, since cpp may effect input */
213       c_output (cmd.infile, "-DRPC_XDR", EXTEND, "_xdr.c");
214       reinitialize ();
215       h_output (cmd.infile, "-DRPC_HDR", EXTEND, ".h");
216       reinitialize ();
217       l_output (cmd.infile, "-DRPC_CLNT", EXTEND, "_clnt.c");
218       reinitialize ();
219       if (inetdflag || !tirpcflag)
220         s_output (allc, allv, cmd.infile, "-DRPC_SVC", EXTEND,
221                   "_svc.c", cmd.mflag, cmd.nflag);
222       else
223         s_output (allnc, allnv, cmd.infile, "-DRPC_SVC",
224                   EXTEND, "_svc.c", cmd.mflag, cmd.nflag);
225       if (tblflag)
226         {
227           reinitialize ();
228           t_output (cmd.infile, "-DRPC_TBL", EXTEND, "_tbl.i");
229         }
230       if (allfiles)
231         {
232           reinitialize ();
233           svc_output (cmd.infile, "-DRPC_SERVER", EXTEND, "_server.c");
234           reinitialize ();
235           clnt_output (cmd.infile, "-DRPC_CLIENT", EXTEND, "_client.c");
236         }
237       if (allfiles || (cmd.makefileflag == 1))
238         {
239           reinitialize ();
240           mkfile_output (&cmd);
241         }
242     }
243
244   return nonfatalerrors;
245 }
246
247 /*
248  * add extension to filename
249  */
250 static char *
251 extendfile (const char *file, const char *ext)
252 {
253   char *res;
254   const char *p;
255
256   res = alloc (strlen (file) + strlen (ext) + 1);
257   if (res == NULL)
258     abort ();
259   p = strrchr (file, '.');
260   if (p == NULL)
261     p = file + strlen (file);
262   strcpy (res, file);
263   strcpy (res + (p - file), ext);
264   return res;
265 }
266
267 /*
268  * Open output file with given extension
269  */
270 static void
271 open_output (const char *infile, const char *outfile)
272 {
273   if (outfile == NULL)
274     {
275       fout = stdout;
276       return;
277     }
278
279   if (infile != NULL && streq (outfile, infile))
280     {
281       fprintf (stderr, _ ("%s: output would overwrite %s\n"), cmdname,
282                infile);
283       crash ();
284     }
285   fout = fopen (outfile, "w");
286   if (fout == NULL)
287     {
288       fprintf (stderr, _ ("%s: unable to open %s: %m\n"), cmdname, outfile);
289       crash ();
290     }
291   record_open (outfile);
292 }
293
294 /* Close the output file and check for write errors.  */
295 static void
296 close_output (const char *outfile)
297 {
298   if (fclose (fout) == EOF)
299     {
300       fprintf (stderr, _("%s: while writing output %s: %m"), cmdname,
301                outfile ?: "<stdout>");
302       crash ();
303     }
304 }
305
306 static void
307 add_warning (void)
308 {
309   fprintf (fout, "/*\n");
310   fprintf (fout, " * Please do not edit this file.\n");
311   fprintf (fout, " * It was generated using rpcgen.\n");
312   fprintf (fout, " */\n\n");
313 }
314
315 /* clear list of arguments */
316 static void
317 clear_args (void)
318 {
319   int i;
320   for (i = FIXEDARGS; i < ARGLISTLEN; ++i)
321     arglist[i] = NULL;
322   argcount = FIXEDARGS;
323 }
324
325 /* make sure that a CPP exists */
326 static void
327 find_cpp (void)
328 {
329   struct stat64 buf;
330
331   if (stat64 (CPP, &buf) == 0)
332     return;
333
334   if (cppDefined) /* user specified cpp but it does not exist */
335     {
336       fprintf (stderr, _ ("cannot find C preprocessor: %s\n"), CPP);
337       crash ();
338     }
339
340   /* fall back to system CPP */
341   CPP = "cpp";
342 }
343
344 /*
345  * Open input file with given define for C-preprocessor
346  */
347 static void
348 open_input (const char *infile, const char *define)
349 {
350   int pd[2];
351
352   infilename = (infile == NULL) ? "<stdin>" : infile;
353   if (pipe (pd) != 0)
354     {
355       perror ("pipe");
356       exit (1);
357     }
358   cpp_pid = fork ();
359   switch (cpp_pid)
360     {
361     case 0:
362       find_cpp ();
363       putarg (0, CPP);
364       putarg (1, CPPFLAGS);
365       addarg (define);
366       if (infile)
367         addarg (infile);
368       addarg ((char *) NULL);
369       close (1);
370       dup2 (pd[1], 1);
371       close (pd[0]);
372       execvp (arglist[0], (char **) arglist);
373       if (errno == ENOENT)
374         {
375           fprintf (stderr, _ ("cannot find C preprocessor: %s\n"), CPP);
376           exit (1);
377         }
378       perror ("execvp");
379       exit (1);
380     case -1:
381       perror ("fork");
382       exit (1);
383     }
384   close (pd[1]);
385   fin = fdopen (pd[0], "r");
386   if (fin == NULL)
387     {
388       fprintf (stderr, "%s: ", cmdname);
389       perror (infilename);
390       crash ();
391     }
392 }
393
394 /* Close the connection to the C-preprocessor and check for successfull
395    termination.  */
396 static void
397 close_input (void)
398 {
399   int status;
400
401   fclose (fin);
402   /* Check the termination status.  */
403   if (waitpid (cpp_pid, &status, 0) < 0)
404     {
405       perror ("waitpid");
406       crash ();
407     }
408   if (WIFSIGNALED (status) || WEXITSTATUS (status) != 0)
409     {
410       if (WIFSIGNALED (status))
411         fprintf (stderr, _("%s: C preprocessor failed with signal %d\n"),
412                  cmdname, WTERMSIG (status));
413       else
414         fprintf (stderr, _("%s: C preprocessor failed with exit code %d\n"),
415                  cmdname, WEXITSTATUS (status));
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     {
449       if (strcmp (name, list_to_check[i]) == 0)
450         {
451           return 1;
452         }
453     }
454   fprintf (stderr, _ ("illegal nettype: `%s'\n"), name);
455   return 0;
456 }
457
458 /*
459  * Compile into an XDR routine output file
460  */
461
462 static void
463 c_output (const char *infile, const char *define, int extend,
464           const char *outfile)
465 {
466   definition *def;
467   char *include;
468   const char *outfilename;
469   long tell;
470
471   c_initialize ();
472   open_input (infile, define);
473   outfilename = extend ? extendfile (infile, outfile) : outfile;
474   open_output (infile, outfilename);
475   add_warning ();
476   if (infile && (include = extendfile (infile, ".h")))
477     {
478       fprintf (fout, "#include \"%s\"\n", include);
479       free (include);
480       /* .h file already contains rpc/rpc.h */
481     }
482   else
483     fprintf (fout, "#include <rpc/rpc.h>\n");
484   tell = ftell (fout);
485   while ((def = get_definition ()) != NULL)
486     emit (def);
487
488   if (extend && tell == ftell (fout))
489     unlink (outfilename);
490   close_input ();
491   close_output (outfilename);
492 }
493
494 void
495 c_initialize (void)
496 {
497
498   /* add all the starting basic types */
499
500   add_type (1, "int");
501   add_type (1, "long");
502   add_type (1, "short");
503   add_type (1, "bool");
504
505   add_type (1, "u_int");
506   add_type (1, "u_long");
507   add_type (1, "u_short");
508
509 }
510
511 char rpcgen_table_dcl[] = "struct rpcgen_table {\n\
512         char    *(*proc)();\n\
513         xdrproc_t       xdr_arg;\n\
514         unsigned        len_arg;\n\
515         xdrproc_t       xdr_res;\n\
516         unsigned        len_res;\n\
517 };\n";
518
519
520 static char *
521 generate_guard (const char *pathname)
522 {
523   const char *filename;
524   char *guard, *tmp;
525
526   filename = strrchr (pathname, '/');   /* find last component */
527   filename = ((filename == NULL) ? pathname : filename + 1);
528   guard = extendfile (filename, "_H_RPCGEN");
529   /* convert to upper case */
530   tmp = guard;
531   while (*tmp)
532     {
533       if (islower (*tmp))
534         *tmp = toupper (*tmp);
535       tmp++;
536     }
537
538   return guard;
539 }
540
541 /*
542  * Compile into an XDR header file
543  */
544
545
546 static void
547 h_output (const char *infile, const char *define, int extend,
548           const char *outfile)
549 {
550   xdrfunc *xdrfuncp;
551   definition *def;
552   const char *ifilename;
553   const char *outfilename;
554   long tell;
555   char *guard;
556   list *l;
557
558   open_input (infile, define);
559   outfilename = extend ? extendfile (infile, outfile) : outfile;
560   open_output (infile, outfilename);
561   add_warning ();
562   ifilename = (infile == NULL) ? "STDIN" : infile;
563   guard = generate_guard (outfilename ? outfilename : ifilename);
564
565   fprintf (fout, "#ifndef _%s\n#define _%s\n\n", guard,
566            guard);
567
568   fprintf (fout, "#include <rpc/rpc.h>\n\n");
569
570   if (mtflag)
571     {
572       fprintf (fout, "#include <pthread.h>\n");
573     }
574
575   /* put the C++ support */
576   if (Cflag && !CCflag)
577     {
578       fprintf (fout, "\n#ifdef __cplusplus\n");
579       fprintf (fout, "extern \"C\" {\n");
580       fprintf (fout, "#endif\n\n");
581     }
582
583   tell = ftell (fout);
584   /* print data definitions */
585   while ((def = get_definition ()) != NULL)
586     {
587       print_datadef (def);
588     }
589
590   /* print function declarations.
591      Do this after data definitions because they might be used as
592      arguments for functions */
593   for (l = defined; l != NULL; l = l->next)
594     {
595       print_funcdef (l->val);
596     }
597   /* Now  print all xdr func declarations */
598   if (xdrfunc_head != NULL)
599     {
600       fprintf (fout, "\n/* the xdr functions */\n");
601       if (CCflag)
602         {
603           fprintf (fout, "\n#ifdef __cplusplus\n");
604           fprintf (fout, "extern \"C\" {\n");
605           fprintf (fout, "#endif\n");
606         }
607       if (!Cflag)
608         {
609           xdrfuncp = xdrfunc_head;
610           while (xdrfuncp != NULL)
611             {
612               print_xdr_func_def (xdrfuncp->name,
613                                   xdrfuncp->pointerp, 2);
614               xdrfuncp = xdrfuncp->next;
615             }
616         }
617       else
618         {
619           int i;
620
621           for (i = 1; i < 3; ++i)
622             {
623               if (i == 1)
624                 fprintf (fout, "\n#if defined(__STDC__) || defined(__cplusplus)\n");
625               else
626                 fprintf (fout, "\n#else /* K&R C */\n");
627
628               xdrfuncp = xdrfunc_head;
629               while (xdrfuncp != NULL)
630                 {
631                   print_xdr_func_def (xdrfuncp->name,
632                                       xdrfuncp->pointerp, i);
633                   xdrfuncp = xdrfuncp->next;
634                 }
635             }
636           fprintf (fout, "\n#endif /* K&R C */\n");
637         }
638     }
639
640   if (extend && tell == ftell (fout))
641     {
642       unlink (outfilename);
643     }
644   else if (tblflag)
645     {
646       fprintf (fout, "%s", rpcgen_table_dcl);
647     }
648
649   if (Cflag)
650     {
651       fprintf (fout, "\n#ifdef __cplusplus\n");
652       fprintf (fout, "}\n");
653       fprintf (fout, "#endif\n");
654     }
655
656   fprintf (fout, "\n#endif /* !_%s */\n", guard);
657   free (guard);
658   close_input ();
659   close_output (outfilename);
660 }
661
662 /*
663  * Compile into an RPC service
664  */
665 static void
666 s_output (int argc, const char *argv[], const char *infile, const char *define,
667           int extend, const char *outfile, int nomain, int netflag)
668 {
669   char *include;
670   definition *def;
671   int foundprogram = 0;
672   const char *outfilename;
673
674   open_input (infile, define);
675   outfilename = extend ? extendfile (infile, outfile) : outfile;
676   open_output (infile, outfilename);
677   add_warning ();
678   if (infile && (include = extendfile (infile, ".h")))
679     {
680       fprintf (fout, "#include \"%s\"\n", include);
681       free (include);
682     }
683   else
684     fprintf (fout, "#include <rpc/rpc.h>\n");
685
686   fprintf (fout, "#include <stdio.h>\n");
687   fprintf (fout, "#include <stdlib.h>\n");
688   fprintf (fout, "#include <rpc/pmap_clnt.h>\n");
689   if (Cflag)
690     fprintf (fout, "#include <string.h>\n");
691   if (strcmp (svcclosetime, "-1") == 0)
692     indefinitewait = 1;
693   else if (strcmp (svcclosetime, "0") == 0)
694     exitnow = 1;
695   else if (inetdflag || pmflag)
696     {
697       fprintf (fout, "#include <signal.h>\n");
698       timerflag = 1;
699     }
700
701   if (!tirpcflag && inetdflag)
702     fprintf (fout, "#include <sys/ioctl.h> /* ioctl, TIOCNOTTY */\n");
703   if (Cflag && (inetdflag || pmflag))
704     {
705       fprintf (fout, "#include <sys/types.h> /* open */\n");
706       fprintf (fout, "#include <sys/stat.h> /* open */\n");
707       fprintf (fout, "#include <fcntl.h> /* open */\n");
708       fprintf (fout, "#include <unistd.h> /* getdtablesize */\n");
709     }
710   if (tirpcflag && !(Cflag && (inetdflag || pmflag)))
711     fprintf (fout, "#include <sys/types.h>\n");
712
713   fprintf (fout, "#include <memory.h>\n");
714   if (inetdflag || !tirpcflag)
715     {
716       fprintf (fout, "#include <sys/socket.h>\n");
717       fprintf (fout, "#include <netinet/in.h>\n");
718     }
719
720   if ((netflag || pmflag) && tirpcflag && !nomain)
721     {
722       fprintf (fout, "#include <netconfig.h>\n");
723     }
724   if ( /*timerflag && */ tirpcflag)
725     fprintf (fout, "#include <sys/resource.h> /* rlimit */\n");
726   if (logflag || inetdflag || pmflag)
727     {
728       fprintf (fout, "#include <syslog.h>\n");
729     }
730
731   /* for ANSI-C */
732   if (Cflag)
733     fprintf (fout, "\n#ifndef SIG_PF\n#define SIG_PF void(*)(int)\n#endif\n");
734
735   if (timerflag)
736     fprintf (fout, "\n#define _RPCSVC_CLOSEDOWN %s\n", svcclosetime);
737   while ((def = get_definition ()) != NULL)
738     {
739       foundprogram |= (def->def_kind == DEF_PROGRAM);
740     }
741   if (extend && !foundprogram)
742     {
743       unlink (outfilename);
744       return;
745     }
746   write_most (infile, netflag, nomain);
747   if (!nomain)
748     {
749       if (!do_registers (argc, argv))
750         {
751           if (outfilename)
752             unlink (outfilename);
753           usage (stderr, 1);
754         }
755       write_rest ();
756     }
757   close_input ();
758   close_output (outfilename);
759 }
760
761 /*
762  * generate client side stubs
763  */
764 static void
765 l_output (const char *infile, const char *define, int extend,
766           const char *outfile)
767 {
768   char *include;
769   definition *def;
770   int foundprogram = 0;
771   const char *outfilename;
772
773   open_input (infile, define);
774   outfilename = extend ? extendfile (infile, outfile) : outfile;
775   open_output (infile, outfilename);
776   add_warning ();
777   if (Cflag)
778     fprintf (fout, "#include <memory.h> /* for memset */\n");
779   if (infile && (include = extendfile (infile, ".h")))
780     {
781       fprintf (fout, "#include \"%s\"\n", include);
782       free (include);
783     }
784   else
785     fprintf (fout, "#include <rpc/rpc.h>\n");
786   while ((def = get_definition ()) != NULL)
787     {
788       foundprogram |= (def->def_kind == DEF_PROGRAM);
789     }
790   if (extend && !foundprogram)
791     {
792       unlink (outfilename);
793       return;
794     }
795   write_stubs ();
796   close_input ();
797   close_output (outfilename);
798 }
799
800 /*
801  * generate the dispatch table
802  */
803 static void
804 t_output (const char *infile, const char *define, int extend,
805           const char *outfile)
806 {
807   definition *def;
808   int foundprogram = 0;
809   const char *outfilename;
810
811   open_input (infile, define);
812   outfilename = extend ? extendfile (infile, outfile) : outfile;
813   open_output (infile, outfilename);
814   add_warning ();
815   while ((def = get_definition ()) != NULL)
816     {
817       foundprogram |= (def->def_kind == DEF_PROGRAM);
818     }
819   if (extend && !foundprogram)
820     {
821       unlink (outfilename);
822       return;
823     }
824   write_tables ();
825   close_input ();
826   close_output (outfilename);
827 }
828
829 /* sample routine for the server template */
830 static void
831 svc_output (const char *infile, const char *define, int extend,
832             const char *outfile)
833 {
834   definition *def;
835   char *include;
836   const char *outfilename;
837   long tell;
838
839   open_input (infile, define);
840   outfilename = extend ? extendfile (infile, outfile) : outfile;
841   checkfiles (infile, outfilename);
842   /*check if outfile already exists.
843      if so, print an error message and exit */
844   open_output (infile, outfilename);
845   add_sample_msg ();
846
847   if (infile && (include = extendfile (infile, ".h")))
848     {
849       fprintf (fout, "#include \"%s\"\n", include);
850       free (include);
851     }
852   else
853     fprintf (fout, "#include <rpc/rpc.h>\n");
854
855   tell = ftell (fout);
856   while ((def = get_definition ()) != NULL)
857     {
858       write_sample_svc (def);
859     }
860   if (extend && tell == ftell (fout))
861     {
862       unlink (outfilename);
863     }
864   close_input ();
865   close_output (outfilename);
866 }
867
868
869 /* sample main routine for client */
870 static void
871 clnt_output (const char *infile, const char *define, int extend,
872              const char *outfile)
873 {
874   definition *def;
875   char *include;
876   const char *outfilename;
877   long tell;
878   int has_program = 0;
879
880   open_input (infile, define);
881   outfilename = extend ? extendfile (infile, outfile) : outfile;
882   checkfiles (infile, outfilename);
883   /*check if outfile already exists.
884      if so, print an error message and exit */
885
886   open_output (infile, outfilename);
887   add_sample_msg ();
888   if (infile && (include = extendfile (infile, ".h")))
889     {
890       fprintf (fout, "#include \"%s\"\n", include);
891       free (include);
892     }
893   else
894     fprintf (fout, "#include <rpc/rpc.h>\n");
895   tell = ftell (fout);
896   while ((def = get_definition ()) != NULL)
897     {
898       has_program += write_sample_clnt (def);
899     }
900
901   if (has_program)
902     write_sample_clnt_main ();
903
904   if (extend && tell == ftell (fout))
905     {
906       unlink (outfilename);
907     }
908   close_input ();
909   close_output (outfilename);
910 }
911
912 static const char space[] = " ";
913
914 static char *
915 file_name (const char *file, const char *ext)
916 {
917   char *temp;
918   temp = extendfile (file, ext);
919
920   if (access (temp, F_OK) != -1)
921     return (temp);
922
923   free (temp);
924   return (char *) space;
925 }
926
927 static void
928 mkfile_output (struct commandline *cmd)
929 {
930   char *mkfilename;
931   char *clientname, *clntname, *xdrname, *hdrname;
932   char *servername, *svcname, *servprogname, *clntprogname;
933
934   svcname = file_name (cmd->infile, "_svc.c");
935   clntname = file_name (cmd->infile, "_clnt.c");
936   xdrname = file_name (cmd->infile, "_xdr.c");
937   hdrname = file_name (cmd->infile, ".h");
938
939   if (allfiles)
940     {
941       servername = extendfile (cmd->infile, "_server.c");
942       clientname = extendfile (cmd->infile, "_client.c");
943     }
944   else
945     {
946       servername = (char *) space;
947       clientname = (char *) space;
948     }
949   servprogname = extendfile (cmd->infile, "_server");
950   clntprogname = extendfile (cmd->infile, "_client");
951
952   if (allfiles)
953     {
954       char *cp, *temp;
955
956       mkfilename = alloc (strlen ("Makefile.") + strlen (cmd->infile) + 1);
957       if (mkfilename == NULL)
958         abort ();
959       temp = rindex (cmd->infile, '.');
960       cp = stpcpy (mkfilename, "Makefile.");
961       if (temp != NULL)
962         *((char *) stpncpy (cp, cmd->infile, temp - cmd->infile)) = '\0';
963       else
964         stpcpy (cp, cmd->infile);
965
966     }
967   else
968     mkfilename = (char *) cmd->outfile;
969
970   checkfiles (NULL, mkfilename);
971   open_output (NULL, mkfilename);
972
973   fprintf (fout, "\n# This is a template Makefile generated by rpcgen\n");
974
975   f_print (fout, "\n# Parameters\n\n");
976
977   f_print (fout, "CLIENT = %s\nSERVER = %s\n\n", clntprogname, servprogname);
978   f_print (fout, "SOURCES_CLNT.c = \nSOURCES_CLNT.h = \n");
979   f_print (fout, "SOURCES_SVC.c = \nSOURCES_SVC.h = \n");
980   f_print (fout, "SOURCES.x = %s\n\n", cmd->infile);
981   f_print (fout, "TARGETS_SVC.c = %s %s %s \n",
982            svcname, servername, xdrname);
983   f_print (fout, "TARGETS_CLNT.c = %s %s %s \n",
984            clntname, clientname, xdrname);
985   f_print (fout, "TARGETS = %s %s %s %s %s %s\n\n",
986            hdrname, xdrname, clntname,
987            svcname, clientname, servername);
988
989   f_print (fout, "OBJECTS_CLNT = $(SOURCES_CLNT.c:%%.c=%%.o) \
990 $(TARGETS_CLNT.c:%%.c=%%.o)");
991
992   f_print (fout, "\nOBJECTS_SVC = $(SOURCES_SVC.c:%%.c=%%.o) \
993 $(TARGETS_SVC.c:%%.c=%%.o)");
994
995   f_print (fout, "\n# Compiler flags \n");
996   if (mtflag)
997     fprintf (fout, "\nCPPFLAGS += -D_REENTRANT\nCFLAGS += -g \nLDLIBS \
998 += -lnsl -lpthread \n ");
999   else
1000     f_print (fout, "\nCFLAGS += -g \nLDLIBS += -lnsl\n");
1001   f_print (fout, "RPCGENFLAGS = \n");
1002
1003   f_print (fout, "\n# Targets \n\n");
1004
1005   f_print (fout, "all : $(CLIENT) $(SERVER)\n\n");
1006   f_print (fout, "$(TARGETS) : $(SOURCES.x) \n");
1007   f_print (fout, "\trpcgen $(RPCGENFLAGS) $(SOURCES.x)\n\n");
1008   f_print (fout, "$(OBJECTS_CLNT) : $(SOURCES_CLNT.c) $(SOURCES_CLNT.h) \
1009 $(TARGETS_CLNT.c) \n\n");
1010
1011   f_print (fout, "$(OBJECTS_SVC) : $(SOURCES_SVC.c) $(SOURCES_SVC.h) \
1012 $(TARGETS_SVC.c) \n\n");
1013   f_print (fout, "$(CLIENT) : $(OBJECTS_CLNT) \n");
1014   f_print (fout, "\t$(LINK.c) -o $(CLIENT) $(OBJECTS_CLNT) \
1015 $(LDLIBS) \n\n");
1016   f_print (fout, "$(SERVER) : $(OBJECTS_SVC) \n");
1017   f_print (fout, "\t$(LINK.c) -o $(SERVER) $(OBJECTS_SVC) $(LDLIBS)\n\n ");
1018   f_print (fout, "clean:\n\t $(RM) core $(TARGETS) $(OBJECTS_CLNT) \
1019 $(OBJECTS_SVC) $(CLIENT) $(SERVER)\n\n");
1020   close_output (mkfilename);
1021
1022   free (clntprogname);
1023   free (servprogname);
1024   if (servername != space)
1025     free (servername);
1026   if (clientname != space)
1027     free (clientname);
1028   if (mkfilename != (char *) cmd->outfile)
1029     free (mkfilename);
1030   if (svcname != space)
1031     free (svcname);
1032   if (clntname != space)
1033     free (clntname);
1034   if (xdrname != space)
1035     free (xdrname);
1036   if (hdrname != space)
1037     free (hdrname);
1038 }
1039
1040 /*
1041  * Perform registrations for service output
1042  * Return 0 if failed; 1 otherwise.
1043  */
1044 static int
1045 do_registers (int argc, const char *argv[])
1046 {
1047   int i;
1048
1049   if (inetdflag || !tirpcflag)
1050     {
1051       for (i = 1; i < argc; i++)
1052         {
1053           if (streq (argv[i], "-s"))
1054             {
1055               if (!check_nettype (argv[i + 1], valid_i_nettypes))
1056                 return 0;
1057               write_inetd_register (argv[i + 1]);
1058               i++;
1059             }
1060         }
1061     }
1062   else
1063     {
1064       for (i = 1; i < argc; i++)
1065         if (streq (argv[i], "-s"))
1066           {
1067             if (!check_nettype (argv[i + 1], valid_ti_nettypes))
1068               return 0;
1069             write_nettype_register (argv[i + 1]);
1070             i++;
1071           }
1072         else if (streq (argv[i], "-n"))
1073           {
1074             write_netid_register (argv[i + 1]);
1075             i++;
1076           }
1077     }
1078   return 1;
1079 }
1080
1081 /*
1082  * Add another argument to the arg list
1083  */
1084 static void
1085 addarg (const char *cp)
1086 {
1087   if (argcount >= ARGLISTLEN)
1088     {
1089       fprintf (stderr, _("rpcgen: too many defines\n"));
1090       crash ();
1091       /*NOTREACHED */
1092     }
1093   arglist[argcount++] = cp;
1094 }
1095
1096 static void
1097 putarg (int whereto, const char *cp)
1098 {
1099   if (whereto >= ARGLISTLEN)
1100     {
1101       fprintf (stderr, _("rpcgen: arglist coding error\n"));
1102       crash ();
1103       /*NOTREACHED */
1104     }
1105   arglist[whereto] = cp;
1106 }
1107
1108 /*
1109  * if input file is stdin and an output file is specified then complain
1110  * if the file already exists. Otherwise the file may get overwritten
1111  * If input file does not exist, exit with an error
1112  */
1113
1114 static void
1115 checkfiles (const char *infile, const char *outfile)
1116 {
1117   struct stat64 buf;
1118
1119   if (infile)                   /* infile ! = NULL */
1120     if (stat64 (infile, &buf) < 0)
1121       {
1122         perror (infile);
1123         crash ();
1124       }
1125   if (outfile)
1126     {
1127       if (stat64 (outfile, &buf) < 0)
1128         return;                 /* file does not exist */
1129       else
1130         {
1131           fprintf (stderr,
1132                    /* TRANS: the file will not be removed; this is an
1133                       TRANS: informative message.  */
1134                    _("file `%s' already exists and may be overwritten\n"),
1135                    outfile);
1136           crash ();
1137         }
1138     }
1139 }
1140
1141 /*
1142  * Parse command line arguments
1143  */
1144 static int
1145 parseargs (int argc, const char *argv[], struct commandline *cmd)
1146 {
1147   int i;
1148   int j;
1149   int c;
1150   char flag[(1 << 8 * sizeof (char))];
1151   int nflags;
1152
1153   cmdname = argv[0];
1154   cmd->infile = cmd->outfile = NULL;
1155   if (argc < 2)
1156     {
1157       return (0);
1158     }
1159   allfiles = 0;
1160   flag['c'] = 0;
1161   flag['h'] = 0;
1162   flag['l'] = 0;
1163   flag['m'] = 0;
1164   flag['o'] = 0;
1165   flag['s'] = 0;
1166   flag['n'] = 0;
1167   flag['t'] = 0;
1168   flag['S'] = 0;
1169   flag['C'] = 0;
1170   flag['M'] = 0;
1171
1172   for (i = 1; i < argc; i++)
1173     {
1174       if (argv[i][0] != '-')
1175         {
1176           if (cmd->infile)
1177             {
1178               fprintf (stderr,
1179                        _("Cannot specify more than one input file!\n"));
1180               return 0;
1181             }
1182           cmd->infile = argv[i];
1183         }
1184       else if (strcmp (argv[i], "--help") == 0)
1185         usage (stdout, 0);
1186       else if (strcmp (argv[i], "--version") == 0)
1187         print_version ();
1188       else
1189         {
1190           for (j = 1; argv[i][j] != 0; j++)
1191             {
1192               c = argv[i][j];
1193               switch (c)
1194                 {
1195                 case 'a':
1196                   allfiles = 1;
1197                   break;
1198                 case 'c':
1199                 case 'h':
1200                 case 'l':
1201                 case 'm':
1202                 case 't':
1203                   if (flag[c])
1204                     return 0;
1205                   flag[c] = 1;
1206                   break;
1207                 case 'S':
1208                   /* sample flag: Ss or Sc.
1209                      Ss means set flag['S'];
1210                      Sc means set flag['C'];
1211                      Sm means set flag['M']; */
1212                   c = argv[i][++j];     /* get next char */
1213                   if (c == 's')
1214                     c = 'S';
1215                   else if (c == 'c')
1216                     c = 'C';
1217                   else if (c == 'm')
1218                     c = 'M';
1219                   else
1220                     return 0;
1221
1222                   if (flag[c])
1223                     return 0;
1224                   flag[c] = 1;
1225                   break;
1226                 case 'C':       /* ANSI C syntax */
1227                   Cflag = 1;
1228                   break;
1229
1230                 case 'k':  /* K&R C syntax */
1231                   Cflag = 0;
1232                   break;
1233
1234                 case 'b':  /* turn TIRPC flag off for
1235                               generating backward compatible
1236                            */
1237                   tirpcflag = 0;
1238                   break;
1239
1240                 case '5':  /* turn TIRPC flag on for
1241                               generating SysVr4 compatible
1242                            */
1243                   tirpcflag = 1;
1244                   break;
1245                 case 'I':
1246                   inetdflag = 1;
1247                   break;
1248                 case 'N':
1249                   newstyle = 1;
1250                   break;
1251                 case 'L':
1252                   logflag = 1;
1253                   break;
1254                 case 'K':
1255                   if (++i == argc)
1256                     {
1257                       return (0);
1258                     }
1259                   svcclosetime = argv[i];
1260                   goto nextarg;
1261                 case 'T':
1262                   tblflag = 1;
1263                   break;
1264                 case 'M':
1265                   mtflag = 1;
1266                   break;
1267                 case 'i':
1268                   if (++i == argc)
1269                     {
1270                       return (0);
1271                     }
1272                   inlineflag = atoi (argv[i]);
1273                   goto nextarg;
1274                 case 'n':
1275                 case 'o':
1276                 case 's':
1277                   if (argv[i][j - 1] != '-' ||
1278                       argv[i][j + 1] != 0)
1279                     {
1280                       return (0);
1281                     }
1282                   flag[c] = 1;
1283                   if (++i == argc)
1284                     {
1285                       return (0);
1286                     }
1287                   if (c == 's')
1288                     {
1289                       if (!streq (argv[i], "udp") &&
1290                           !streq (argv[i], "tcp"))
1291                         return 0;
1292                     }
1293                   else if (c == 'o')
1294                     {
1295                       if (cmd->outfile)
1296                         return 0;
1297                       cmd->outfile = argv[i];
1298                     }
1299                   goto nextarg;
1300                 case 'D':
1301                   if (argv[i][j - 1] != '-')
1302                     return 0;
1303                   addarg (argv[i]);
1304                   goto nextarg;
1305                 case 'Y':
1306                   if (++i == argc)
1307                     return 0;
1308                   {
1309                     size_t len = strlen (argv[i]);
1310                     pathbuf = malloc (len + 5);
1311                     if (pathbuf == NULL)
1312                       {
1313                         perror (cmdname);
1314                         crash ();
1315                       }
1316                     stpcpy (stpcpy (pathbuf,
1317                                     argv[i]),
1318                             "/cpp");
1319                     CPP = pathbuf;
1320                     cppDefined = 1;
1321                     goto nextarg;
1322                   }
1323
1324                 default:
1325                   return 0;
1326                 }
1327               }
1328         nextarg:
1329           ;
1330         }
1331     }
1332
1333   cmd->cflag = flag['c'];
1334   cmd->hflag = flag['h'];
1335   cmd->lflag = flag['l'];
1336   cmd->mflag = flag['m'];
1337   cmd->nflag = flag['n'];
1338   cmd->sflag = flag['s'];
1339   cmd->tflag = flag['t'];
1340   cmd->Ssflag = flag['S'];
1341   cmd->Scflag = flag['C'];
1342   cmd->makefileflag = flag['M'];
1343
1344 #ifndef _RPC_THREAD_SAFE_
1345   if (mtflag || newstyle)
1346     {
1347       /* glibc doesn't support these flags.  */
1348       f_print (stderr,
1349                _("This implementation doesn't support newstyle or MT-safe code!\n"));
1350       return (0);
1351     }
1352 #endif
1353   if (tirpcflag)
1354     {
1355       pmflag = inetdflag ? 0 : 1;    /* pmflag or inetdflag is always TRUE */
1356       if ((inetdflag && cmd->nflag))
1357         {                       /* netid not allowed with inetdflag */
1358           fprintf (stderr, _("Cannot use netid flag with inetd flag!\n"));
1359           return 0;
1360         }
1361     }
1362   else
1363     {                           /* 4.1 mode */
1364       pmflag = 0;               /* set pmflag only in tirpcmode */
1365       if (cmd->nflag)
1366         {                       /* netid needs TIRPC */
1367           f_print (stderr, _("Cannot use netid flag without TIRPC!\n"));
1368           return (0);
1369         }
1370     }
1371
1372   if (newstyle && (tblflag || cmd->tflag))
1373     {
1374       f_print (stderr, _("Cannot use table flags with newstyle!\n"));
1375       return (0);
1376     }
1377
1378   /* check no conflicts with file generation flags */
1379   nflags = cmd->cflag + cmd->hflag + cmd->lflag + cmd->mflag +
1380     cmd->sflag + cmd->nflag + cmd->tflag + cmd->Ssflag + cmd->Scflag;
1381
1382   if (nflags == 0)
1383     {
1384       if (cmd->outfile != NULL || cmd->infile == NULL)
1385         {
1386           return (0);
1387         }
1388     }
1389   else if (cmd->infile == NULL &&
1390            (cmd->Ssflag || cmd->Scflag || cmd->makefileflag))
1391     {
1392       fprintf (stderr,
1393                _("\"infile\" is required for template generation flags.\n"));
1394       return 0;
1395     }
1396   if (nflags > 1)
1397     {
1398       fprintf (stderr, _("Cannot have more than one file generation flag!\n"));
1399       return 0;
1400     }
1401   return 1;
1402 }
1403
1404 static void
1405 usage (FILE *stream, int status)
1406 {
1407   fprintf (stream, _("usage: %s infile\n"), cmdname);
1408   fprintf (stream, _("\t%s [-abkCLNTM][-Dname[=value]] [-i size] \
1409 [-I [-K seconds]] [-Y path] infile\n"), cmdname);
1410   fprintf (stream, _("\t%s [-c | -h | -l | -m | -t | -Sc | -Ss | -Sm] \
1411 [-o outfile] [infile]\n"), cmdname);
1412   fprintf (stream, _("\t%s [-s nettype]* [-o outfile] [infile]\n"), cmdname);
1413   fprintf (stream, _("\t%s [-n netid]* [-o outfile] [infile]\n"), cmdname);
1414   options_usage (stream, status);
1415   exit (status);
1416 }
1417
1418 static void
1419 options_usage (FILE *stream, int status)
1420 {
1421   f_print (stream, _("options:\n"));
1422   f_print (stream, _("-a\t\tgenerate all files, including samples\n"));
1423   f_print (stream, _("-b\t\tbackward compatibility mode (generates code for SunOS 4.1)\n"));
1424   f_print (stream, _("-c\t\tgenerate XDR routines\n"));
1425   f_print (stream, _("-C\t\tANSI C mode\n"));
1426   f_print (stream, _("-Dname[=value]\tdefine a symbol (same as #define)\n"));
1427   f_print (stream, _("-h\t\tgenerate header file\n"));
1428   f_print (stream, _("-i size\t\tsize at which to start generating inline code\n"));
1429   f_print (stream, _("-I\t\tgenerate code for inetd support in server (for SunOS 4.1)\n"));
1430   f_print (stream, _("-K seconds\tserver exits after K seconds of inactivity\n"));
1431   f_print (stream, _("-l\t\tgenerate client side stubs\n"));
1432   f_print (stream, _("-L\t\tserver errors will be printed to syslog\n"));
1433   f_print (stream, _("-m\t\tgenerate server side stubs\n"));
1434   f_print (stream, _("-M\t\tgenerate MT-safe code\n"));
1435   f_print (stream, _("-n netid\tgenerate server code that supports named netid\n"));
1436   f_print (stream, _("-N\t\tsupports multiple arguments and call-by-value\n"));
1437   f_print (stream, _("-o outfile\tname of the output file\n"));
1438   f_print (stream, _("-s nettype\tgenerate server code that supports named nettype\n"));
1439   f_print (stream, _("-Sc\t\tgenerate sample client code that uses remote procedures\n"));
1440   f_print (stream, _("-Ss\t\tgenerate sample server code that defines remote procedures\n"));
1441   f_print (stream, _("-Sm \t\tgenerate makefile template \n"));
1442   f_print (stream, _("-t\t\tgenerate RPC dispatch table\n"));
1443   f_print (stream, _("-T\t\tgenerate code to support RPC dispatch tables\n"));
1444   f_print (stream, _("-Y path\t\tdirectory name to find C preprocessor (cpp)\n"));
1445   f_print (stream, _("-5\t\tSysVr4 compatibility mode\n"));
1446   f_print (stream, _("--help\t\tgive this help list\n"));
1447   f_print (stream, _("--version\tprint program version\n"));
1448
1449   f_print (stream, _("\n\
1450 For bug reporting instructions, please see:\n\
1451 %s.\n"), REPORT_BUGS_TO);
1452   exit (status);
1453 }
1454
1455 static void
1456 print_version (void)
1457 {
1458   printf ("rpcgen %s%s\n", PKGVERSION, VERSION);
1459   exit (0);
1460 }