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