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