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