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