1 /* 2 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 3 * unrestricted use provided that this legend is included on all tape 4 * media and as a part of the software program in whole or part. Users 5 * may copy or modify Sun RPC without charge, but are not authorized 6 * to license or distribute it to anyone else except as part of a product or 7 * program developed by the user. 8 * 9 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 10 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 11 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 12 * 13 * Sun RPC is provided with no support and without any obligation on the 14 * part of Sun Microsystems, Inc. to assist in its use, correction, 15 * modification or enhancement. 16 * 17 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 18 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 19 * OR ANY PART THEREOF. 20 * 21 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 22 * or profits or other special, indirect and consequential damages, even if 23 * Sun has been advised of the possibility of such damages. 24 * 25 * Sun Microsystems, Inc. 26 * 2550 Garcia Avenue 27 * Mountain View, California 94043 28 */ 29 30 31 #if 0 32 #ifndef lint 33 #ident "@(#)rpc_main.c 1.21 94/04/25 SMI" 34 static char sccsid[] = "@(#)rpc_main.c 1.30 89/03/30 (C) 1987 SMI"; 35 #endif 36 #endif 37 38 #include <sys/cdefs.h> 39 /* 40 * rpc_main.c, Top level of the RPC protocol compiler. 41 * Copyright (C) 1987, Sun Microsystems, Inc. 42 */ 43 44 #include <err.h> 45 #include <ctype.h> 46 #include <stdbool.h> 47 #include <stdio.h> 48 #include <string.h> 49 #include <unistd.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_scan.h" 56 #include "rpc_util.h" 57 58 static void c_output(const char *, const char *, int, const char *); 59 static void h_output(const char *, const char *, int, const char *, int); 60 static void l_output(const char *, const char *, int, const char *); 61 static void t_output(const char *, const char *, int, const char *); 62 static void clnt_output(const char *, const char *, int, const char * ); 63 static char *generate_guard(const char *); 64 static void c_initialize(void); 65 66 static void usage(void) __dead2; 67 static void options_usage(void); 68 static int do_registers(int, const char **); 69 static int parseargs(int, const char **, struct commandline *); 70 static void svc_output(const char *, const char *, int, const char *); 71 static void mkfile_output(struct commandline *); 72 static void s_output(int, const char **, const char *, const char *, int, const char *, int, int); 73 74 #define EXTEND 1 /* alias for TRUE */ 75 #define DONT_EXTEND 0 /* alias for FALSE */ 76 77 static const char *svcclosetime = "120"; 78 static const char *CPP = NULL; 79 static const char CPPFLAGS[] = "-C"; 80 static char pathbuf[MAXPATHLEN + 1]; 81 static const char *allv[] = { 82 "rpcgen", "-s", "udp", "-s", "tcp", 83 }; 84 static int allc = nitems(allv); 85 static const char *allnv[] = { 86 "rpcgen", "-s", "netpath", 87 }; 88 static int allnc = nitems(allnv); 89 90 /* 91 * machinations for handling expanding argument list 92 */ 93 static void addarg(const char *); /* add another argument to the list */ 94 static void insarg(int, const char *); /* insert arg at specified location */ 95 static void checkfiles(const char *, const char *); 96 /* check if out file already exists */ 97 98 static char **arglist; 99 static int argcount = 0; 100 static int argmax = 0; 101 102 int nonfatalerrors; /* errors */ 103 int inetdflag = 0; /* Support for inetd is disabled by default, use -I */ 104 int pmflag = 0; /* Support for port monitors is disabled by default */ 105 int tirpc_socket = 1; /* TI-RPC on socket, no TLI library */ 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 110 #define INLINE 0 111 /* length at which to start doing an inline */ 112 113 int inline_size = INLINE; 114 /* 115 * Length at which to start doing an inline. INLINE = default 116 * if 0, no xdr_inline code 117 */ 118 119 int indefinitewait; /* If started by port monitors, hang till it wants */ 120 int exitnow; /* If started by port monitors, exit after the call */ 121 int timerflag; /* TRUE if !indefinite && !exitnow */ 122 int newstyle; /* newstyle of passing arguments (by value) */ 123 int CCflag = 0; /* C++ files */ 124 static int allfiles; /* generate all files */ 125 int tirpcflag = 1; /* generating code for tirpc, by default */ 126 xdrfunc *xdrfunc_head = NULL; /* xdr function list */ 127 xdrfunc *xdrfunc_tail = NULL; /* xdr function list */ 128 pid_t childpid; 129 130 131 int 132 main(int argc, const char *argv[]) 133 { 134 struct commandline cmd; 135 136 (void) memset((char *)&cmd, 0, sizeof (struct commandline)); 137 if (!parseargs(argc, argv, &cmd)) 138 usage(); 139 /* 140 * Only the client and server side stubs are likely to be customized, 141 * so in that case only, check if the outfile exists, and if so, 142 * print an error message and exit. 143 */ 144 if (cmd.Ssflag || cmd.Scflag || cmd.makefileflag) { 145 checkfiles(cmd.infile, cmd.outfile); 146 } 147 else 148 checkfiles(cmd.infile, NULL); 149 150 if (cmd.cflag) { 151 c_output(cmd.infile, "-DRPC_XDR", DONT_EXTEND, cmd.outfile); 152 } else if (cmd.hflag) { 153 h_output(cmd.infile, "-DRPC_HDR", DONT_EXTEND, cmd.outfile, 154 cmd.hflag); 155 } else if (cmd.lflag) { 156 l_output(cmd.infile, "-DRPC_CLNT", DONT_EXTEND, cmd.outfile); 157 } else if (cmd.sflag || cmd.mflag || (cmd.nflag)) { 158 s_output(argc, argv, cmd.infile, "-DRPC_SVC", DONT_EXTEND, 159 cmd.outfile, cmd.mflag, cmd.nflag); 160 } else if (cmd.tflag) { 161 t_output(cmd.infile, "-DRPC_TBL", DONT_EXTEND, cmd.outfile); 162 } else if (cmd.Ssflag) { 163 svc_output(cmd.infile, "-DRPC_SERVER", DONT_EXTEND, 164 cmd.outfile); 165 } else if (cmd.Scflag) { 166 clnt_output(cmd.infile, "-DRPC_CLIENT", DONT_EXTEND, 167 cmd.outfile); 168 } else if (cmd.makefileflag) { 169 mkfile_output(&cmd); 170 } else { 171 /* the rescans are required, since cpp may effect input */ 172 c_output(cmd.infile, "-DRPC_XDR", EXTEND, "_xdr.c"); 173 reinitialize(); 174 h_output(cmd.infile, "-DRPC_HDR", EXTEND, ".h", cmd.hflag); 175 reinitialize(); 176 l_output(cmd.infile, "-DRPC_CLNT", EXTEND, "_clnt.c"); 177 reinitialize(); 178 if (inetdflag || !tirpcflag) 179 s_output(allc, allv, cmd.infile, "-DRPC_SVC", EXTEND, 180 "_svc.c", cmd.mflag, cmd.nflag); 181 else 182 s_output(allnc, allnv, cmd.infile, "-DRPC_SVC", 183 EXTEND, "_svc.c", cmd.mflag, cmd.nflag); 184 if (tblflag) { 185 reinitialize(); 186 t_output(cmd.infile, "-DRPC_TBL", EXTEND, "_tbl.i"); 187 } 188 189 if (allfiles) { 190 reinitialize(); 191 svc_output(cmd.infile, "-DRPC_SERVER", EXTEND, 192 "_server.c"); 193 reinitialize(); 194 clnt_output(cmd.infile, "-DRPC_CLIENT", EXTEND, 195 "_client.c"); 196 197 } 198 if (allfiles || (cmd.makefileflag == 1)){ 199 reinitialize(); 200 mkfile_output(&cmd); 201 } 202 203 } 204 exit(nonfatalerrors); 205 /* NOTREACHED */ 206 } 207 208 209 /* 210 * add extension to filename 211 */ 212 static char * 213 extendfile(const char *path, const char *ext) 214 { 215 char *res; 216 const char *p; 217 const char *file; 218 219 if ((file = strrchr(path, '/')) == NULL) 220 file = path; 221 else 222 file++; 223 res = xmalloc(strlen(file) + strlen(ext) + 1); 224 p = strrchr(file, '.'); 225 if (p == NULL) { 226 p = file + strlen(file); 227 } 228 (void) strcpy(res, file); 229 (void) strcpy(res + (p - file), ext); 230 return (res); 231 } 232 233 /* 234 * Open output file with given extension 235 */ 236 static void 237 open_output(const char *infile, const char *outfile) 238 { 239 240 if (outfile == NULL) { 241 fout = stdout; 242 return; 243 } 244 245 if (infile != NULL && streq(outfile, infile)) { 246 warnx("%s already exists. No output generated", infile); 247 crash(); 248 } 249 fout = fopen(outfile, "w"); 250 if (fout == NULL) { 251 warn("unable to open %s", outfile); 252 crash(); 253 } 254 record_open(outfile); 255 256 return; 257 } 258 259 static void 260 add_warning(void) 261 { 262 f_print(fout, "/*\n"); 263 f_print(fout, " * Please do not edit this file.\n"); 264 f_print(fout, " * It was generated using rpcgen.\n"); 265 f_print(fout, " */\n\n"); 266 } 267 268 /* prepend C-preprocessor and flags before arguments */ 269 static void 270 prepend_cpp(void) 271 { 272 int idx = 0, quoted; 273 const char *var, *s; 274 char *dupvar, *t, *word; 275 276 if (CPP != NULL) 277 insarg(idx++, CPP); 278 else if ((var = getenv("RPCGEN_CPP")) == NULL) 279 insarg(idx++, "/usr/bin/cpp"); 280 else { 281 /* 282 * Parse command line like a shell (but only handle whitespace, 283 * quotes and backslash). 284 */ 285 dupvar = malloc(strlen(var) + 1); 286 quoted = 0; 287 word = NULL; 288 for (s = var, t = dupvar; *s; ++s) { 289 switch (quoted) { 290 /* Unquoted */ 291 case 0: 292 switch (*s) { 293 case ' ': 294 case '\t': 295 case '\n': 296 if (word != NULL) { 297 *t++ = '\0'; 298 insarg(idx++, word); 299 word = NULL; 300 } 301 break; 302 case '\'': 303 if (word == NULL) 304 word = t; 305 quoted = 1; 306 break; 307 case '"': 308 if (word == NULL) 309 word = t; 310 quoted = 2; 311 break; 312 case '\\': 313 switch (*(s + 1)) { 314 case '\0': 315 break; 316 case '\n': 317 ++s; 318 continue; 319 default: 320 ++s; 321 break; 322 } 323 /* FALLTHROUGH */ 324 default: 325 if (word == NULL) 326 word = t; 327 *t++ = *s; 328 break; 329 } 330 break; 331 332 /* Single-quoted */ 333 case 1: 334 switch (*s) { 335 case '\'': 336 quoted = 0; 337 break; 338 default: 339 *t++ = *s; 340 break; 341 } 342 break; 343 344 /* Double-quoted */ 345 case 2: 346 switch (*s) { 347 case '"': 348 quoted = 0; 349 break; 350 case '\\': 351 switch (*(s + 1)) { 352 case '\0': 353 break; 354 case '$': 355 case '`': 356 case '"': 357 case '\\': 358 ++s; 359 break; 360 case '\n': 361 ++s; 362 continue; 363 default: 364 break; 365 } 366 /* FALLTHROUGH */ 367 default: 368 *t++ = *s; 369 break; 370 } 371 break; 372 } 373 } 374 if (quoted) 375 errx(1, "RPCGEN_CPP: unterminated %c", 376 quoted == 1 ? '\'' : '"'); 377 if (word != NULL) { 378 *t++ = '\0'; 379 insarg(idx++, word); 380 } 381 free(dupvar); 382 } 383 384 insarg(idx, CPPFLAGS); 385 } 386 387 /* 388 * Open input file with given define for C-preprocessor 389 */ 390 static void 391 open_input(const char *infile, const char *define) 392 { 393 int pd[2]; 394 395 infilename = (infile == NULL) ? "<stdin>" : infile; 396 (void) pipe(pd); 397 switch (childpid = fork()) { 398 case 0: 399 prepend_cpp(); 400 addarg(define); 401 if (infile) 402 addarg(infile); 403 addarg((char *)NULL); 404 (void) close(1); 405 (void) dup2(pd[1], 1); 406 (void) close(pd[0]); 407 execvp(arglist[0], arglist); 408 err(1, "execvp %s", arglist[0]); 409 case -1: 410 err(1, "fork"); 411 } 412 (void) close(pd[1]); 413 fin = fdopen(pd[0], "r"); 414 if (fin == NULL) { 415 warn("%s", infilename); 416 crash(); 417 } 418 } 419 420 /* valid tirpc nettypes */ 421 static const char *valid_ti_nettypes[] = 422 { 423 "netpath", 424 "visible", 425 "circuit_v", 426 "datagram_v", 427 "circuit_n", 428 "datagram_n", 429 "udp", 430 "tcp", 431 "raw", 432 NULL 433 }; 434 435 /* valid inetd nettypes */ 436 static const char *valid_i_nettypes[] = 437 { 438 "udp", 439 "tcp", 440 NULL 441 }; 442 443 static int 444 check_nettype(const char *name, const char *list_to_check[]) 445 { 446 int i; 447 for (i = 0; list_to_check[i] != NULL; i++) { 448 if (strcmp(name, list_to_check[i]) == 0) { 449 return (1); 450 } 451 } 452 warnx("illegal nettype :\'%s\'", name); 453 return (0); 454 } 455 456 static const char * 457 file_name(const char *file, const char *ext) 458 { 459 char *temp; 460 temp = extendfile(file, ext); 461 462 if (access(temp, F_OK) != -1) 463 return (temp); 464 else 465 return (" "); 466 467 } 468 469 470 static void 471 c_output(const char *infile, const char *define, int extend, const char *outfile) 472 { 473 definition *def; 474 char *include; 475 const char *outfilename; 476 long tell; 477 478 c_initialize(); 479 open_input(infile, define); 480 outfilename = extend ? extendfile(infile, outfile) : outfile; 481 open_output(infile, outfilename); 482 add_warning(); 483 if (infile && (include = extendfile(infile, ".h"))) { 484 f_print(fout, "#include \"%s\"\n", include); 485 free(include); 486 /* .h file already contains rpc/rpc.h */ 487 } else 488 f_print(fout, "#include <rpc/rpc.h>\n"); 489 tell = ftell(fout); 490 while ( (def = get_definition()) ) { 491 emit(def); 492 } 493 if (extend && tell == ftell(fout)) { 494 (void) unlink(outfilename); 495 } 496 } 497 498 499 void 500 c_initialize(void) 501 { 502 503 /* add all the starting basic types */ 504 add_type(1, "int"); 505 add_type(1, "long"); 506 add_type(1, "short"); 507 add_type(1, "bool"); 508 add_type(1, "u_int"); 509 add_type(1, "u_long"); 510 add_type(1, "u_short"); 511 512 } 513 514 static const char rpcgen_table_dcl[] = "struct rpcgen_table {\n\ 515 char *(*proc)(); \n\ 516 xdrproc_t xdr_arg; \n\ 517 unsigned len_arg; \n\ 518 xdrproc_t xdr_res; \n\ 519 unsigned len_res; \n\ 520 }; \n"; 521 522 523 char * 524 generate_guard(const char *pathname) 525 { 526 const char *filename; 527 char *guard, *tmp, *stopat; 528 529 filename = strrchr(pathname, '/'); /* find last component */ 530 filename = ((filename == NULL) ? pathname : filename+1); 531 guard = xstrdup(filename); 532 stopat = strrchr(guard, '.'); 533 534 /* 535 * Convert to a valid C macro name and make it upper case. 536 * Map macro unfriendly characterss to '_'. 537 */ 538 for (tmp = guard; *tmp != '\000'; ++tmp) { 539 if (islower(*tmp)) 540 *tmp = toupper(*tmp); 541 else if (isupper(*tmp) || *tmp == '_') 542 /* OK for C */; 543 else if (tmp == guard) 544 *tmp = '_'; 545 else if (isdigit(*tmp)) 546 /* OK for all but first character */; 547 else if (tmp == stopat) { 548 *tmp = '\0'; 549 break; 550 } else 551 *tmp = '_'; 552 } 553 /* 554 * Can't have a '_' in front, because it'll end up being "__". 555 * "__" macros shoudln't be used. So, remove all of the 556 * '_' characters from the front. 557 */ 558 if (*guard == '_') { 559 for (tmp = guard; *tmp == '_'; ++tmp) 560 ; 561 strcpy(guard, tmp); 562 } 563 tmp = guard; 564 guard = extendfile(guard, "_H_RPCGEN"); 565 free(tmp); 566 return (guard); 567 } 568 569 /* 570 * Compile into an XDR header file 571 */ 572 573 574 static void 575 h_output(const char *infile, const char *define, int extend, const char *outfile, int headeronly) 576 { 577 definition *def; 578 const char *outfilename; 579 long tell; 580 const char *guard; 581 list *l; 582 xdrfunc *xdrfuncp; 583 void *tmp = NULL; 584 585 open_input(infile, define); 586 outfilename = extend ? extendfile(infile, outfile) : outfile; 587 open_output(infile, outfilename); 588 add_warning(); 589 if (outfilename || infile){ 590 guard = tmp = generate_guard(outfilename ? outfilename: infile); 591 } else 592 guard = "STDIN_"; 593 594 f_print(fout, "#ifndef _%s\n#define _%s\n\n", guard, 595 guard); 596 597 f_print(fout, "#include <rpc/rpc.h>\n"); 598 599 if (mtflag) 600 f_print(fout, "#include <pthread.h>\n"); 601 602 /* put the C++ support */ 603 if (!CCflag) { 604 f_print(fout, "\n#ifdef __cplusplus\n"); 605 f_print(fout, "extern \"C\" {\n"); 606 f_print(fout, "#endif\n\n"); 607 } 608 609 /* put in a typedef for quadprecision. Only with Cflag */ 610 611 tell = ftell(fout); 612 613 /* print data definitions */ 614 while ( (def = get_definition()) ) { 615 print_datadef(def, headeronly); 616 } 617 618 /* 619 * print function declarations. 620 * Do this after data definitions because they might be used as 621 * arguments for functions 622 */ 623 for (l = defined; l != NULL; l = l->next) { 624 print_funcdef(l->val, headeronly); 625 } 626 /* Now print all xdr func declarations */ 627 if (xdrfunc_head != NULL){ 628 629 f_print(fout, 630 "\n/* the xdr functions */\n"); 631 632 if (CCflag){ 633 f_print(fout, "\n#ifdef __cplusplus\n"); 634 f_print(fout, "extern \"C\" {\n"); 635 f_print(fout, "#endif\n"); 636 } 637 638 xdrfuncp = xdrfunc_head; 639 while (xdrfuncp != NULL){ 640 print_xdr_func_def(xdrfuncp->name, xdrfuncp->pointerp); 641 xdrfuncp = xdrfuncp->next; 642 } 643 } 644 645 if (extend && tell == ftell(fout)) { 646 (void) unlink(outfilename); 647 } else if (tblflag) { 648 f_print(fout, rpcgen_table_dcl); 649 } 650 651 f_print(fout, "\n#ifdef __cplusplus\n"); 652 f_print(fout, "}\n"); 653 f_print(fout, "#endif\n"); 654 655 f_print(fout, "\n#endif /* !_%s */\n", guard); 656 free(tmp); 657 } 658 659 /* 660 * Compile into an RPC service 661 */ 662 static void 663 s_output(int argc, const char *argv[], const char *infile, const char *define, 664 int extend, const char *outfile, int nomain, int netflag) 665 { 666 char *include; 667 definition *def; 668 int foundprogram = 0; 669 const char *outfilename; 670 671 open_input(infile, define); 672 outfilename = extend ? extendfile(infile, outfile) : outfile; 673 open_output(infile, outfilename); 674 add_warning(); 675 if (infile && (include = extendfile(infile, ".h"))) { 676 f_print(fout, "#include \"%s\"\n", include); 677 free(include); 678 } else 679 f_print(fout, "#include <rpc/rpc.h>\n"); 680 681 f_print(fout, "#include <stdio.h>\n"); 682 f_print(fout, "#include <stdlib.h> /* getenv, exit */\n"); 683 f_print (fout, "#include <rpc/pmap_clnt.h> /* for pmap_unset */\n"); 684 f_print (fout, "#include <string.h> /* strcmp */\n"); 685 if (tirpcflag) 686 f_print(fout, "#include <rpc/rpc_com.h>\n"); 687 if (strcmp(svcclosetime, "-1") == 0) 688 indefinitewait = 1; 689 else if (strcmp(svcclosetime, "0") == 0) 690 exitnow = 1; 691 else if (inetdflag || pmflag) { 692 f_print(fout, "#include <signal.h>\n"); 693 timerflag = 1; 694 } 695 696 if (!tirpcflag && inetdflag) 697 f_print(fout, "#include <sys/ttycom.h> /* TIOCNOTTY */\n"); 698 if (inetdflag || pmflag) { 699 f_print(fout, "#ifdef __cplusplus\n"); 700 f_print(fout, 701 "#include <sys/sysent.h> /* getdtablesize, open */\n"); 702 f_print(fout, "#endif /* __cplusplus */\n"); 703 } 704 if (tirpcflag) { 705 f_print(fout, "#include <fcntl.h> /* open */\n"); 706 f_print(fout, "#include <unistd.h> /* fork / setsid */\n"); 707 f_print(fout, "#include <sys/types.h>\n"); 708 } 709 710 f_print(fout, "#include <string.h>\n"); 711 if (inetdflag || !tirpcflag) { 712 f_print(fout, "#include <sys/socket.h>\n"); 713 f_print(fout, "#include <netinet/in.h>\n"); 714 } 715 716 if ((netflag || pmflag) && tirpcflag && !nomain) { 717 f_print(fout, "#include <netconfig.h>\n"); 718 } 719 if (tirpcflag) 720 f_print(fout, "#include <sys/resource.h> /* rlimit */\n"); 721 if (logflag || inetdflag || pmflag || tirpcflag) 722 f_print(fout, "#include <syslog.h>\n"); 723 724 f_print(fout, "\n#ifdef DEBUG\n#define RPC_SVC_FG\n#endif\n"); 725 if (timerflag) 726 f_print(fout, "\n#define _RPCSVC_CLOSEDOWN %s\n", 727 svcclosetime); 728 while ( (def = get_definition()) ) { 729 foundprogram |= (def->def_kind == DEF_PROGRAM); 730 } 731 if (extend && !foundprogram) { 732 (void) unlink(outfilename); 733 return; 734 } 735 write_most(infile, netflag, nomain); 736 if (!nomain) { 737 if (!do_registers(argc, argv)) { 738 if (outfilename) 739 (void) unlink(outfilename); 740 usage(); 741 } 742 write_rest(); 743 } 744 } 745 746 /* 747 * generate client side stubs 748 */ 749 static void 750 l_output(const char *infile, const char *define, int extend, const char *outfile) 751 { 752 char *include; 753 definition *def; 754 int foundprogram = 0; 755 const char *outfilename; 756 757 open_input(infile, define); 758 outfilename = extend ? extendfile(infile, outfile) : outfile; 759 open_output(infile, outfilename); 760 add_warning(); 761 f_print (fout, "#include <string.h> /* for memset */\n"); 762 if (infile && (include = extendfile(infile, ".h"))) { 763 f_print(fout, "#include \"%s\"\n", include); 764 free(include); 765 } else 766 f_print(fout, "#include <rpc/rpc.h>\n"); 767 while ( (def = get_definition()) ) { 768 foundprogram |= (def->def_kind == DEF_PROGRAM); 769 } 770 if (extend && !foundprogram) { 771 (void) unlink(outfilename); 772 return; 773 } 774 write_stubs(); 775 } 776 777 /* 778 * generate the dispatch table 779 */ 780 static void 781 t_output(const char *infile, const char *define, int extend, const char *outfile) 782 { 783 definition *def; 784 int foundprogram = 0; 785 const char *outfilename; 786 787 open_input(infile, define); 788 outfilename = extend ? extendfile(infile, outfile) : outfile; 789 open_output(infile, outfilename); 790 add_warning(); 791 while ( (def = get_definition()) ) { 792 foundprogram |= (def->def_kind == DEF_PROGRAM); 793 } 794 if (extend && !foundprogram) { 795 (void) unlink(outfilename); 796 return; 797 } 798 write_tables(); 799 } 800 801 /* sample routine for the server template */ 802 static void 803 svc_output(const char *infile, const char *define, int extend, const char *outfile) 804 { 805 definition *def; 806 char *include; 807 const char *outfilename; 808 long tell; 809 open_input(infile, define); 810 outfilename = extend ? extendfile(infile, outfile) : outfile; 811 checkfiles(infile, outfilename); 812 /* 813 * Check if outfile already exists. 814 * if so, print an error message and exit 815 */ 816 open_output(infile, outfilename); 817 add_sample_msg(); 818 819 if (infile && (include = extendfile(infile, ".h"))) { 820 f_print(fout, "#include \"%s\"\n", include); 821 free(include); 822 } else 823 f_print(fout, "#include <rpc/rpc.h>\n"); 824 825 tell = ftell(fout); 826 while ( (def = get_definition()) ) { 827 write_sample_svc(def); 828 } 829 if (extend && tell == ftell(fout)) { 830 (void) unlink(outfilename); 831 } 832 } 833 834 /* sample main routine for client */ 835 static void 836 clnt_output(const char *infile, const char *define, int extend, const char *outfile) 837 { 838 definition *def; 839 char *include; 840 const char *outfilename; 841 long tell; 842 int has_program = 0; 843 844 open_input(infile, define); 845 outfilename = extend ? extendfile(infile, outfile) : outfile; 846 checkfiles(infile, outfilename); 847 /* 848 * Check if outfile already exists. 849 * if so, print an error message and exit 850 */ 851 852 open_output(infile, outfilename); 853 add_sample_msg(); 854 if (infile && (include = extendfile(infile, ".h"))) { 855 f_print(fout, "#include \"%s\"\n", include); 856 free(include); 857 } else 858 f_print(fout, "#include <rpc/rpc.h>\n"); 859 f_print(fout, "#include <stdio.h>\n"); 860 f_print(fout, "#include <stdlib.h>\n"); 861 tell = ftell(fout); 862 while ( (def = get_definition()) ) { 863 has_program += write_sample_clnt(def); 864 } 865 866 if (has_program) 867 write_sample_clnt_main(); 868 869 if (extend && tell == ftell(fout)) { 870 (void) unlink(outfilename); 871 } 872 } 873 874 875 static void mkfile_output(struct commandline *cmd) 876 { 877 const char *mkfilename, *clientname, *clntname, *xdrname, *hdrname; 878 const char *servername, *svcname, *servprogname, *clntprogname; 879 char *temp, *mkftemp; 880 881 svcname = file_name(cmd->infile, "_svc.c"); 882 clntname = file_name(cmd->infile, "_clnt.c"); 883 xdrname = file_name(cmd->infile, "_xdr.c"); 884 hdrname = file_name(cmd->infile, ".h"); 885 886 887 if (allfiles){ 888 servername = extendfile(cmd->infile, "_server.c"); 889 clientname = extendfile(cmd->infile, "_client.c"); 890 }else{ 891 servername = " "; 892 clientname = " "; 893 } 894 servprogname = extendfile(cmd->infile, "_server"); 895 clntprogname = extendfile(cmd->infile, "_client"); 896 897 if (allfiles){ 898 mkftemp = xmalloc(strlen("makefile.") + 899 strlen(cmd->infile) + 1); 900 temp = strrchr(cmd->infile, '.'); 901 strcpy(mkftemp, "makefile."); 902 (void) strncat(mkftemp, cmd->infile, 903 (temp - cmd->infile)); 904 mkfilename = mkftemp; 905 } else 906 mkfilename = cmd->outfile; 907 908 909 checkfiles(NULL, mkfilename); 910 open_output(NULL, mkfilename); 911 912 f_print(fout, "\n# This is a template makefile generated\ 913 by rpcgen \n"); 914 915 f_print(fout, "\n# Parameters \n\n"); 916 917 f_print(fout, "CLIENT = %s\nSERVER = %s\n\n", 918 clntprogname, servprogname); 919 f_print(fout, "SOURCES_CLNT.c = \nSOURCES_CLNT.h = \n"); 920 f_print(fout, "SOURCES_SVC.c = \nSOURCES_SVC.h = \n"); 921 f_print(fout, "SOURCES.x = %s\n\n", cmd->infile); 922 f_print(fout, "TARGETS_SVC.c = %s %s %s \n", 923 svcname, servername, xdrname); 924 f_print(fout, "TARGETS_CLNT.c = %s %s %s \n", 925 clntname, clientname, xdrname); 926 f_print(fout, "TARGETS = %s %s %s %s %s %s\n\n", 927 hdrname, xdrname, clntname, 928 svcname, clientname, servername); 929 930 f_print(fout, "OBJECTS_CLNT = $(SOURCES_CLNT.c:%%.c=%%.o) \ 931 $(TARGETS_CLNT.c:%%.c=%%.o) "); 932 933 f_print(fout, "\nOBJECTS_SVC = $(SOURCES_SVC.c:%%.c=%%.o) \ 934 $(TARGETS_SVC.c:%%.c=%%.o) "); 935 936 937 f_print(fout, "\n# Compiler flags \n"); 938 if (mtflag) 939 f_print(fout, "\nCFLAGS += -D_REENTRANT -D_THEAD_SAFE \nLDLIBS += -pthread\n"); 940 941 f_print(fout, "RPCGENFLAGS = \n"); 942 943 f_print(fout, "\n# Targets \n\n"); 944 945 f_print(fout, "all : $(CLIENT) $(SERVER)\n\n"); 946 f_print(fout, "$(TARGETS) : $(SOURCES.x) \n"); 947 f_print(fout, "\trpcgen $(RPCGENFLAGS) $(SOURCES.x)\n\n"); 948 if (allfiles) { 949 f_print(fout, "\trpcgen -Sc $(RPCGENFLAGS) $(SOURCES.x) -o %s\n\n", clientname); 950 f_print(fout, "\trpcgen -Ss $(RPCGENFLAGS) $(SOURCES.x) -o %s\n\n", servername); 951 } 952 f_print(fout, "$(OBJECTS_CLNT) : $(SOURCES_CLNT.c) $(SOURCES_CLNT.h) \ 953 $(TARGETS_CLNT.c) \n\n"); 954 955 f_print(fout, "$(OBJECTS_SVC) : $(SOURCES_SVC.c) $(SOURCES_SVC.h) \ 956 $(TARGETS_SVC.c) \n\n"); 957 f_print(fout, "$(CLIENT) : $(OBJECTS_CLNT) \n"); 958 f_print(fout, "\t$(CC) -o $(CLIENT) $(OBJECTS_CLNT) \ 959 $(LDLIBS) \n\n"); 960 f_print(fout, "$(SERVER) : $(OBJECTS_SVC) \n"); 961 f_print(fout, "\t$(CC) -o $(SERVER) $(OBJECTS_SVC) $(LDLIBS)\n\n"); 962 f_print(fout, "clean:\n\t rm -f core $(TARGETS) $(OBJECTS_CLNT) \ 963 $(OBJECTS_SVC) $(CLIENT) $(SERVER)\n\n"); 964 } 965 966 967 968 /* 969 * Perform registrations for service output 970 * Return 0 if failed; 1 otherwise. 971 */ 972 static int 973 do_registers(int argc, const char *argv[]) 974 { 975 int i; 976 977 if (inetdflag || !tirpcflag) { 978 for (i = 1; i < argc; i++) { 979 if (streq(argv[i], "-s")) { 980 if (!check_nettype(argv[i + 1], 981 valid_i_nettypes)) 982 return (0); 983 write_inetd_register(argv[i + 1]); 984 i++; 985 } 986 } 987 } else { 988 for (i = 1; i < argc; i++) 989 if (streq(argv[i], "-s")) { 990 if (!check_nettype(argv[i + 1], 991 valid_ti_nettypes)) 992 return (0); 993 write_nettype_register(argv[i + 1]); 994 i++; 995 } else if (streq(argv[i], "-n")) { 996 write_netid_register(argv[i + 1]); 997 i++; 998 } 999 } 1000 return (1); 1001 } 1002 1003 /* 1004 * Extend the argument list 1005 */ 1006 static void 1007 moreargs(void) 1008 { 1009 char **newarglist; 1010 1011 argmax = argmax == 0 ? 32 : argmax << 1; 1012 if (argmax > INT_MAX / 4) { 1013 warnx("refusing to allocate too many arguments"); 1014 crash(); 1015 } 1016 newarglist = realloc(arglist, argmax * sizeof(*arglist)); 1017 if (newarglist == NULL) { 1018 warnx("unable to allocate arglist"); 1019 crash(); 1020 } 1021 arglist = newarglist; 1022 } 1023 1024 /* 1025 * Add another argument to the arg list 1026 */ 1027 static void 1028 addarg(const char *cp) 1029 { 1030 if (argcount >= argmax) 1031 moreargs(); 1032 1033 if (cp != NULL) 1034 arglist[argcount++] = xstrdup(cp); 1035 else 1036 arglist[argcount++] = NULL; 1037 } 1038 1039 /* 1040 * Insert an argument at the specified location 1041 */ 1042 static void 1043 insarg(int place, const char *cp) 1044 { 1045 int i; 1046 1047 if (argcount >= argmax) 1048 moreargs(); 1049 1050 /* Move up existing arguments */ 1051 for (i = argcount - 1; i >= place; i--) 1052 arglist[i + 1] = arglist[i]; 1053 1054 arglist[place] = xstrdup(cp); 1055 argcount++; 1056 } 1057 1058 /* 1059 * if input file is stdin and an output file is specified then complain 1060 * if the file already exists. Otherwise the file may get overwritten 1061 * If input file does not exist, exit with an error 1062 */ 1063 1064 static void 1065 checkfiles(const char *infile, const char *outfile) 1066 { 1067 1068 struct stat buf; 1069 1070 if (infile) /* infile ! = NULL */ 1071 if (stat(infile, &buf) < 0) 1072 { 1073 warn("%s", infile); 1074 crash(); 1075 } 1076 if (outfile) { 1077 if (stat(outfile, &buf) < 0) 1078 return; /* file does not exist */ 1079 else { 1080 warnx("file '%s' already exists and may be overwritten", outfile); 1081 crash(); 1082 } 1083 } 1084 } 1085 1086 /* 1087 * Parse command line arguments 1088 */ 1089 static int 1090 parseargs(int argc, const char *argv[], struct commandline *cmd) 1091 { 1092 int i; 1093 int j; 1094 char c, ch; 1095 char flag[(1 << 8 * sizeof (char))]; 1096 int nflags; 1097 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 warnx("cannot specify more than one input file"); 1119 return (0); 1120 } 1121 cmd->infile = argv[i]; 1122 } else { 1123 for (j = 1; argv[i][j] != 0; j++) { 1124 c = argv[i][j]; 1125 switch (c) { 1126 case 'a': 1127 allfiles = 1; 1128 break; 1129 case 'c': 1130 case 'h': 1131 case 'l': 1132 case 'm': 1133 case 't': 1134 if (flag[(int)c]) { 1135 return (0); 1136 } 1137 flag[(int)c] = 1; 1138 break; 1139 case 'S': 1140 /* 1141 * sample flag: Ss or Sc. 1142 * Ss means set flag['S']; 1143 * Sc means set flag['C']; 1144 * Sm means set flag['M']; 1145 */ 1146 ch = argv[i][++j]; /* get next char */ 1147 if (ch == 's') 1148 ch = 'S'; 1149 else if (ch == 'c') 1150 ch = 'C'; 1151 else if (ch == 'm') 1152 ch = 'M'; 1153 else 1154 return (0); 1155 1156 if (flag[(int)ch]) { 1157 return (0); 1158 } 1159 flag[(int)ch] = 1; 1160 break; 1161 case 'C': /* ANSI C syntax */ 1162 ch = argv[i][j+1]; /* get next char */ 1163 1164 if (ch != 'C') 1165 break; 1166 CCflag = 1; 1167 break; 1168 case 'b': 1169 /* 1170 * Turn TIRPC flag off for 1171 * generating backward compatible 1172 * code 1173 */ 1174 tirpcflag = 0; 1175 break; 1176 1177 case 'I': 1178 inetdflag = 1; 1179 break; 1180 case 'N': 1181 newstyle = 1; 1182 break; 1183 case 'L': 1184 logflag = 1; 1185 break; 1186 case 'P': 1187 pmflag = 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 'M': 1199 mtflag = 1; 1200 break; 1201 case 'i' : 1202 if (++i == argc) { 1203 return (0); 1204 } 1205 inline_size = atoi(argv[i]); 1206 goto nextarg; 1207 case 'n': 1208 case 'o': 1209 case 's': 1210 if (argv[i][j - 1] != '-' || 1211 argv[i][j + 1] != 0) { 1212 return (0); 1213 } 1214 flag[(int)c] = 1; 1215 if (++i == argc) { 1216 return (0); 1217 } 1218 if (c == 'o') { 1219 if (cmd->outfile) { 1220 return (0); 1221 } 1222 cmd->outfile = argv[i]; 1223 } 1224 goto nextarg; 1225 case 'D': 1226 if (argv[i][j - 1] != '-') { 1227 return (0); 1228 } 1229 (void) addarg(argv[i]); 1230 goto nextarg; 1231 case 'Y': 1232 if (++i == argc) { 1233 return (0); 1234 } 1235 if (strlcpy(pathbuf, argv[i], 1236 sizeof(pathbuf)) >= sizeof(pathbuf) 1237 || strlcat(pathbuf, "/cpp", 1238 sizeof(pathbuf)) >= 1239 sizeof(pathbuf)) { 1240 warnx("argument too long"); 1241 return (0); 1242 } 1243 CPP = pathbuf; 1244 goto nextarg; 1245 1246 1247 1248 default: 1249 return (0); 1250 } 1251 } 1252 nextarg: 1253 ; 1254 } 1255 } 1256 1257 cmd->cflag = flag['c']; 1258 cmd->hflag = flag['h']; 1259 cmd->lflag = flag['l']; 1260 cmd->mflag = flag['m']; 1261 cmd->nflag = flag['n']; 1262 cmd->sflag = flag['s']; 1263 cmd->tflag = flag['t']; 1264 cmd->Ssflag = flag['S']; 1265 cmd->Scflag = flag['C']; 1266 cmd->makefileflag = flag['M']; 1267 1268 if (tirpcflag) { 1269 if (inetdflag) 1270 pmflag = 0; 1271 if ((inetdflag && cmd->nflag)) { 1272 /* netid not allowed with inetdflag */ 1273 warnx("cannot use netid flag with inetd flag"); 1274 return (0); 1275 } 1276 } else { /* 4.1 mode */ 1277 pmflag = 0; /* set pmflag only in tirpcmode */ 1278 if (cmd->nflag) { /* netid needs TIRPC */ 1279 warnx("cannot use netid flag without TIRPC"); 1280 return (0); 1281 } 1282 } 1283 1284 if (newstyle && (tblflag || cmd->tflag)) { 1285 warnx("cannot use table flags with newstyle"); 1286 return (0); 1287 } 1288 1289 /* check no conflicts with file generation flags */ 1290 nflags = cmd->cflag + cmd->hflag + cmd->lflag + cmd->mflag + 1291 cmd->sflag + cmd->nflag + cmd->tflag + cmd->Ssflag + 1292 cmd->Scflag + cmd->makefileflag; 1293 1294 if (nflags == 0) { 1295 if (cmd->outfile != NULL || cmd->infile == NULL) { 1296 return (0); 1297 } 1298 } else if (cmd->infile == NULL && 1299 (cmd->Ssflag || cmd->Scflag || cmd->makefileflag)) { 1300 warnx("\"infile\" is required for template generation flags"); 1301 return (0); 1302 } if (nflags > 1) { 1303 warnx("cannot have more than one file generation flag"); 1304 return (0); 1305 } 1306 return (1); 1307 } 1308 1309 static void 1310 usage(void) 1311 { 1312 f_print(stderr, "%s\n%s\n%s\n%s\n%s\n", 1313 "usage: rpcgen infile", 1314 " rpcgen [-abCLNTM] [-Dname[=value]] [-i size]\ 1315 [-I -P [-K seconds]] [-Y path] infile", 1316 " rpcgen [-c | -h | -l | -m | -t | -Sc | -Ss | -Sm]\ 1317 [-o outfile] [infile]", 1318 " rpcgen [-s nettype]* [-o outfile] [infile]", 1319 " rpcgen [-n netid]* [-o outfile] [infile]"); 1320 options_usage(); 1321 exit(1); 1322 } 1323 1324 static void 1325 options_usage(void) 1326 { 1327 f_print(stderr, "options:\n"); 1328 f_print(stderr, "-a\t\tgenerate all files, including samples\n"); 1329 f_print(stderr, "-b\t\tbackward compatibility mode (generates code \ 1330 for FreeBSD 4.X)\n"); 1331 f_print(stderr, "-c\t\tgenerate XDR routines\n"); 1332 f_print(stderr, "-C\t\tANSI C mode\n"); 1333 f_print(stderr, "-Dname[=value]\tdefine a symbol (same as #define)\n"); 1334 f_print(stderr, "-h\t\tgenerate header file\n"); 1335 f_print(stderr, "-i size\t\tsize at which to start generating\ 1336 inline code\n"); 1337 f_print(stderr, "-I\t\tgenerate code for inetd support in server\n"); 1338 f_print(stderr, "-K seconds\tserver exits after K seconds of\ 1339 inactivity\n"); 1340 f_print(stderr, "-l\t\tgenerate client side stubs\n"); 1341 f_print(stderr, "-L\t\tserver errors will be printed to syslog\n"); 1342 f_print(stderr, "-m\t\tgenerate server side stubs\n"); 1343 f_print(stderr, "-M\t\tgenerate MT-safe code\n"); 1344 f_print(stderr, "-n netid\tgenerate server code that supports\ 1345 named netid\n"); 1346 f_print(stderr, "-N\t\tsupports multiple arguments and\ 1347 call-by-value\n"); 1348 f_print(stderr, "-o outfile\tname of the output file\n"); 1349 f_print(stderr, "-P\t\tgenerate code for port monitoring support in server\n"); 1350 f_print(stderr, "-s nettype\tgenerate server code that supports named\ 1351 nettype\n"); 1352 f_print(stderr, "-Sc\t\tgenerate sample client code that uses remote\ 1353 procedures\n"); 1354 f_print(stderr, "-Ss\t\tgenerate sample server code that defines\ 1355 remote procedures\n"); 1356 f_print(stderr, "-Sm \t\tgenerate makefile template \n"); 1357 1358 f_print(stderr, "-t\t\tgenerate RPC dispatch table\n"); 1359 f_print(stderr, "-T\t\tgenerate code to support RPC dispatch tables\n"); 1360 f_print(stderr, "-Y path\t\tpath where cpp is found\n"); 1361 exit(1); 1362 } 1363