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