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