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