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