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