# Buildsheet autogenerated by ravenadm tool -- Do not edit. NAMEBASE= rpcgen VERSION= 1.0 KEYWORDS= sysutils raven VARIANTS= standard SDESC[standard]= RPC protocol compiler HOMEPAGE= https://www.freebsd.org/cgi/man.cgi?rpcgen(1) CONTACT= John_Marino[draco@marino.st] DOWNLOAD_GROUPS= none SPKGS[standard]= single OPTIONS_AVAILABLE= none OPTIONS_STANDARD= none B_DEPS[linux]= libbsd:single:standard LICENSE= CUSTOM1:single LICENSE_NAME= CUSTOM1:"Sun Microsystems RPC license" LICENSE_SCHEME= solo LICENSE_FILE= CUSTOM1:{{WRKSRC}}/LICENSE do-extract: ${MKDIR} ${WRKSRC} cp ${FILESDIR}/* ${WRKSRC}/ [FILE:240:descriptions/desc.single] The rpcgen utility is a tool that generates C code to implement an RPC protocol. The input to rpcgen is a language similar to C known as RPC Language (Remote Procedure Call Language). This version was extracted from DragonFly 4.8-RELEASE. [FILE:38:manifests/plist.single] bin/rpcgen share/man/man1/rpcgen.1.gz [FILE:1331:files/LICENSE] /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape * media and as a part of the software program in whole or part. Users * may copy or modify Sun RPC without charge, but are not authorized * to license or distribute it to anyone else except as part of a product or * program developed by the user. * * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. * * Sun RPC is provided with no support and without any obligation on the * part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC * OR ANY PART THEREOF. * * In no event will Sun Microsystems, Inc. be liable for any lost revenue * or profits or other special, indirect and consequential damages, even if * Sun has been advised of the possibility of such damages. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 * * @(#)rpc_main.c 1.21 94/04/25 SMI; 1.30 89/03/30 (C) 1987 SMI */ [FILE:489:files/Makefile] PROG= rpcgen SRCS= rpc_main.c rpc_clntout.c rpc_cout.c rpc_hout.c rpc_parse.c \ rpc_sample.c rpc_scan.c rpc_svcout.c rpc_tblout.c rpc_util.c OBJS= ${SRCS:.c=.o} PREFIX?= /usr/local .if ${OPSYS} == Linux LIBS+= ${PREFIX}/lib/libbsd.a .endif all: ${PROG} clean: rm -f ${OBJS} ${PROG} ${PROG}: ${SRCS} ${CC} -o ${PROG} ${.ALLSRC} ${CFLAGS} ${LIBS} install: ${BSD_INSTALL_PROGRAM} ${PROG} ${DESTDIR}${PREFIX}/bin/ ${BSD_INSTALL_MAN} ${PROG}.1 ${DESTDIR}${PREFIX}/share/man/man1 [FILE:5955:files/rpc_clntout.c] #include #include #include #include "rpc_parse.h" #include "rpc_scan.h" #include "rpc_util.h" static void write_program(definition *); static void printbody(proc_list *); static char RESULT[] = "clnt_res"; #define DEFAULT_TIMEOUT 25 /* in seconds */ void write_stubs(void) { list *l; definition *def; f_print(fout, "\n/* Default timeout can be changed using clnt_control() */\n"); f_print(fout, "static struct timeval TIMEOUT = { %d, 0 };\n", DEFAULT_TIMEOUT); for (l = defined; l != NULL; l = l->next) { def = (definition *) l->val; if (def->def_kind == DEF_PROGRAM) write_program(def); } } static void write_program(definition *def) { version_list *vp; proc_list *proc; for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) { for (proc = vp->procs; proc != NULL; proc = proc->next) { f_print(fout, "\n"); if (mtflag == 0) { ptype(proc->res_prefix, proc->res_type, 1); f_print(fout, "*\n"); pvname(proc->proc_name, vp->vers_num); printarglist(proc, RESULT, "clnt", "CLIENT *"); } else { f_print(fout, "enum clnt_stat \n"); pvname(proc->proc_name, vp->vers_num); printarglist(proc, RESULT, "clnt", "CLIENT *"); } f_print(fout, "{\n"); printbody(proc); f_print(fout, "}\n"); } } } /* * Writes out declarations of procedure's argument list. * In either ANSI C style, in one of old rpcgen style (pass by reference), * or new rpcgen style (multiple arguments, pass by value); */ /* sample addargname = "clnt"; sample addargtype = "CLIENT * " */ void printarglist(proc_list *proc, const char *result, const char *addargname, const char *addargtype) { decl_list *l; if (!newstyle) { /* old style: always pass argument by reference */ f_print(fout, "("); ptype(proc->args.decls->decl.prefix, proc->args.decls->decl.type, 1); if (mtflag) {/* Generate result field */ f_print(fout, "*argp, "); ptype(proc->res_prefix, proc->res_type, 1); f_print(fout, "*%s, %s%s)\n", result, addargtype, addargname); } else f_print(fout, "*argp, %s%s)\n", addargtype, addargname); } else if (streq(proc->args.decls->decl.type, "void")) { /* newstyle, 0 argument */ if (mtflag) { f_print(fout, "("); ptype(proc->res_prefix, proc->res_type, 1); f_print(fout, "*%s, %s%s)\n", result, addargtype, addargname); } else f_print(fout, "(%s%s)\n", addargtype, addargname); } else { /* new style, 1 or multiple arguments */ f_print(fout, "("); for (l = proc->args.decls; l != NULL; l = l->next) { pdeclaration(proc->args.argname, &l->decl, 0, ", "); } if (mtflag) { ptype(proc->res_prefix, proc->res_type, 1); f_print(fout, "*%s, ", result); } f_print(fout, "%s%s)\n", addargtype, addargname); } } static const char * ampr(const char *type) { if (isvectordef(type, REL_ALIAS)) return (""); else return ("&"); } static void printbody(proc_list *proc) { decl_list *l; bool_t args2 = (proc->arg_num > 1); /* * For new style with multiple arguments, need a structure in which * to stuff the arguments. */ if (newstyle && args2) { f_print(fout, "\t%s", proc->args.argname); f_print(fout, " arg;\n"); } if (!mtflag) { f_print(fout, "\tstatic "); if (streq(proc->res_type, "void")) f_print(fout, "char "); else ptype(proc->res_prefix, proc->res_type, 0); f_print(fout, "%s;\n", RESULT); f_print(fout, "\n"); f_print(fout, "\tmemset((char *)%s%s, 0, sizeof (%s));\n", ampr(proc->res_type), RESULT, RESULT); } if (newstyle && !args2 && (streq(proc->args.decls->decl.type, "void"))) { /* newstyle, 0 arguments */ if (mtflag) f_print(fout, "\t return "); else f_print(fout, "\t if "); f_print(fout, "(clnt_call(clnt, %s,\n\t\t(xdrproc_t) xdr_void, ", proc->proc_name); f_print(fout, "(caddr_t) NULL,\n\t\t(xdrproc_t) xdr_%s, " "(caddr_t) %s%s,", stringfix(proc->res_type), (mtflag) ? "" : ampr(proc->res_type), RESULT); if (mtflag) f_print(fout, "\n\t\tTIMEOUT));\n"); else f_print(fout, "\n\t\tTIMEOUT) != RPC_SUCCESS) {\n"); } else if (newstyle && args2) { /* * Newstyle, multiple arguments * stuff arguments into structure */ for (l = proc->args.decls; l != NULL; l = l->next) { f_print(fout, "\targ.%s = %s;\n", l->decl.name, l->decl.name); } if (mtflag) f_print(fout, "\treturn "); else f_print(fout, "\tif "); f_print(fout, "(clnt_call(clnt, %s,\n\t\t(xdrproc_t) xdr_%s", proc->proc_name,proc->args.argname); f_print(fout, ", (caddr_t) &arg,\n\t\t(xdrproc_t) xdr_%s, " "(caddr_t) %s%s,", stringfix(proc->res_type), (mtflag) ? "" : ampr(proc->res_type), RESULT); if (mtflag) f_print(fout, "\n\t\tTIMEOUT));\n"); else f_print(fout, "\n\t\tTIMEOUT) != RPC_SUCCESS) {\n"); } else { /* single argument, new or old style */ if (!mtflag) { f_print(fout, "\tif (clnt_call(clnt, %s,\n" "\t\t(xdrproc_t) xdr_%s, (caddr_t) %s%s,\n" "\t\t(xdrproc_t) xdr_%s, (caddr_t) %s%s,\n" "\t\tTIMEOUT) != RPC_SUCCESS) {\n", proc->proc_name, stringfix(proc->args.decls->decl.type), (newstyle ? "&" : ""), (newstyle) ? proc->args.decls->decl.name : "argp", stringfix(proc->res_type), ampr(proc->res_type), RESULT); } else { f_print(fout, "\treturn (clnt_call(clnt, %s,\n" "\t\t(xdrproc_t) xdr_%s, (caddr_t) %s%s,\n" "\t\t(xdrproc_t) xdr_%s, (caddr_t) %s%s,\n" "\t\tTIMEOUT));\n", proc->proc_name, stringfix(proc->args.decls->decl.type), (newstyle ? "&" : ""), (newstyle) ? proc->args.decls->decl.name : "argp", stringfix(proc->res_type), "", RESULT); } } if (!mtflag) { f_print(fout, "\t\treturn (NULL);\n"); f_print(fout, "\t}\n"); if (streq(proc->res_type, "void")) { f_print(fout, "\treturn ((void *)%s%s);\n", ampr(proc->res_type), RESULT); } else { f_print(fout, "\treturn (%s%s);\n", ampr(proc->res_type), RESULT); } } } [FILE:14783:files/rpc_cout.c] #include #include #include #include "rpc_parse.h" #include "rpc_scan.h" #include "rpc_util.h" static void print_header(definition *); static void print_trailer(void); static void print_stat(int , declaration *); static void emit_enum(definition *); static void emit_program(definition *); static void emit_union(definition *); static void emit_struct(definition *); static void emit_typedef(definition *); static void emit_inline(int, declaration *, int); static void emit_single_in_line(int, declaration *, int, relation); static char *upcase(const char *); /* * Emit the C-routine for the given definition */ void emit(definition *def) { if (def->def_kind == DEF_CONST) return; if (def->def_kind == DEF_PROGRAM) { emit_program(def); return; } if (def->def_kind == DEF_TYPEDEF) { /* * now we need to handle declarations like * struct typedef foo foo; * since we dont want this to be expanded into 2 calls to xdr_foo */ if (strcmp(def->def.ty.old_type, def->def_name) == 0) return; } print_header(def); switch (def->def_kind) { case DEF_UNION: emit_union(def); break; case DEF_ENUM: emit_enum(def); break; case DEF_STRUCT: emit_struct(def); break; case DEF_TYPEDEF: emit_typedef(def); break; /* DEF_CONST and DEF_PROGRAM have already been handled */ default: break; } print_trailer(); } static int findtype(definition *def, const char *type) { if (def->def_kind == DEF_PROGRAM || def->def_kind == DEF_CONST) return(0); else return(streq(def->def_name, type)); } static int undefined(const char *type) { definition *def; def = (definition *) FINDVAL(defined, type, findtype); return(def == NULL); } static void print_generic_header(const char *procname, int pointerp) { f_print(fout, "\n"); f_print(fout, "bool_t\n"); f_print(fout, "xdr_%s(", procname); f_print(fout, "XDR *xdrs, "); f_print(fout, "%s ", procname); if (pointerp) f_print(fout, "*"); f_print(fout, "objp)\n{\n\n"); } static void print_header(definition *def) { print_generic_header(def->def_name, def->def_kind != DEF_TYPEDEF || !isvectordef(def->def.ty.old_type, def->def.ty.rel)); /* Now add Inline support */ if (inline_size == 0) return; /* May cause lint to complain. but ... */ f_print(fout, "\tlong *buf;\n\n"); } static void print_prog_header(proc_list *plist) { print_generic_header(plist->args.argname, 1); } static void print_trailer(void) { f_print(fout, "\treturn (TRUE);\n"); f_print(fout, "}\n"); } static void print_ifopen(int indent, const char *name) { tabify(fout, indent); f_print(fout, "if (!xdr_%s(xdrs", name); } static void print_ifarg(const char *arg) { f_print(fout, ", %s", arg); } static void print_ifsizeof(int indent, const char *prefix, const char *type) { if (indent) { f_print(fout, ",\n"); tabify(fout, indent); } else { f_print(fout, ", "); } if (streq(type, "bool")) { f_print(fout, "sizeof (bool_t), (xdrproc_t) xdr_bool"); } else { f_print(fout, "sizeof ("); if (undefined(type) && prefix) f_print(fout, "%s ", prefix); f_print(fout, "%s), (xdrproc_t) xdr_%s", type, type); } } static void print_ifclose(int indent, int brace) { f_print(fout, "))\n"); tabify(fout, indent); f_print(fout, "\treturn (FALSE);\n"); if (brace) f_print(fout, "\t}\n"); } static void print_ifstat(int indent, const char *prefix, const char *type, relation rel, const char *amax, const char *objname, const char *name) { const char *alt = NULL; int brace = 0; switch (rel) { case REL_POINTER: brace = 1; f_print(fout, "\t{\n"); f_print(fout, "\t%s **pp = %s;\n", type, objname); print_ifopen(indent, "pointer"); print_ifarg("(char **)"); f_print(fout, "pp"); print_ifsizeof(0, prefix, type); break; case REL_VECTOR: if (streq(type, "string")) alt = "string"; else if (streq(type, "opaque")) alt = "opaque"; if (alt) { print_ifopen(indent, alt); print_ifarg(objname); } else { print_ifopen(indent, "vector"); print_ifarg("(char *)"); f_print(fout, "%s", objname); } print_ifarg(amax); if (!alt) print_ifsizeof(indent + 1, prefix, type); break; case REL_ARRAY: if (streq(type, "string")) alt = "string"; else if (streq(type, "opaque")) alt = "bytes"; if (streq(type, "string")) { print_ifopen(indent, alt); print_ifarg(objname); } else { if (alt) print_ifopen(indent, alt); else print_ifopen(indent, "array"); print_ifarg("(char **)"); if (*objname == '&') { f_print(fout, "%s.%s_val, (u_int *) %s.%s_len", objname, name, objname, name); } else { f_print(fout, "&%s->%s_val, (u_int *) &%s->%s_len", objname, name, objname, name); } } print_ifarg(amax); if (!alt) print_ifsizeof(indent + 1, prefix, type); break; case REL_ALIAS: print_ifopen(indent, type); print_ifarg(objname); break; } print_ifclose(indent, brace); } /* ARGSUSED */ static void emit_enum(definition *def __unused) { print_ifopen(1, "enum"); print_ifarg("(enum_t *)objp"); print_ifclose(1, 0); } static void emit_program(definition *def) { decl_list *dl; version_list *vlist; proc_list *plist; for (vlist = def->def.pr.versions; vlist != NULL; vlist = vlist->next) for (plist = vlist->procs; plist != NULL; plist = plist->next) { if (!newstyle || plist->arg_num < 2) continue; /* old style, or single argument */ print_prog_header(plist); for (dl = plist->args.decls; dl != NULL; dl = dl->next) print_stat(1, &dl->decl); print_trailer(); } } static void emit_union(definition *def) { declaration *dflt; case_list *cl; declaration *cs; char *object; const char *vecformat = "objp->%s_u.%s"; const char *format = "&objp->%s_u.%s"; print_stat(1, &def->def.un.enum_decl); f_print(fout, "\tswitch (objp->%s) {\n", def->def.un.enum_decl.name); for (cl = def->def.un.cases; cl != NULL; cl = cl->next) { f_print(fout, "\tcase %s:\n", cl->case_name); if (cl->contflag == 1) /* a continued case statement */ continue; cs = &cl->case_decl; if (!streq(cs->type, "void")) { object = xmalloc(strlen(def->def_name) + strlen(format) + strlen(cs->name) + 1); if (isvectordef (cs->type, cs->rel)) { s_print(object, vecformat, def->def_name, cs->name); } else { s_print(object, format, def->def_name, cs->name); } print_ifstat(2, cs->prefix, cs->type, cs->rel, cs->array_max, object, cs->name); free(object); } f_print(fout, "\t\tbreak;\n"); } dflt = def->def.un.default_decl; if (dflt != NULL) { if (!streq(dflt->type, "void")) { f_print(fout, "\tdefault:\n"); object = xmalloc(strlen(def->def_name) + strlen(format) + strlen(dflt->name) + 1); if (isvectordef (dflt->type, dflt->rel)) { s_print(object, vecformat, def->def_name, dflt->name); } else { s_print(object, format, def->def_name, dflt->name); } print_ifstat(2, dflt->prefix, dflt->type, dflt->rel, dflt->array_max, object, dflt->name); free(object); f_print(fout, "\t\tbreak;\n"); } else { f_print(fout, "\tdefault:\n"); f_print(fout, "\t\tbreak;\n"); } } else { f_print(fout, "\tdefault:\n"); f_print(fout, "\t\treturn (FALSE);\n"); } f_print(fout, "\t}\n"); } static void inline_struct(definition *def, int flag) { decl_list *dl; int i, size; decl_list *cur, *psav; bas_type *ptr; char *sizestr; const char *plus; char ptemp[256]; int indent = 1; cur = NULL; if (flag == PUT) f_print(fout, "\n\tif (xdrs->x_op == XDR_ENCODE) {\n"); else f_print(fout, "\t\treturn (TRUE);\n" "\t} else if (xdrs->x_op == XDR_DECODE) {\n"); i = 0; size = 0; sizestr = NULL; for (dl = def->def.st.decls; dl != NULL; dl = dl->next) { /* xxx */ /* now walk down the list and check for basic types */ if ((dl->decl.prefix == NULL) && ((ptr = find_type(dl->decl.type)) != NULL) && ((dl->decl.rel == REL_ALIAS) || (dl->decl.rel == REL_VECTOR))){ if (i == 0) cur = dl; i++; if (dl->decl.rel == REL_ALIAS) { size += ptr->length; } else { /* this code is required to handle arrays */ if (sizestr == NULL) plus = ""; else plus = " + "; if (ptr->length != 1) s_print(ptemp, "%s%s * %d", plus, dl->decl.array_max, ptr->length); else s_print(ptemp, "%s%s", plus, dl->decl.array_max); /* now concatenate to sizestr !!!! */ if (sizestr == NULL) { sizestr = xstrdup(ptemp); } else { sizestr = xrealloc(sizestr, strlen(sizestr) +strlen(ptemp)+1); sizestr = strcat(sizestr, ptemp); /* build up length of array */ } } } else { if (i > 0) { if (sizestr == NULL && size < inline_size) { /* * don't expand into inline code * if size < inline_size */ while (cur != dl) { print_stat(indent + 1, &cur->decl); cur = cur->next; } } else { /* were already looking at a xdr_inlineable structure */ tabify(fout, indent + 1); if (sizestr == NULL) f_print(fout, "buf = XDR_INLINE(xdrs, %d * BYTES_PER_XDR_UNIT);", size); else { if (size == 0) f_print(fout, "buf = XDR_INLINE(xdrs, (%s) * BYTES_PER_XDR_UNIT);", sizestr); else f_print(fout, "buf = XDR_INLINE(xdrs, (%d + (%s)) * BYTES_PER_XDR_UNIT);", size, sizestr); } f_print(fout, "\n"); tabify(fout, indent + 1); f_print(fout, "if (buf == NULL) {\n"); psav = cur; while (cur != dl) { print_stat(indent + 2, &cur->decl); cur = cur->next; } f_print(fout, "\n\t\t} else {\n"); cur = psav; while (cur != dl) { emit_inline(indent + 2, &cur->decl, flag); cur = cur->next; } tabify(fout, indent + 1); f_print(fout, "}\n"); } } size = 0; i = 0; sizestr = NULL; print_stat(indent + 1, &dl->decl); } } if (i > 0) { if (sizestr == NULL && size < inline_size) { /* don't expand into inline code if size < inline_size */ while (cur != dl) { print_stat(indent + 1, &cur->decl); cur = cur->next; } } else { /* were already looking at a xdr_inlineable structure */ if (sizestr == NULL) f_print(fout, "\t\tbuf = XDR_INLINE(xdrs, %d * BYTES_PER_XDR_UNIT);", size); else { if (size == 0) f_print(fout, "\t\tbuf = XDR_INLINE(xdrs, (%s) * BYTES_PER_XDR_UNIT);", sizestr); else f_print(fout, "\t\tbuf = XDR_INLINE(xdrs, (%d + (%s)) * BYTES_PER_XDR_UNIT);", size, sizestr); } f_print(fout, "\n\t\tif (buf == NULL) {\n"); psav = cur; while (cur != NULL) { print_stat(indent + 2, &cur->decl); cur = cur->next; } f_print(fout, "\t\t} else {\n"); cur = psav; while (cur != dl) { emit_inline(indent + 2, &cur->decl, flag); cur = cur->next; } f_print(fout, "\t\t}\n"); } } } static void emit_struct(definition *def) { decl_list *dl; int j, size, flag; bas_type *ptr; int can_inline; if (inline_size == 0) { /* No xdr_inlining at all */ for (dl = def->def.st.decls; dl != NULL; dl = dl->next) print_stat(1, &dl->decl); return; } for (dl = def->def.st.decls; dl != NULL; dl = dl->next) { if (dl->decl.rel == REL_VECTOR){ f_print(fout, "\tint i;\n"); break; } } size = 0; can_inline = 0; /* * Make a first pass and see if inling is possible. */ for (dl = def->def.st.decls; dl != NULL; dl = dl->next) { if ((dl->decl.prefix == NULL) && ((ptr = find_type(dl->decl.type)) != NULL) && ((dl->decl.rel == REL_ALIAS)|| (dl->decl.rel == REL_VECTOR))) { if (dl->decl.rel == REL_ALIAS) size += ptr->length; else { can_inline = 1; break; /* can be inlined */ } } else { if (size >= inline_size) { can_inline = 1; break; /* can be inlined */ } size = 0; } } if (size >= inline_size) can_inline = 1; if (can_inline == 0) { /* can not inline, drop back to old mode */ for (dl = def->def.st.decls; dl != NULL; dl = dl->next) print_stat(1, &dl->decl); return; } flag = PUT; for (j = 0; j < 2; j++){ inline_struct(def, flag); if (flag == PUT) flag = GET; } f_print(fout, "\t\treturn (TRUE);\n\t}\n\n"); /* now take care of XDR_FREE case */ for (dl = def->def.st.decls; dl != NULL; dl = dl->next) print_stat(1, &dl->decl); } static void emit_typedef(definition *def) { const char *prefix = def->def.ty.old_prefix; const char *type = def->def.ty.old_type; const char *amax = def->def.ty.array_max; relation rel = def->def.ty.rel; print_ifstat(1, prefix, type, rel, amax, "objp", def->def_name); } static void print_stat(int indent, declaration *dec) { const char *prefix = dec->prefix; const char *type = dec->type; const char *amax = dec->array_max; relation rel = dec->rel; char name[256]; if (isvectordef(type, rel)) s_print(name, "objp->%s", dec->name); else s_print(name, "&objp->%s", dec->name); print_ifstat(indent, prefix, type, rel, amax, name, dec->name); } static void emit_inline(int indent, declaration *decl, int flag) { switch (decl->rel) { case REL_ALIAS : emit_single_in_line(indent, decl, flag, REL_ALIAS); break; case REL_VECTOR : tabify(fout, indent); f_print(fout, "{\n"); tabify(fout, indent + 1); f_print(fout, "%s *genp;\n\n", decl->type); tabify(fout, indent + 1); f_print(fout, "for (i = 0, genp = objp->%s;\n", decl->name); tabify(fout, indent + 2); f_print(fout, "i < %s; i++) {\n", decl->array_max); emit_single_in_line(indent + 2, decl, flag, REL_VECTOR); tabify(fout, indent + 1); f_print(fout, "}\n"); tabify(fout, indent); f_print(fout, "}\n"); break; default: break; } } static void emit_single_in_line(int indent, declaration *decl, int flag, relation rel) { char *upp_case; tabify(fout, indent); if (flag == PUT) f_print(fout, "IXDR_PUT_"); else if (rel == REL_ALIAS) f_print(fout, "objp->%s = IXDR_GET_", decl->name); else f_print(fout, "*genp++ = IXDR_GET_"); upp_case = upcase(decl->type); /* hack - XX */ if (strcmp(upp_case, "INT") == 0) { free(upp_case); upp_case = strdup("LONG"); } if (strcmp(upp_case, "U_INT") == 0) { free(upp_case); upp_case = strdup("U_LONG"); } if (flag == PUT) { if (rel == REL_ALIAS) f_print(fout, "%s(buf, objp->%s);\n", upp_case, decl->name); else f_print(fout, "%s(buf, *genp++);\n", upp_case); } else { f_print(fout, "%s(buf);\n", upp_case); } free(upp_case); } static char * upcase(const char *str) { char *ptr, *hptr; ptr = xmalloc(strlen(str)+1); hptr = ptr; while (*str != '\0') *ptr++ = toupper(*str++); *ptr = '\0'; return(hptr); } [FILE:10429:files/rpc_hout.c] #include #include #include "rpc_parse.h" #include "rpc_scan.h" #include "rpc_util.h" void storexdrfuncdecl(const char *, int); static void pconstdef(definition *); static void pstructdef(definition *); static void puniondef(definition *); static void pprogramdef(definition *, int); static void penumdef(definition *); static void ptypedef(definition *); static void pdefine(const char *, const char *); static int undefined2(const char *, const char *); static void parglist(proc_list *, const char *); static void pprocdef(proc_list *, version_list *, const char *, int); /* * Print the C-version of an xdr definition */ void print_datadef(definition *def, int headeronly) { if (def->def_kind == DEF_PROGRAM) /* handle data only */ return; if (def->def_kind != DEF_CONST) f_print(fout, "\n"); switch (def->def_kind) { case DEF_STRUCT: pstructdef(def); break; case DEF_UNION: puniondef(def); break; case DEF_ENUM: penumdef(def); break; case DEF_TYPEDEF: ptypedef(def); break; case DEF_PROGRAM: pprogramdef(def, headeronly); break; case DEF_CONST: pconstdef(def); break; } if (def->def_kind != DEF_PROGRAM && def->def_kind != DEF_CONST) { if (def->def_kind != DEF_TYPEDEF || !isvectordef(def->def.ty.old_type, def->def.ty.rel)) storexdrfuncdecl(def->def_name, 1); else storexdrfuncdecl(def->def_name, 0); } } void print_funcdef(definition *def, int headeronly) { switch (def->def_kind) { case DEF_PROGRAM: f_print(fout, "\n"); pprogramdef(def, headeronly); break; default: break; } } /* store away enough information to allow the XDR functions to be spat out at the end of the file */ void storexdrfuncdecl(const char *name, int pointerp) { xdrfunc * xdrptr; xdrptr = XALLOC(struct xdrfunc); xdrptr->name = name; xdrptr->pointerp = pointerp; xdrptr->next = NULL; if (xdrfunc_tail == NULL) xdrfunc_head = xdrptr; else xdrfunc_tail->next = xdrptr; xdrfunc_tail = xdrptr; } void print_xdr_func_def(const char *name, int pointerp) { f_print(fout, "extern bool_t xdr_%s(XDR *, %s%s);\n", name, name, pointerp ? "*" : ""); } static void pconstdef(definition *def) { pdefine(def->def_name, def->def.co); } /* print out the definitions for the arguments of functions in the header file */ static void pargdef(definition *def) { decl_list *l; version_list *vers; char *name; proc_list *plist; for (vers = def->def.pr.versions; vers != NULL; vers = vers->next) { for (plist = vers->procs; plist != NULL; plist = plist->next) { if (!newstyle || plist->arg_num < 2) continue; /* old style or single args */ name = plist->args.argname; f_print(fout, "struct %s {\n", name); for (l = plist->args.decls; l != NULL; l = l->next) pdeclaration(name, &l->decl, 1, ";\n"); f_print(fout, "};\n"); f_print(fout, "typedef struct %s %s;\n", name, name); storexdrfuncdecl(name, 1); f_print(fout, "\n"); } } } static void pstructdef(definition *def) { decl_list *l; const char *name = def->def_name; f_print(fout, "struct %s {\n", name); for (l = def->def.st.decls; l != NULL; l = l->next) pdeclaration(name, &l->decl, 1, ";\n"); f_print(fout, "};\n"); f_print(fout, "typedef struct %s %s;\n", name, name); } static void puniondef(definition *def) { case_list *l; const char *name = def->def_name; declaration *decl; f_print(fout, "struct %s {\n", name); decl = &def->def.un.enum_decl; if (streq(decl->type, "bool")) f_print(fout, "\tbool_t %s;\n", decl->name); else f_print(fout, "\t%s %s;\n", decl->type, decl->name); f_print(fout, "\tunion {\n"); for (l = def->def.un.cases; l != NULL; l = l->next) { if (l->contflag == 0) pdeclaration(name, &l->case_decl, 2, ";\n"); } decl = def->def.un.default_decl; if (decl && !streq(decl->type, "void")) { pdeclaration(name, decl, 2, ";\n"); } f_print(fout, "\t} %s_u;\n", name); f_print(fout, "};\n"); f_print(fout, "typedef struct %s %s;\n", name, name); } static void pdefine(const char *name, const char *num) { f_print(fout, "#define\t%s %s\n", name, num); } static void puldefine(const char *name, const char *num) { f_print(fout, "#define\t%s ((unsigned long)(%s))\n", name, num); } static int define_printed(proc_list *stop, version_list *start) { version_list *vers; proc_list *proc; for (vers = start; vers != NULL; vers = vers->next) { for (proc = vers->procs; proc != NULL; proc = proc->next) { if (proc == stop) return(0); else if (streq(proc->proc_name, stop->proc_name)) return(1); } } abort(); /* NOTREACHED */ } static void pfreeprocdef(const char * name, const char *vers) { f_print(fout, "extern int "); pvname(name, vers); f_print(fout, "_freeresult(SVCXPRT *, xdrproc_t, caddr_t);\n"); } static void pdispatch(const char * name, const char *vers) { f_print(fout, "void "); pvname(name, vers); f_print(fout, "(struct svc_req *rqstp, SVCXPRT *transp);\n"); } static void pprogramdef(definition *def, int headeronly) { version_list *vers; proc_list *proc; const char *ext; pargdef(def); puldefine(def->def_name, def->def.pr.prog_num); for (vers = def->def.pr.versions; vers != NULL; vers = vers->next) { if (tblflag) { f_print(fout, "extern struct rpcgen_table %s_%s_table[];\n", locase(def->def_name), vers->vers_num); f_print(fout, "extern %s_%s_nproc;\n", locase(def->def_name), vers->vers_num); } puldefine(vers->vers_name, vers->vers_num); f_print(fout, "\n"); ext = "extern "; if (headeronly) { f_print(fout, "%s", ext); pdispatch(def->def_name, vers->vers_num); } for (proc = vers->procs; proc != NULL; proc = proc->next) { if (!define_printed(proc, def->def.pr.versions)) { puldefine(proc->proc_name, proc->proc_num); } f_print(fout, "%s", ext); pprocdef(proc, vers, "CLIENT *", 0); f_print(fout, "%s", ext); pprocdef(proc, vers, "struct svc_req *", 1); } pfreeprocdef(def->def_name, vers->vers_num); } } static void pprocdef(proc_list *proc, version_list *vp, const char *addargtype, int server_p) { if (mtflag) { /* Print MT style stubs */ if (server_p) f_print(fout, "bool_t "); else f_print(fout, "enum clnt_stat "); } else { ptype(proc->res_prefix, proc->res_type, 1); f_print(fout, "* "); } if (server_p) pvname_svc(proc->proc_name, vp->vers_num); else pvname(proc->proc_name, vp->vers_num); parglist(proc, addargtype); } /* print out argument list of procedure */ static void parglist(proc_list *proc, const char *addargtype) { decl_list *dl; f_print(fout, "("); if (proc->arg_num < 2 && newstyle && streq(proc->args.decls->decl.type, "void")) { /* 0 argument in new style: do nothing*/ } else { for (dl = proc->args.decls; dl != NULL; dl = dl->next) { ptype(dl->decl.prefix, dl->decl.type, 1); if (!newstyle) f_print(fout, "*"); /* old style passes by reference */ f_print(fout, ", "); } } if (mtflag) { ptype(proc->res_prefix, proc->res_type, 1); f_print(fout, "*, "); } f_print(fout, "%s);\n", addargtype); } static void penumdef(definition *def) { const char *name = def->def_name; enumval_list *l; const char *last = NULL; int count = 0; f_print(fout, "enum %s {\n", name); for (l = def->def.en.vals; l != NULL; l = l->next) { f_print(fout, "\t%s", l->name); if (l->assignment) { f_print(fout, " = %s", l->assignment); last = l->assignment; count = 1; } else { if (last == NULL) f_print(fout, " = %d", count++); else f_print(fout, " = %s + %d", last, count++); } if (l->next) f_print(fout, ",\n"); else f_print(fout, "\n"); } f_print(fout, "};\n"); f_print(fout, "typedef enum %s %s;\n", name, name); } static void ptypedef(definition *def) { const char *name = def->def_name; const char *old = def->def.ty.old_type; char prefix[8]; /* enough to contain "struct ", including NUL */ relation rel = def->def.ty.rel; if (!streq(name, old)) { if (streq(old, "string")) { old = "char"; rel = REL_POINTER; } else if (streq(old, "opaque")) { old = "char"; } else if (streq(old, "bool")) { old = "bool_t"; } if (undefined2(old, name) && def->def.ty.old_prefix) s_print(prefix, "%s ", def->def.ty.old_prefix); else prefix[0] = 0; f_print(fout, "typedef "); switch (rel) { case REL_ARRAY: f_print(fout, "struct {\n"); f_print(fout, "\tu_int %s_len;\n", name); f_print(fout, "\t%s%s *%s_val;\n", prefix, old, name); f_print(fout, "} %s", name); break; case REL_POINTER: f_print(fout, "%s%s *%s", prefix, old, name); break; case REL_VECTOR: f_print(fout, "%s%s %s[%s]", prefix, old, name, def->def.ty.array_max); break; case REL_ALIAS: f_print(fout, "%s%s %s", prefix, old, name); break; } f_print(fout, ";\n"); } } void pdeclaration(const char *name, declaration *dec, int tab, const char *separator) { char buf[8]; /* enough to hold "struct ", include NUL */ const char *prefix; const char *type; if (streq(dec->type, "void")) return; tabify(fout, tab); if (streq(dec->type, name) && !dec->prefix) f_print(fout, "struct "); if (streq(dec->type, "string")) { f_print(fout, "char *%s", dec->name); } else { prefix = ""; if (streq(dec->type, "bool")) { type = "bool_t"; } else if (streq(dec->type, "opaque")) { type = "char"; } else { if (dec->prefix) { s_print(buf, "%s ", dec->prefix); prefix = buf; } type = dec->type; } switch (dec->rel) { case REL_ALIAS: f_print(fout, "%s%s %s", prefix, type, dec->name); break; case REL_VECTOR: f_print(fout, "%s%s %s[%s]", prefix, type, dec->name, dec->array_max); break; case REL_POINTER: f_print(fout, "%s%s *%s", prefix, type, dec->name); break; case REL_ARRAY: f_print(fout, "struct {\n"); tabify(fout, tab); f_print(fout, "\tu_int %s_len;\n", dec->name); tabify(fout, tab); f_print(fout, "\t%s%s *%s_val;\n", prefix, type, dec->name); tabify(fout, tab); f_print(fout, "} %s", dec->name); break; } } f_print(fout, "%s", separator); } static int undefined2(const char *type, const char *stop) { list *l; definition *def; for (l = defined; l != NULL; l = l->next) { def = (definition *) l->val; if (def->def_kind != DEF_PROGRAM) { if (streq(def->def_name, stop)) return(1); else if (streq(def->def_name, type)) return(0); } } return(1); } [FILE:28607:files/rpc_main.c] /* * rpc_main.c, Top level of the RPC protocol compiler. */ #include #include #include #include #include #include #include #include #include #include "rpc_parse.h" #include "rpc_scan.h" #include "rpc_util.h" #ifdef __linux__ #include #endif static void c_output(const char *, const char *, int, const char *); static void h_output(const char *, const char *, int, const char *, int); static void l_output(const char *, const char *, int, const char *); static void t_output(const char *, const char *, int, const char *); static void clnt_output(const char *, const char *, int, const char *); static char *generate_guard(const char *); static void c_initialize(void); static void usage(void); static void options_usage(void); static int do_registers(int, const char **); static int parseargs(int, const char **, struct commandline *); static void svc_output(const char *, const char *, int, const char *); static void mkfile_output(struct commandline *); static void s_output(int, const char **, const char *, const char *, int, const char *, int, int); #define EXTEND 1 /* alias for TRUE */ #define DONT_EXTEND 0 /* alias for FALSE */ static int cppDefined = 0; /* explicit path for C preprocessor */ static const char *svcclosetime = "120"; static const char *CPP = NULL; static const char CPPFLAGS[] = "-C"; static char pathbuf[MAXPATHLEN + 1]; static const char *allv[] = { "rpcgen", "-s", "udp", "-s", "tcp", }; static int allc = sizeof (allv)/sizeof (allv[0]); static const char *allnv[] = { "rpcgen", "-s", "netpath", }; static int allnc = sizeof (allnv)/sizeof (allnv[0]); /* * machinations for handling expanding argument list */ static void addarg(const char *); /* add another argument to the list */ static void putarg(int, const char *); /* put argument at specified location */ static void clear_args(void); /* clear argument list */ static void checkfiles(const char *, const char *); /* check if out file already exists */ #define ARGLISTLEN 20 #define FIXEDARGS 2 static char *arglist[ARGLISTLEN]; static int argcount = FIXEDARGS; int nonfatalerrors; /* errors */ int inetdflag = 0; /* Support for inetd is disabled by default, use -I */ int pmflag = 0; /* Support for port monitors is disabled by default */ int tirpc_socket = 1; /* TI-RPC on socket, no TLI library */ int logflag; /* Use syslog instead of fprintf for errors */ int tblflag; /* Support for dispatch table file */ int mtflag = 0; /* Support for MT */ #define INLINE 0 /* length at which to start doing an inline */ int inline_size = INLINE; /* * Length at which to start doing an inline. INLINE = default * if 0, no xdr_inline code */ int indefinitewait; /* If started by port monitors, hang till it wants */ int exitnow; /* If started by port monitors, exit after the call */ int timerflag; /* TRUE if !indefinite && !exitnow */ int newstyle; /* newstyle of passing arguments (by value) */ int CCflag = 0; /* C++ files */ static int allfiles; /* generate all files */ int tirpcflag = 1; /* generating code for tirpc, by default */ xdrfunc *xdrfunc_head = NULL; /* xdr function list */ xdrfunc *xdrfunc_tail = NULL; /* xdr function list */ pid_t childpid; int main(int argc, const char **argv) { struct commandline cmd; memset(&cmd, 0, sizeof (struct commandline)); clear_args(); if (!parseargs(argc, argv, &cmd)) usage(); /* * Only the client and server side stubs are likely to be customized, * so in that case only, check if the outfile exists, and if so, * print an error message and exit. */ if (cmd.Ssflag || cmd.Scflag || cmd.makefileflag) checkfiles(cmd.infile, cmd.outfile); else checkfiles(cmd.infile, NULL); if (cmd.cflag) { c_output(cmd.infile, "-DRPC_XDR", DONT_EXTEND, cmd.outfile); } else if (cmd.hflag) { h_output(cmd.infile, "-DRPC_HDR", DONT_EXTEND, cmd.outfile, cmd.hflag); } else if (cmd.lflag) { l_output(cmd.infile, "-DRPC_CLNT", DONT_EXTEND, cmd.outfile); } else if (cmd.sflag || cmd.mflag || (cmd.nflag)) { s_output(argc, argv, cmd.infile, "-DRPC_SVC", DONT_EXTEND, cmd.outfile, cmd.mflag, cmd.nflag); } else if (cmd.tflag) { t_output(cmd.infile, "-DRPC_TBL", DONT_EXTEND, cmd.outfile); } else if (cmd.Ssflag) { svc_output(cmd.infile, "-DRPC_SERVER", DONT_EXTEND, cmd.outfile); } else if (cmd.Scflag) { clnt_output(cmd.infile, "-DRPC_CLIENT", DONT_EXTEND, cmd.outfile); } else if (cmd.makefileflag) { mkfile_output(&cmd); } else { /* the rescans are required, since cpp may effect input */ c_output(cmd.infile, "-DRPC_XDR", EXTEND, "_xdr.c"); reinitialize(); h_output(cmd.infile, "-DRPC_HDR", EXTEND, ".h", cmd.hflag); reinitialize(); l_output(cmd.infile, "-DRPC_CLNT", EXTEND, "_clnt.c"); reinitialize(); if (inetdflag || !tirpcflag) s_output(allc, allv, cmd.infile, "-DRPC_SVC", EXTEND, "_svc.c", cmd.mflag, cmd.nflag); else s_output(allnc, allnv, cmd.infile, "-DRPC_SVC", EXTEND, "_svc.c", cmd.mflag, cmd.nflag); if (tblflag) { reinitialize(); t_output(cmd.infile, "-DRPC_TBL", EXTEND, "_tbl.i"); } if (allfiles) { reinitialize(); svc_output(cmd.infile, "-DRPC_SERVER", EXTEND, "_server.c"); reinitialize(); clnt_output(cmd.infile, "-DRPC_CLIENT", EXTEND, "_client.c"); } if (allfiles || (cmd.makefileflag == 1)){ reinitialize(); mkfile_output(&cmd); } } exit(nonfatalerrors); /* NOTREACHED */ } /* * add extension to filename */ static char * extendfile(const char *path, const char *ext) { char *res; const char *p; const char *file; if ((file = strrchr(path, '/')) == NULL) file = path; else file++; res = xmalloc(strlen(file) + strlen(ext) + 1); p = strrchr(file, '.'); if (p == NULL) p = file + strlen(file); strcpy(res, file); strcpy(res + (p - file), ext); return(res); } /* * Open output file with given extension */ static void open_output(const char *infile, const char *outfile) { if (outfile == NULL) { fout = stdout; return; } if (infile != NULL && streq(outfile, infile)) { warnx("%s already exists. No output generated", infile); crash(); } fout = fopen(outfile, "w"); if (fout == NULL) { warn("unable to open %s", outfile); crash(); } record_open(outfile); } static void add_warning(void) { f_print(fout, "/*\n"); f_print(fout, " * Please do not edit this file.\n"); f_print(fout, " * It was generated using rpcgen.\n"); f_print(fout, " */\n\n"); } /* clear list of arguments */ static void clear_args(void) { int i; for (i = FIXEDARGS; i < ARGLISTLEN; i++) arglist[i] = NULL; argcount = FIXEDARGS; } /* make sure that a CPP exists */ static int find_cpp(void) { if (CPP) return(0); CPP = "cpp"; return(1); } /* * Open input file with given define for C-preprocessor */ static void open_input(const char *infile, const char *define) { int pd[2]; int usevp; infilename = (infile == NULL) ? "" : infile; pipe(pd); switch (childpid = fork()) { case 0: usevp = find_cpp(); putarg(0, CPP); putarg(1, CPPFLAGS); addarg(define); if (infile) addarg(infile); addarg(NULL); close(1); dup2(pd[1], 1); close(pd[0]); if (usevp) execvp(arglist[0], arglist); else execv(arglist[0], arglist); err(1, "execv(%s)", arglist[0]); case -1: err(1, "fork"); } close(pd[1]); fin = fdopen(pd[0], "r"); if (fin == NULL) { warn("%s", infilename); crash(); } } /* valid tirpc nettypes */ static const char *valid_ti_nettypes[] = { "netpath", "visible", "circuit_v", "datagram_v", "circuit_n", "datagram_n", "udp", "tcp", "raw", NULL }; /* valid inetd nettypes */ static const char *valid_i_nettypes[] = { "udp", "tcp", NULL }; static int check_nettype(const char *name, const char *list_to_check[]) { int i; for (i = 0; list_to_check[i] != NULL; i++) { if (strcmp(name, list_to_check[i]) == 0) return(1); } warnx("illegal nettype :\'%s\'", name); return(0); } static const char * file_name(const char *file, const char *ext) { char *temp; temp = extendfile(file, ext); if (access(temp, F_OK) != -1) return(temp); else return(" "); } static void c_output(const char *infile, const char *define, int extend, const char *outfile) { definition *def; char *include; const char *outfilename; long tell; c_initialize(); open_input(infile, define); outfilename = extend ? extendfile(infile, outfile) : outfile; open_output(infile, outfilename); add_warning(); if (infile && (include = extendfile(infile, ".h"))) { f_print(fout, "#include \"%s\"\n", include); free(include); /* .h file already contains rpc/rpc.h */ } else f_print(fout, "#include \n"); tell = ftell(fout); while ( (def = get_definition()) ) emit(def); if (extend && tell == ftell(fout)) unlink(outfilename); } void c_initialize(void) { /* add all the starting basic types */ add_type(1, "int"); add_type(1, "long"); add_type(1, "short"); add_type(1, "bool"); add_type(1, "u_int"); add_type(1, "u_long"); add_type(1, "u_short"); } const char rpcgen_table_dcl[] = "struct rpcgen_table {\n\ char *(*proc)(); \n\ xdrproc_t xdr_arg; \n\ unsigned len_arg; \n\ xdrproc_t xdr_res; \n\ unsigned len_res; \n\ }; \n"; char * generate_guard(const char *pathname) { const char *filename; char *guard, *tmp, *stopat; filename = strrchr(pathname, '/'); /* find last component */ filename = ((filename == NULL) ? pathname : filename+1); guard = xstrdup(filename); stopat = strrchr(guard, '.'); /* * Convert to a valid C macro name and make it upper case. * Map macro unfriendly characterss to '_'. */ for (tmp = guard; *tmp != '\000'; ++tmp) { if (islower(*tmp)) *tmp = toupper(*tmp); else if (isupper(*tmp) || *tmp == '_') /* OK for C */; else if (tmp == guard) *tmp = '_'; else if (isdigit(*tmp)) /* OK for all but first character */; else if (tmp == stopat) { *tmp = '\0'; break; } else *tmp = '_'; } /* * Can't have a '_' in front, because it'll end up being "__". * "__" macros shoudln't be used. So, remove all of the * '_' characters from the front. */ if (*guard == '_') { for (tmp = guard; *tmp == '_'; ++tmp) ; strcpy(guard, tmp); } guard = extendfile(guard, "_H_RPCGEN"); return(guard); } /* * Compile into an XDR header file */ static void h_output(const char *infile, const char *define, int extend, const char *outfile, int headeronly) { definition *def; const char *outfilename; long tell; const char *guard; list *l; xdrfunc *xdrfuncp; open_input(infile, define); outfilename = extend ? extendfile(infile, outfile) : outfile; open_output(infile, outfilename); add_warning(); if (outfilename || infile){ guard = generate_guard(outfilename ? outfilename: infile); } else guard = "STDIN_"; f_print(fout, "#ifndef _%s\n#define _%s\n\n", guard, guard); f_print(fout, "#include \n"); if (mtflag) f_print(fout, "#include \n"); /* put the C++ support */ if (!CCflag) { f_print(fout, "\n#ifdef __cplusplus\n"); f_print(fout, "extern \"C\" {\n"); f_print(fout, "#endif\n\n"); } /* put in a typedef for quadprecision. Only with Cflag */ tell = ftell(fout); /* print data definitions */ while ((def = get_definition()) != NULL) print_datadef(def, headeronly); /* * print function declarations. * Do this after data definitions because they might be used as * arguments for functions */ for (l = defined; l != NULL; l = l->next) print_funcdef(l->val, headeronly); /* Now print all xdr func declarations */ if (xdrfunc_head != NULL) { f_print(fout, "\n/* the xdr functions */\n"); if (CCflag) { f_print(fout, "\n#ifdef __cplusplus\n"); f_print(fout, "extern \"C\" {\n"); f_print(fout, "#endif\n"); } xdrfuncp = xdrfunc_head; while (xdrfuncp != NULL) { print_xdr_func_def(xdrfuncp->name, xdrfuncp->pointerp); xdrfuncp = xdrfuncp->next; } } if (extend && tell == ftell(fout)) unlink(outfilename); else if (tblflag) f_print(fout, rpcgen_table_dcl); f_print(fout, "\n#ifdef __cplusplus\n"); f_print(fout, "}\n"); f_print(fout, "#endif\n"); f_print(fout, "\n#endif /* !_%s */\n", guard); } /* * Compile into an RPC service */ static void s_output(int argc, const char **argv, const char *infile, const char *define, int extend, const char *outfile, int nomain, int netflag) { char *include; definition *def; int foundprogram = 0; const char *outfilename; open_input(infile, define); outfilename = extend ? extendfile(infile, outfile) : outfile; open_output(infile, outfilename); add_warning(); if (infile && (include = extendfile(infile, ".h"))) { f_print(fout, "#include \"%s\"\n", include); free(include); } else f_print(fout, "#include \n"); f_print(fout, "#include \n"); f_print(fout, "#include /* getenv, exit */\n"); f_print(fout, "#include /* for pmap_unset */\n"); f_print(fout, "#include /* strcmp */\n"); if (tirpcflag) f_print(fout, "#include \n"); if (strcmp(svcclosetime, "-1") == 0) indefinitewait = 1; else if (strcmp(svcclosetime, "0") == 0) exitnow = 1; else if (inetdflag || pmflag) { f_print(fout, "#include \n"); timerflag = 1; } if (!tirpcflag && inetdflag) f_print(fout, "#include /* TIOCNOTTY */\n"); if (inetdflag || pmflag) { f_print(fout, "#ifdef __cplusplus\n"); f_print(fout, "#include /* getdtablesize, open */\n"); f_print(fout, "#endif /* __cplusplus */\n"); } if (tirpcflag) { f_print(fout, "#include /* open */\n"); f_print(fout, "#include /* fork / setsid */\n"); f_print(fout, "#include \n"); } f_print(fout, "#include \n"); if (inetdflag || !tirpcflag) { f_print(fout, "#include \n"); f_print(fout, "#include \n"); } if ((netflag || pmflag) && tirpcflag && !nomain) f_print(fout, "#include \n"); if (tirpcflag) f_print(fout, "#include /* rlimit */\n"); if (logflag || inetdflag || pmflag || tirpcflag) f_print(fout, "#include \n"); f_print(fout, "\n#ifdef DEBUG\n#define RPC_SVC_FG\n#endif\n"); if (timerflag) f_print(fout, "\n#define _RPCSVC_CLOSEDOWN %s\n", svcclosetime); while ((def = get_definition()) != NULL) foundprogram |= (def->def_kind == DEF_PROGRAM); if (extend && !foundprogram) { unlink(outfilename); return; } write_most(infile, netflag, nomain); if (!nomain) { if (!do_registers(argc, argv)) { if (outfilename) unlink(outfilename); usage(); } write_rest(); } } /* * generate client side stubs */ static void l_output(const char *infile, const char *define, int extend, const char *outfile) { char *include; definition *def; int foundprogram = 0; const char *outfilename; open_input(infile, define); outfilename = extend ? extendfile(infile, outfile) : outfile; open_output(infile, outfilename); add_warning(); f_print(fout, "#include /* for memset */\n"); if (infile && (include = extendfile(infile, ".h"))) { f_print(fout, "#include \"%s\"\n", include); free(include); } else f_print(fout, "#include \n"); while ((def = get_definition()) != NULL) foundprogram |= (def->def_kind == DEF_PROGRAM); if (extend && !foundprogram) unlink(outfilename); else write_stubs(); } /* * generate the dispatch table */ static void t_output(const char *infile, const char *define, int extend, const char *outfile) { definition *def; int foundprogram = 0; const char *outfilename; open_input(infile, define); outfilename = extend ? extendfile(infile, outfile) : outfile; open_output(infile, outfilename); add_warning(); while ((def = get_definition()) != NULL) foundprogram |= (def->def_kind == DEF_PROGRAM); if (extend && !foundprogram) unlink(outfilename); else write_tables(); } /* sample routine for the server template */ static void svc_output(const char *infile, const char *define, int extend, const char *outfile) { definition *def; char *include; const char *outfilename; long tell; open_input(infile, define); outfilename = extend ? extendfile(infile, outfile) : outfile; checkfiles(infile, outfilename); /* * Check if outfile already exists. * if so, print an error message and exit */ open_output(infile, outfilename); add_sample_msg(); if (infile && (include = extendfile(infile, ".h"))) { f_print(fout, "#include \"%s\"\n", include); free(include); } else f_print(fout, "#include \n"); tell = ftell(fout); while ((def = get_definition()) != NULL) write_sample_svc(def); if (extend && tell == ftell(fout)) unlink(outfilename); } /* sample main routine for client */ static void clnt_output(const char *infile, const char *define, int extend, const char *outfile) { definition *def; char *include; const char *outfilename; long tell; int has_program = 0; open_input(infile, define); outfilename = extend ? extendfile(infile, outfile) : outfile; checkfiles(infile, outfilename); /* * Check if outfile already exists. * if so, print an error message and exit */ open_output(infile, outfilename); add_sample_msg(); if (infile && (include = extendfile(infile, ".h"))) { f_print(fout, "#include \"%s\"\n", include); free(include); } else f_print(fout, "#include \n"); tell = ftell(fout); while ((def = get_definition()) != NULL) has_program += write_sample_clnt(def); if (has_program) write_sample_clnt_main(); if (extend && tell == ftell(fout)) unlink(outfilename); } static void mkfile_output(struct commandline *cmd) { const char *mkfilename, *clientname, *clntname, *xdrname, *hdrname; const char *servername, *svcname, *servprogname, *clntprogname; char *temp, *mkftemp; svcname = file_name(cmd->infile, "_svc.c"); clntname = file_name(cmd->infile, "_clnt.c"); xdrname = file_name(cmd->infile, "_xdr.c"); hdrname = file_name(cmd->infile, ".h"); if (allfiles) { servername = extendfile(cmd->infile, "_server.c"); clientname = extendfile(cmd->infile, "_client.c"); } else { servername = " "; clientname = " "; } servprogname = extendfile(cmd->infile, "_server"); clntprogname = extendfile(cmd->infile, "_client"); if (allfiles) { mkftemp = xmalloc(strlen("makefile.") + strlen(cmd->infile) + 1); temp = strrchr(cmd->infile, '.'); strcpy(mkftemp, "makefile."); strncat(mkftemp, cmd->infile, (temp - cmd->infile)); mkfilename = mkftemp; } else mkfilename = cmd->outfile; checkfiles(NULL, mkfilename); open_output(NULL, mkfilename); f_print(fout, "\n# This is a template makefile generated " "by rpcgen \n"); f_print(fout, "\n# Parameters \n\n"); f_print(fout, "CLIENT = %s\nSERVER = %s\n\n", clntprogname, servprogname); f_print(fout, "SOURCES_CLNT.c = \nSOURCES_CLNT.h = \n"); f_print(fout, "SOURCES_SVC.c = \nSOURCES_SVC.h = \n"); f_print(fout, "SOURCES.x = %s\n\n", cmd->infile); f_print(fout, "TARGETS_SVC.c = %s %s %s \n", svcname, servername, xdrname); f_print(fout, "TARGETS_CLNT.c = %s %s %s \n", clntname, clientname, xdrname); f_print(fout, "TARGETS = %s %s %s %s %s %s\n\n", hdrname, xdrname, clntname, svcname, clientname, servername); f_print(fout, "OBJECTS_CLNT = $(SOURCES_CLNT.c:%%.c=%%.o) " "$(TARGETS_CLNT.c:%%.c=%%.o) "); f_print(fout, "\nOBJECTS_SVC = $(SOURCES_SVC.c:%%.c=%%.o) " "$(TARGETS_SVC.c:%%.c=%%.o) "); f_print(fout, "\n# Compiler flags \n"); if (mtflag) f_print(fout, "\nCFLAGS += -D_REENTRANT -D_THEAD_SAFE \nLDLIBS += -pthread\n"); f_print(fout, "RPCGENFLAGS = \n"); f_print(fout, "\n# Targets \n\n"); f_print(fout, "all : $(CLIENT) $(SERVER)\n\n"); f_print(fout, "$(TARGETS) : $(SOURCES.x) \n"); f_print(fout, "\trpcgen $(RPCGENFLAGS) $(SOURCES.x)\n\n"); f_print(fout, "$(OBJECTS_CLNT) : $(SOURCES_CLNT.c) $(SOURCES_CLNT.h) " "$(TARGETS_CLNT.c) \n\n"); f_print(fout, "$(OBJECTS_SVC) : $(SOURCES_SVC.c) $(SOURCES_SVC.h) " "$(TARGETS_SVC.c) \n\n"); f_print(fout, "$(CLIENT) : $(OBJECTS_CLNT) \n"); f_print(fout, "\t$(CC) -o $(CLIENT) $(OBJECTS_CLNT) $(LDLIBS) \n\n"); f_print(fout, "$(SERVER) : $(OBJECTS_SVC) \n"); f_print(fout, "\t$(CC) -o $(SERVER) $(OBJECTS_SVC) $(LDLIBS)\n\n "); f_print(fout, "clean:\n\t $(RM) -f core $(TARGETS) $(OBJECTS_CLNT) " "$(OBJECTS_SVC) $(CLIENT) $(SERVER)\n\n"); } /* * Perform registrations for service output * Return 0 if failed; 1 otherwise. */ static int do_registers(int argc, const char **argv) { int i; if (inetdflag || !tirpcflag) { for (i = 1; i < argc; i++) { if (streq(argv[i], "-s")) { if (!check_nettype(argv[i + 1], valid_i_nettypes)) return(0); write_inetd_register(argv[i + 1]); i++; } } } else { for (i = 1; i < argc; i++) if (streq(argv[i], "-s")) { if (!check_nettype(argv[i + 1], valid_ti_nettypes)) return(0); write_nettype_register(argv[i + 1]); i++; } else if (streq(argv[i], "-n")) { write_netid_register(argv[i + 1]); i++; } } return(1); } /* * Add another argument to the arg list */ static void addarg(const char *cp) { if (argcount >= ARGLISTLEN) { warnx("too many defines"); crash(); /*NOTREACHED*/ } if (cp != NULL) arglist[argcount++] = xstrdup(cp); else arglist[argcount++] = NULL; } static void putarg(int place, const char *cp) { if (place >= ARGLISTLEN) { warnx("arglist coding error"); crash(); /*NOTREACHED*/ } if (cp != NULL) arglist[place] = xstrdup(cp); else arglist[place] = NULL; } /* * if input file is stdin and an output file is specified then complain * if the file already exists. Otherwise the file may get overwritten * If input file does not exist, exit with an error */ static void checkfiles(const char *infile, const char *outfile) { struct stat buf; if (infile != NULL && stat(infile, &buf) < 0) { warn("%s", infile); crash(); } if (outfile) { if (stat(outfile, &buf) < 0) return; /* file does not exist */ else { warnx("file '%s' already exists and may be overwritten", outfile); crash(); } } } /* * Parse command line arguments */ static int parseargs(int argc, const char **argv, struct commandline *cmd) { int i; int j; char c, ch; char flag[(1 << 8 * sizeof (char))]; int nflags; cmd->infile = cmd->outfile = NULL; if (argc < 2) return(0); allfiles = 0; flag['c'] = 0; flag['h'] = 0; flag['l'] = 0; flag['m'] = 0; flag['o'] = 0; flag['s'] = 0; flag['n'] = 0; flag['t'] = 0; flag['S'] = 0; flag['C'] = 0; flag['M'] = 0; for (i = 1; i < argc; i++) { if (argv[i][0] != '-') { if (cmd->infile) { warnx("cannot specify more than one input file"); return(0); } cmd->infile = argv[i]; } else { for (j = 1; argv[i][j] != 0; j++) { c = argv[i][j]; switch (c) { case 'a': allfiles = 1; break; case 'c': case 'h': case 'l': case 'm': case 't': if (flag[(int)c]) return(0); flag[(int)c] = 1; break; case 'S': /* * sample flag: Ss or Sc. * Ss means set flag['S']; * Sc means set flag['C']; * Sm means set flag['M']; */ ch = argv[i][++j]; /* get next char */ if (ch == 's') ch = 'S'; else if (ch == 'c') ch = 'C'; else if (ch == 'm') ch = 'M'; else return(0); if (flag[(int)ch]) return(0); flag[(int)ch] = 1; break; case 'C': /* ANSI C syntax */ ch = argv[i][j+1]; /* get next char */ if (ch != 'C') break; CCflag = 1; break; case 'b': /* * Turn TIRPC flag off for * generating backward compatible * code */ tirpcflag = 0; break; case 'I': inetdflag = 1; break; case 'N': newstyle = 1; break; case 'L': logflag = 1; break; case 'P': pmflag = 1; break; case 'K': if (++i == argc) return(0); svcclosetime = argv[i]; goto nextarg; case 'T': tblflag = 1; break; case 'M': mtflag = 1; break; case 'i' : if (++i == argc) return(0); inline_size = atoi(argv[i]); goto nextarg; case 'n': case 'o': case 's': if (argv[i][j - 1] != '-' || argv[i][j + 1] != 0) return(0); flag[(int)c] = 1; if (++i == argc) return(0); if (c == 'o') { if (cmd->outfile) return(0); cmd->outfile = argv[i]; } goto nextarg; case 'D': if (argv[i][j - 1] != '-') return(0); addarg(argv[i]); goto nextarg; case 'Y': if (++i == argc) return(0); strlcpy(pathbuf, argv[i], sizeof(pathbuf)); if (strlcat(pathbuf, "/cpp", sizeof(pathbuf)) >= sizeof(pathbuf)) { warnx("argument too long"); return (0); } CPP = pathbuf; cppDefined = 1; goto nextarg; default: return(0); } } nextarg: ; } } cmd->cflag = flag['c']; cmd->hflag = flag['h']; cmd->lflag = flag['l']; cmd->mflag = flag['m']; cmd->nflag = flag['n']; cmd->sflag = flag['s']; cmd->tflag = flag['t']; cmd->Ssflag = flag['S']; cmd->Scflag = flag['C']; cmd->makefileflag = flag['M']; if (tirpcflag) { if (inetdflag) pmflag = 0; if ((inetdflag && cmd->nflag)) { /* netid not allowed with inetdflag */ warnx("cannot use netid flag with inetd flag"); return(0); } } else { /* 4.1 mode */ pmflag = 0; /* set pmflag only in tirpcmode */ if (cmd->nflag) { /* netid needs TIRPC */ warnx("cannot use netid flag without TIRPC"); return(0); } } if (newstyle && (tblflag || cmd->tflag)) { warnx("cannot use table flags with newstyle"); return(0); } /* check no conflicts with file generation flags */ nflags = cmd->cflag + cmd->hflag + cmd->lflag + cmd->mflag + cmd->sflag + cmd->nflag + cmd->tflag + cmd->Ssflag + cmd->Scflag + cmd->makefileflag; if (nflags == 0) { if (cmd->outfile != NULL || cmd->infile == NULL) return(0); } else if (cmd->infile == NULL && (cmd->Ssflag || cmd->Scflag || cmd->makefileflag)) { warnx("\"infile\" is required for template generation flags"); return(0); } if (nflags > 1) { warnx("cannot have more than one file generation flag"); return(0); } return(1); } static void usage(void) { f_print(stderr, "%s\n%s\n%s\n%s\n%s\n", "usage: rpcgen infile", " rpcgen [-abCLNTM] [-Dname[=value]] [-i size]" "[-I -P [-K seconds]] [-Y path] infile", " rpcgen [-c | -h | -l | -m | -t | -Sc | -Ss | -Sm]" "[-o outfile] [infile]", " rpcgen [-s nettype]* [-o outfile] [infile]", " rpcgen [-n netid]* [-o outfile] [infile]"); options_usage(); exit(1); } static void options_usage(void) { f_print(stderr, "options:\n"); f_print(stderr, "-a\t\tgenerate all files, including samples\n"); f_print(stderr, "-b\t\tbackward compatibility mode (generates code" "for SunOS 4.X)\n"); f_print(stderr, "-c\t\tgenerate XDR routines\n"); f_print(stderr, "-C\t\tANSI C mode\n"); f_print(stderr, "-Dname[=value]\tdefine a symbol (same as #define)\n"); f_print(stderr, "-h\t\tgenerate header file\n"); f_print(stderr, "-i size\t\tsize at which to start generating" "inline code\n"); f_print(stderr, "-I\t\tgenerate code for inetd support in server\n"); f_print(stderr, "-K seconds\tserver exits after K seconds of" "inactivity\n"); f_print(stderr, "-l\t\tgenerate client side stubs\n"); f_print(stderr, "-L\t\tserver errors will be printed to syslog\n"); f_print(stderr, "-m\t\tgenerate server side stubs\n"); f_print(stderr, "-M\t\tgenerate MT-safe code\n"); f_print(stderr, "-n netid\tgenerate server code that supports" "named netid\n"); f_print(stderr, "-N\t\tsupports multiple arguments and" "call-by-value\n"); f_print(stderr, "-o outfile\tname of the output file\n"); f_print(stderr, "-P\t\tgenerate code for port monitoring support in server\n"); f_print(stderr, "-s nettype\tgenerate server code that supports named" "nettype\n"); f_print(stderr, "-Sc\t\tgenerate sample client code that uses remote" "procedures\n"); f_print(stderr, "-Ss\t\tgenerate sample server code that defines" "remote procedures\n"); f_print(stderr, "-Sm \t\tgenerate makefile template \n"); f_print(stderr, "-t\t\tgenerate RPC dispatch table\n"); f_print(stderr, "-T\t\tgenerate code to support RPC dispatch tables\n"); f_print(stderr, "-Y path\t\tpath where cpp is found\n"); exit(1); } [FILE:12599:files/rpc_parse.c] #include #include #include "rpc/types.h" #include "rpc_parse.h" #include "rpc_scan.h" #include "rpc_util.h" #define ARGNAME "arg" static void isdefined(definition *); static void def_struct(definition *); static void def_program(definition *); static void def_enum(definition *); static void def_const(definition *); static void def_union(definition *); static void def_typedef(definition *); static void get_declaration(declaration *, defkind); static void get_prog_declaration(declaration *, defkind, int); static void get_type(const char **, const char **, defkind); static void unsigned_dec(const char **); /* * return the next definition you see */ definition * get_definition(void) { definition *defp; token tok; defp = XALLOC(definition); get_token(&tok); switch (tok.kind) { case TOK_STRUCT: def_struct(defp); break; case TOK_UNION: def_union(defp); break; case TOK_TYPEDEF: def_typedef(defp); break; case TOK_ENUM: def_enum(defp); break; case TOK_PROGRAM: def_program(defp); break; case TOK_CONST: def_const(defp); break; case TOK_EOF: return(NULL); default: error("definition keyword expected"); } scan(TOK_SEMICOLON, &tok); isdefined(defp); return(defp); } static void isdefined(definition *defp) { STOREVAL(&defined, defp); } static void def_struct(definition *defp) { token tok; declaration dec; decl_list *decls; decl_list **tailp; defp->def_kind = DEF_STRUCT; scan(TOK_IDENT, &tok); defp->def_name = tok.str; scan(TOK_LBRACE, &tok); tailp = &defp->def.st.decls; do { get_declaration(&dec, DEF_STRUCT); decls = XALLOC(decl_list); decls->decl = dec; *tailp = decls; tailp = &decls->next; scan(TOK_SEMICOLON, &tok); peek(&tok); } while (tok.kind != TOK_RBRACE); get_token(&tok); *tailp = NULL; } static void def_program(definition *defp) { token tok; declaration dec; decl_list *decls; decl_list **tailp; version_list *vlist; version_list **vtailp; proc_list *plist; proc_list **ptailp; int num_args; bool_t isvoid = FALSE; /* whether first argument is void */ defp->def_kind = DEF_PROGRAM; scan(TOK_IDENT, &tok); defp->def_name = tok.str; scan(TOK_LBRACE, &tok); vtailp = &defp->def.pr.versions; tailp = &defp->def.st.decls; scan(TOK_VERSION, &tok); do { scan(TOK_IDENT, &tok); vlist = XALLOC(version_list); vlist->vers_name = tok.str; scan(TOK_LBRACE, &tok); ptailp = &vlist->procs; do { /* get result type */ plist = XALLOC(proc_list); get_type(&plist->res_prefix, &plist->res_type, DEF_PROGRAM); if (streq(plist->res_type, "opaque")) error("illegal result type"); scan(TOK_IDENT, &tok); plist->proc_name = tok.str; scan(TOK_LPAREN, &tok); /* get args - first one */ num_args = 1; isvoid = FALSE; /* * type of DEF_PROGRAM in the first * get_prog_declaration and DEF_STURCT in the next * allows void as argument if it is the only argument */ get_prog_declaration(&dec, DEF_PROGRAM, num_args); if (streq(dec.type, "void")) isvoid = TRUE; decls = XALLOC(decl_list); plist->args.decls = decls; decls->decl = dec; tailp = &decls->next; /* get args */ while (peekscan(TOK_COMMA, &tok)) { num_args++; get_prog_declaration(&dec, DEF_STRUCT, num_args); decls = XALLOC(decl_list); decls->decl = dec; *tailp = decls; if (streq(dec.type, "void")) isvoid = TRUE; tailp = &decls->next; } /* multiple arguments are only allowed in newstyle */ if (!newstyle && num_args > 1) error("only one argument is allowed"); if (isvoid && num_args > 1) error("illegal use of void in program definition"); *tailp = NULL; scan(TOK_RPAREN, &tok); scan(TOK_EQUAL, &tok); scan_num(&tok); scan(TOK_SEMICOLON, &tok); plist->proc_num = tok.str; plist->arg_num = num_args; *ptailp = plist; ptailp = &plist->next; peek(&tok); } while (tok.kind != TOK_RBRACE); *ptailp = NULL; *vtailp = vlist; vtailp = &vlist->next; scan(TOK_RBRACE, &tok); scan(TOK_EQUAL, &tok); scan_num(&tok); vlist->vers_num = tok.str; /* make the argument structure name for each arg */ for (plist = vlist->procs; plist != NULL; plist = plist->next) { plist->args.argname = make_argname(plist->proc_name, vlist->vers_num); /* free the memory ?? */ } scan(TOK_SEMICOLON, &tok); scan2(TOK_VERSION, TOK_RBRACE, &tok); } while (tok.kind == TOK_VERSION); scan(TOK_EQUAL, &tok); scan_num(&tok); defp->def.pr.prog_num = tok.str; *vtailp = NULL; } static void def_enum(definition *defp) { token tok; enumval_list *elist; enumval_list **tailp; defp->def_kind = DEF_ENUM; scan(TOK_IDENT, &tok); defp->def_name = tok.str; scan(TOK_LBRACE, &tok); tailp = &defp->def.en.vals; do { scan(TOK_IDENT, &tok); elist = XALLOC(enumval_list); elist->name = tok.str; elist->assignment = NULL; scan3(TOK_COMMA, TOK_RBRACE, TOK_EQUAL, &tok); if (tok.kind == TOK_EQUAL) { scan_num(&tok); elist->assignment = tok.str; scan2(TOK_COMMA, TOK_RBRACE, &tok); } *tailp = elist; tailp = &elist->next; } while (tok.kind != TOK_RBRACE); *tailp = NULL; } static void def_const(definition *defp) { token tok; defp->def_kind = DEF_CONST; scan(TOK_IDENT, &tok); defp->def_name = tok.str; scan(TOK_EQUAL, &tok); scan2(TOK_IDENT, TOK_STRCONST, &tok); defp->def.co = tok.str; } static void def_union(definition *defp) { token tok; declaration dec; case_list *cases; case_list **tailp; int flag; defp->def_kind = DEF_UNION; scan(TOK_IDENT, &tok); defp->def_name = tok.str; scan(TOK_SWITCH, &tok); scan(TOK_LPAREN, &tok); get_declaration(&dec, DEF_UNION); defp->def.un.enum_decl = dec; tailp = &defp->def.un.cases; scan(TOK_RPAREN, &tok); scan(TOK_LBRACE, &tok); scan(TOK_CASE, &tok); while (tok.kind == TOK_CASE) { scan2(TOK_IDENT, TOK_CHARCONST, &tok); cases = XALLOC(case_list); cases->case_name = tok.str; scan(TOK_COLON, &tok); /* now peek at next token */ flag = 0; if (peekscan(TOK_CASE, &tok)){ do { scan2(TOK_IDENT, TOK_CHARCONST, &tok); cases->contflag = 1; /* continued case statement */ *tailp = cases; tailp = &cases->next; cases = XALLOC(case_list); cases->case_name = tok.str; scan(TOK_COLON, &tok); } while (peekscan(TOK_CASE, &tok)); } else if (flag) { *tailp = cases; tailp = &cases->next; cases = XALLOC(case_list); } get_declaration(&dec, DEF_UNION); cases->case_decl = dec; cases->contflag = 0; /* no continued case statement */ *tailp = cases; tailp = &cases->next; scan(TOK_SEMICOLON, &tok); scan3(TOK_CASE, TOK_DEFAULT, TOK_RBRACE, &tok); } *tailp = NULL; if (tok.kind == TOK_DEFAULT) { scan(TOK_COLON, &tok); get_declaration(&dec, DEF_UNION); defp->def.un.default_decl = XALLOC(declaration); *defp->def.un.default_decl = dec; scan(TOK_SEMICOLON, &tok); scan(TOK_RBRACE, &tok); } else { defp->def.un.default_decl = NULL; } } static const char *reserved_words[] = { "array", "bytes", "destroy", "free", "getpos", "inline", "pointer", "reference", "setpos", "sizeof", "union", "vector", NULL }; static const char *reserved_types[] = { "opaque", "string", NULL }; /* * check that the given name is not one that would eventually result in * xdr routines that would conflict with internal XDR routines. */ static void check_type_name(const char *name, int new_type) { int i; char tmp[100]; for (i = 0; reserved_words[i] != NULL; i++) { if (strcmp(name, reserved_words[i]) == 0) { sprintf(tmp, "illegal (reserved) name :\'%s\' in type definition", name); error(tmp); } } if (new_type) { for (i = 0; reserved_types[i] != NULL; i++) { if (strcmp(name, reserved_types[i]) == 0) { sprintf(tmp, "illegal (reserved) name :\'%s\' in type definition", name); error(tmp); } } } } static void def_typedef(definition *defp) { declaration dec; defp->def_kind = DEF_TYPEDEF; get_declaration(&dec, DEF_TYPEDEF); defp->def_name = dec.name; check_type_name(dec.name, 1); defp->def.ty.old_prefix = dec.prefix; defp->def.ty.old_type = dec.type; defp->def.ty.rel = dec.rel; defp->def.ty.array_max = dec.array_max; } static void get_declaration(declaration *dec, defkind dkind) { token tok; get_type(&dec->prefix, &dec->type, dkind); dec->rel = REL_ALIAS; if (streq(dec->type, "void")) return; check_type_name(dec->type, 0); scan2(TOK_STAR, TOK_IDENT, &tok); if (tok.kind == TOK_STAR) { dec->rel = REL_POINTER; scan(TOK_IDENT, &tok); } dec->name = tok.str; if (peekscan(TOK_LBRACKET, &tok)) { if (dec->rel == REL_POINTER) error("no array-of-pointer declarations -- use typedef"); dec->rel = REL_VECTOR; scan_num(&tok); dec->array_max = tok.str; scan(TOK_RBRACKET, &tok); } else if (peekscan(TOK_LANGLE, &tok)) { if (dec->rel == REL_POINTER) error("no array-of-pointer declarations -- use typedef"); dec->rel = REL_ARRAY; if (peekscan(TOK_RANGLE, &tok)) { dec->array_max = "~0"; /* unspecified size, use max */ } else { scan_num(&tok); dec->array_max = tok.str; scan(TOK_RANGLE, &tok); } } if (streq(dec->type, "opaque")) { if (dec->rel != REL_ARRAY && dec->rel != REL_VECTOR) { error("array declaration expected"); } } else if (streq(dec->type, "string")) { if (dec->rel != REL_ARRAY) { error("variable-length array declaration expected"); } } } static void get_prog_declaration(declaration *dec, defkind dkind, int num) { token tok; char name[10]; /* argument name */ if (dkind == DEF_PROGRAM) { peek(&tok); if (tok.kind == TOK_RPAREN) { /* no arguments */ dec->rel = REL_ALIAS; dec->type = "void"; dec->prefix = NULL; dec->name = NULL; return; } } get_type(&dec->prefix, &dec->type, dkind); dec->rel = REL_ALIAS; if (peekscan(TOK_IDENT, &tok)) /* optional name of argument */ strcpy(name, tok.str); else sprintf(name, "%s%d", ARGNAME, num); /* default name of argument */ dec->name = (char *) xstrdup(name); if (streq(dec->type, "void")) { return; } if (streq(dec->type, "opaque")) error("opaque -- illegal argument type"); if (peekscan(TOK_STAR, &tok)) { if (streq(dec->type, "string")) error("pointer to string not allowed in program arguments"); dec->rel = REL_POINTER; if (peekscan(TOK_IDENT, &tok)) { /* optional name of argument */ dec->name = xstrdup(tok.str); } } if (peekscan(TOK_LANGLE, &tok)) { if (!streq(dec->type, "string")) error("arrays cannot be declared as arguments to procedures -- use typedef"); dec->rel = REL_ARRAY; if (peekscan(TOK_RANGLE, &tok)) { dec->array_max = "~0"; /* unspecified size, use max */ } else { scan_num(&tok); dec->array_max = tok.str; scan(TOK_RANGLE, &tok); } } if (streq(dec->type, "string")) { if (dec->rel != REL_ARRAY) { /* * .x specifies just string as * type of argument * - make it string<> */ dec->rel = REL_ARRAY; dec->array_max = "~0"; /* unspecified size, use max */ } } } static void get_type(const char **prefixp, const char **typep, defkind dkind) { token tok; *prefixp = NULL; get_token(&tok); switch (tok.kind) { case TOK_IDENT: *typep = tok.str; break; case TOK_STRUCT: case TOK_ENUM: case TOK_UNION: *prefixp = tok.str; scan(TOK_IDENT, &tok); *typep = tok.str; break; case TOK_UNSIGNED: unsigned_dec(typep); break; case TOK_SHORT: *typep = "short"; peekscan(TOK_INT, &tok); break; case TOK_LONG: *typep = "long"; peekscan(TOK_INT, &tok); break; case TOK_HYPER: *typep = "int64_t"; peekscan(TOK_INT, &tok); break; case TOK_VOID: if (dkind != DEF_UNION && dkind != DEF_PROGRAM) error("voids allowed only inside union and program definitions with one argument"); *typep = tok.str; break; case TOK_STRING: case TOK_OPAQUE: case TOK_CHAR: case TOK_INT: case TOK_FLOAT: case TOK_DOUBLE: case TOK_BOOL: case TOK_QUAD: *typep = tok.str; break; default: error("expected type specifier"); } } static void unsigned_dec(const char **typep) { token tok; peek(&tok); switch (tok.kind) { case TOK_CHAR: get_token(&tok); *typep = "u_char"; break; case TOK_SHORT: get_token(&tok); *typep = "u_short"; peekscan(TOK_INT, &tok); break; case TOK_LONG: get_token(&tok); *typep = "u_long"; peekscan(TOK_INT, &tok); break; case TOK_HYPER: get_token(&tok); *typep = "u_int64_t"; peekscan(TOK_INT, &tok); break; case TOK_INT: get_token(&tok); *typep = "u_int"; break; default: *typep = "u_int"; break; } } [FILE:2308:files/rpc_parse.h] enum defkind { DEF_CONST, DEF_STRUCT, DEF_UNION, DEF_ENUM, DEF_TYPEDEF, DEF_PROGRAM }; typedef enum defkind defkind; typedef const char *const_def; enum relation { REL_VECTOR, /* fixed length array */ REL_ARRAY, /* variable length array */ REL_POINTER, /* pointer */ REL_ALIAS, /* simple */ }; typedef enum relation relation; struct typedef_def { const char *old_prefix; const char *old_type; relation rel; const char *array_max; }; typedef struct typedef_def typedef_def; struct enumval_list { const char *name; const char *assignment; struct enumval_list *next; }; typedef struct enumval_list enumval_list; struct enum_def { enumval_list *vals; }; typedef struct enum_def enum_def; struct declaration { const char *prefix; const char *type; const char *name; relation rel; const char *array_max; }; typedef struct declaration declaration; struct decl_list { declaration decl; struct decl_list *next; }; typedef struct decl_list decl_list; struct struct_def { decl_list *decls; }; typedef struct struct_def struct_def; struct case_list { const char *case_name; int contflag; declaration case_decl; struct case_list *next; }; typedef struct case_list case_list; struct union_def { declaration enum_decl; case_list *cases; declaration *default_decl; }; typedef struct union_def union_def; struct arg_list { char *argname; /* name of struct for arg*/ decl_list *decls; }; typedef struct arg_list arg_list; struct proc_list { const char *proc_name; const char *proc_num; arg_list args; int arg_num; const char *res_type; const char *res_prefix; struct proc_list *next; }; typedef struct proc_list proc_list; struct version_list { const char *vers_name; const char *vers_num; proc_list *procs; struct version_list *next; }; typedef struct version_list version_list; struct program_def { const char *prog_num; version_list *versions; }; typedef struct program_def program_def; struct definition { const char *def_name; defkind def_kind; union { const_def co; struct_def st; union_def un; enum_def en; typedef_def ty; program_def pr; } def; }; typedef struct definition definition; definition *get_definition(void); struct bas_type { const char *name; int length; struct bas_type *next; }; typedef struct bas_type bas_type; [FILE:6481:files/rpc_sample.c] #include #include #include "rpc_parse.h" #include "rpc_scan.h" #include "rpc_util.h" static char RQSTP[] = "rqstp"; static void write_sample_client(const char *, version_list *); static void write_sample_server(definition *); static void return_type(proc_list *); void write_sample_svc(definition *def) { if (def->def_kind != DEF_PROGRAM) return; write_sample_server(def); } int write_sample_clnt(definition *def) { version_list *vp; int count = 0; if (def->def_kind != DEF_PROGRAM) return(0); /* generate sample code for each version */ for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) { write_sample_client(def->def_name, vp); ++count; } return(count); } static void write_sample_client(const char *program_name, version_list *vp) { proc_list *proc; int i; decl_list *l; f_print(fout, "\n\nvoid\n"); pvname(program_name, vp->vers_num); f_print(fout, "(char *host)\n{\n"); f_print(fout, "\tCLIENT *clnt;\n"); i = 0; for (proc = vp->procs; proc != NULL; proc = proc->next) { f_print(fout, "\t"); if (mtflag) { f_print(fout, "enum clnt_stat retval_%d;\n\t", ++i); ptype(proc->res_prefix, proc->res_type, 1); f_print(fout, "result_%d;\n", i); } else { ptype(proc->res_prefix, proc->res_type, 1); f_print(fout, " *result_%d;\n",++i); } /* print out declarations for arguments */ if(proc->arg_num < 2 && !newstyle) { f_print(fout, "\t"); if(!streq(proc->args.decls->decl.type, "void")) ptype(proc->args.decls->decl.prefix, proc->args.decls->decl.type, 1); else f_print(fout, "char * "); /* cannot have "void" type */ f_print(fout, " "); pvname(proc->proc_name, vp->vers_num); f_print(fout, "_arg;\n"); } else if (!streq(proc->args.decls->decl.type, "void")) { for (l = proc->args.decls; l != NULL; l = l->next) { f_print(fout, "\t"); ptype(l->decl.prefix, l->decl.type, 1); if (strcmp(l->decl.type,"string") == 1) f_print(fout, " "); pvname(proc->proc_name, vp->vers_num); f_print(fout, "_%s;\n", l->decl.name); } } } /* generate creation of client handle */ f_print(fout, "\n#ifndef\tDEBUG\n"); f_print(fout, "\tclnt = clnt_create(host, %s, %s, \"%s\");\n", program_name, vp->vers_name, tirpcflag? "netpath" : "udp"); f_print(fout, "\tif (clnt == NULL) {\n"); f_print(fout, "\t\tclnt_pcreateerror(host);\n"); f_print(fout, "\t\texit(1);\n\t}\n"); f_print(fout, "#endif\t/* !DEBUG */\n\n"); /* generate calls to procedures */ i = 0; for (proc = vp->procs; proc != NULL; proc = proc->next) { if (mtflag) f_print(fout, "\tretval_%d = ",++i); else f_print(fout, "\tresult_%d = ",++i); pvname(proc->proc_name, vp->vers_num); if (proc->arg_num < 2 && !newstyle) { f_print(fout, "("); if(streq(proc->args.decls->decl.type, "void")) { /* cast to void * */ f_print(fout, "(void *)"); } f_print(fout, "&"); pvname(proc->proc_name, vp->vers_num); if (mtflag) f_print(fout, "_arg, &result_%d, clnt);\n", i); else f_print(fout, "_arg, clnt);\n"); } else if (streq(proc->args.decls->decl.type, "void")) { if (mtflag) f_print(fout, "(&result_%d, clnt);\n", i); else f_print(fout, "(clnt);\n"); } else { f_print(fout, "("); for (l = proc->args.decls; l != NULL; l = l->next) { pvname(proc->proc_name, vp->vers_num); f_print(fout, "_%s, ", l->decl.name); } if (mtflag) f_print(fout, "&result_%d, ", i); f_print(fout, "clnt);\n"); } if (mtflag) f_print(fout, "\tif (retval_%d != RPC_SUCCESS) {\n", i); else f_print(fout, "\tif (result_%d == NULL) {\n", i); f_print(fout, "\t\tclnt_perror(clnt, \"call failed\");\n"); f_print(fout, "\t}\n"); } f_print(fout, "#ifndef\tDEBUG\n"); f_print(fout, "\tclnt_destroy(clnt);\n"); f_print(fout, "#endif\t /* !DEBUG */\n"); f_print(fout, "}\n"); } static void write_sample_server(definition *def) { version_list *vp; proc_list *proc; for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) { for (proc = vp->procs; proc != NULL; proc = proc->next) { f_print(fout, "\n"); if (!mtflag) { return_type(proc); f_print(fout, "*\n"); } else f_print(fout, "bool_t\n"); pvname_svc(proc->proc_name, vp->vers_num); printarglist(proc, "result", RQSTP, "struct svc_req *"); f_print(fout, "{\n"); if (!mtflag) { f_print(fout, "\tstatic "); if(!streq(proc->res_type, "void")) return_type(proc); else f_print(fout, "char *"); /* cannot have void type */ f_print(fout, " result;\n"); } else { f_print(fout, "\tbool_t retval;\n"); } f_print(fout, "\n\t/*\n\t * insert server code here\n\t */\n\n"); if (!mtflag) { if(!streq(proc->res_type, "void")) f_print(fout, "\treturn (&result);\n}\n"); else /* cast back to void * */ f_print(fout, "\treturn((void *) &result);\n}\n"); } else { f_print(fout, "\treturn (retval);\n}\n"); } } /* put in sample freeing routine */ if (mtflag) { f_print(fout, "\nint\n"); pvname(def->def_name, vp->vers_num); f_print(fout,"_freeresult(SVCXPRT *transp, xdrproc_t xdr_result, caddr_t result)\n"); f_print(fout, "{\n"); f_print(fout, "\txdr_free(xdr_result, result);\n"); f_print(fout, "\n\t/*\n\t * Insert additional freeing code here, if needed\n\t */\n"); f_print(fout, "\n}\n"); } } } static void return_type(proc_list *plist) { ptype(plist->res_prefix, plist->res_type, 1); } void add_sample_msg(void) { f_print(fout, "/*\n"); f_print(fout, " * This is sample code generated by rpcgen.\n"); f_print(fout, " * These are only templates and you can use them\n"); f_print(fout, " * as a guideline for developing your own functions.\n"); f_print(fout, " */\n\n"); } void write_sample_clnt_main(void) { list *l; definition *def; version_list *vp; f_print(fout, "\n\n"); f_print(fout, "main(int argc, char *argv[])\n{\n"); f_print(fout, "\tchar *host;"); f_print(fout, "\n\n\tif (argc < 2) {"); f_print(fout, "\n\t\tprintf(\"usage: %%s server_host\\n\", argv[0]);\n"); f_print(fout, "\t\texit(1);\n\t}"); f_print(fout, "\n\thost = argv[1];\n"); for (l = defined; l != NULL; l = l->next) { def = l->val; if (def->def_kind != DEF_PROGRAM) continue; for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) { f_print(fout, "\t"); pvname(def->def_name, vp->vers_num); f_print(fout, "(host);\n"); } } f_print(fout, "}\n"); } [FILE:7816:files/rpc_scan.c] /* * rpc_scan.c, Scanner for the RPC protocol compiler */ #include #include #include #include #include #include "rpc_parse.h" #include "rpc_scan.h" #include "rpc_util.h" #define startcomment(where) (where[0] == '/' && where[1] == '*') #define endcomment(where) (where[-1] == '*' && where[0] == '/') static int pushed = 0; /* is a token pushed */ static token lasttok; /* last token, if pushed */ static void unget_token(token *); static void findstrconst(char **, const char **); static void findchrconst(char **, const char **); static void findconst(char **, const char **); static void findkind(char **, token *); static int cppline(char *); static int directive(char *); static void printdirective(char *); static void docppline(char *, int *, const char **); /* * scan expecting 1 given token */ void scan(tok_kind expect, token *tokp) { get_token(tokp); if (tokp->kind != expect) expected1(expect); } /* * scan expecting any of the 2 given tokens */ void scan2(tok_kind expect1, tok_kind expect2, token *tokp) { get_token(tokp); if (tokp->kind != expect1 && tokp->kind != expect2) expected2(expect1, expect2); } /* * scan expecting any of the 3 given token */ void scan3(tok_kind expect1, tok_kind expect2, tok_kind expect3, token *tokp) { get_token(tokp); if (tokp->kind != expect1 && tokp->kind != expect2 && tokp->kind != expect3) expected3(expect1, expect2, expect3); } /* * scan expecting a constant, possibly symbolic */ void scan_num(token *tokp) { get_token(tokp); switch (tokp->kind) { case TOK_IDENT: break; default: error("constant or identifier expected"); } } /* * Peek at the next token */ void peek(token *tokp) { get_token(tokp); unget_token(tokp); } /* * Peek at the next token and scan it if it matches what you expect */ int peekscan(tok_kind expect, token *tokp) { peek(tokp); if (tokp->kind == expect) { get_token(tokp); return(1); } return(0); } /* * Get the next token, printing out any directive that are encountered. */ void get_token(token *tokp) { int commenting; int stat = 0; if (pushed) { pushed = 0; *tokp = lasttok; return; } commenting = 0; for (;;) { if (*where == 0) { for (;;) { if (!fgets(curline, MAXLINESIZE, fin)) { tokp->kind = TOK_EOF; /* * now check if cpp returned * non NULL value */ waitpid(childpid, &stat, WUNTRACED); if (stat > 0) { /* * Set return value from rpcgen */ nonfatalerrors = stat >> 8; } *where = 0; return; } linenum++; if (commenting) break; else if (cppline(curline)) docppline(curline, &linenum, &infilename); else if (directive(curline)) printdirective(curline); else break; } where = curline; } else if (isspace(*where)) { while (isspace(*where)) where++; /* eat */ } else if (commenting) { for (where++; *where; where++) { if (endcomment(where)) { where++; commenting--; break; } } } else if (startcomment(where)) { where += 2; commenting++; } else { break; } } /* * 'where' is not whitespace, comment or directive Must be a token! */ switch (*where) { case ':': tokp->kind = TOK_COLON; where++; break; case ';': tokp->kind = TOK_SEMICOLON; where++; break; case ',': tokp->kind = TOK_COMMA; where++; break; case '=': tokp->kind = TOK_EQUAL; where++; break; case '*': tokp->kind = TOK_STAR; where++; break; case '[': tokp->kind = TOK_LBRACKET; where++; break; case ']': tokp->kind = TOK_RBRACKET; where++; break; case '{': tokp->kind = TOK_LBRACE; where++; break; case '}': tokp->kind = TOK_RBRACE; where++; break; case '(': tokp->kind = TOK_LPAREN; where++; break; case ')': tokp->kind = TOK_RPAREN; where++; break; case '<': tokp->kind = TOK_LANGLE; where++; break; case '>': tokp->kind = TOK_RANGLE; where++; break; case '"': tokp->kind = TOK_STRCONST; findstrconst(&where, &tokp->str); break; case '\'': tokp->kind = TOK_CHARCONST; findchrconst(&where, &tokp->str); break; case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': tokp->kind = TOK_IDENT; findconst(&where, &tokp->str); break; default: if (!(isalpha(*where) || *where == '_')) { char buf[100]; char *p; s_print(buf, "illegal character in file: "); p = buf + strlen(buf); if (isprint(*where)) { s_print(p, "%c", *where); } else { s_print(p, "%d", *where); } error(buf); } findkind(&where, tokp); break; } } static void unget_token(token *tokp) { lasttok = *tokp; pushed = 1; } static void findstrconst(char **str, const char **val) { char *p; char *tmp; int size; p = *str; do { p++; } while (*p && *p != '"'); if (*p == 0) error("unterminated string constant"); p++; size = p - *str; tmp = xmalloc(size + 1); strncpy(tmp, *str, size); tmp[size] = 0; *val = tmp; *str = p; } static void findchrconst(char **str, const char **val) { char *p; char *tmp; int size; p = *str; do { p++; } while (*p && *p != '\''); if (*p == 0) error("unterminated string constant"); p++; size = p - *str; if (size != 3) error("empty char string"); tmp = xmalloc(size + 1); strncpy(tmp, *str, size); tmp[size] = 0; *val = tmp; *str = p; } static void findconst(char **str, const char **val) { char *p; char *tmp; int size; p = *str; if (*p == '0' && *(p + 1) == 'x') { p++; do { p++; } while (isxdigit(*p)); } else { do { p++; } while (isdigit(*p)); } size = p - *str; tmp = xmalloc(size + 1); strncpy(tmp, *str, size); tmp[size] = 0; *val = tmp; *str = p; } static token symbols[] = { {TOK_CONST, "const"}, {TOK_UNION, "union"}, {TOK_SWITCH, "switch"}, {TOK_CASE, "case"}, {TOK_DEFAULT, "default"}, {TOK_STRUCT, "struct"}, {TOK_TYPEDEF, "typedef"}, {TOK_ENUM, "enum"}, {TOK_OPAQUE, "opaque"}, {TOK_BOOL, "bool"}, {TOK_VOID, "void"}, {TOK_CHAR, "char"}, {TOK_INT, "int"}, {TOK_UNSIGNED, "unsigned"}, {TOK_SHORT, "short"}, {TOK_LONG, "long"}, {TOK_HYPER, "hyper"}, {TOK_FLOAT, "float"}, {TOK_DOUBLE, "double"}, {TOK_QUAD, "quadruple"}, {TOK_STRING, "string"}, {TOK_PROGRAM, "program"}, {TOK_VERSION, "version"}, {TOK_EOF, "??????"}, }; static void findkind(char **mark, token *tokp) { int len; token *s; char *str, *tmp; str = *mark; for (s = symbols; s->kind != TOK_EOF; s++) { len = strlen(s->str); if (strncmp(str, s->str, len) == 0) { if (!isalnum(str[len]) && str[len] != '_') { tokp->kind = s->kind; tokp->str = s->str; *mark = str + len; return; } } } tokp->kind = TOK_IDENT; for (len = 0; isalnum(str[len]) || str[len] == '_'; len++); tmp = xmalloc(len + 1); strncpy(tmp, str, len); tmp[len] = 0; tokp->str = tmp; *mark = str + len; } static int cppline(char *line) { return(line == curline && *line == '#'); } static int directive(char *line) { return(line == curline && *line == '%'); } static void printdirective(char *line) { f_print(fout, "%s", line + 1); } static void docppline(char *line, int *lineno, const char **fname) { char *file; int num; char *p; line++; while (isspace(*line)) line++; num = atoi(line); while (isdigit(*line)) line++; while (isspace(*line)) line++; if (*line != '"') error("preprocessor error"); line++; p = file = xmalloc(strlen(line) + 1); while (*line && *line != '"') *p++ = *line++; if (*line == 0) error("preprocessor error"); *p = 0; if (*file == 0) *fname = NULL; else *fname = file; *lineno = num - 1; } [FILE:1006:files/rpc_scan.h] #ifndef _RPC_SCAN_H_ #define _RPC_SCAN_H_ /* * kinds of tokens */ enum tok_kind { TOK_IDENT, TOK_CHARCONST, TOK_STRCONST, TOK_LPAREN, TOK_RPAREN, TOK_LBRACE, TOK_RBRACE, TOK_LBRACKET, TOK_RBRACKET, TOK_LANGLE, TOK_RANGLE, TOK_STAR, TOK_COMMA, TOK_EQUAL, TOK_COLON, TOK_SEMICOLON, TOK_CONST, TOK_STRUCT, TOK_UNION, TOK_SWITCH, TOK_CASE, TOK_DEFAULT, TOK_ENUM, TOK_TYPEDEF, TOK_INT, TOK_SHORT, TOK_LONG, TOK_HYPER, TOK_UNSIGNED, TOK_FLOAT, TOK_DOUBLE, TOK_QUAD, TOK_OPAQUE, TOK_CHAR, TOK_STRING, TOK_BOOL, TOK_VOID, TOK_PROGRAM, TOK_VERSION, TOK_EOF }; typedef enum tok_kind tok_kind; /* * a token */ struct token { tok_kind kind; const char *str; }; typedef struct token token; /* * routine interface */ void scan(tok_kind, token *); void scan2(tok_kind, tok_kind, token *); void scan3(tok_kind, tok_kind, tok_kind, token *); void scan_num(token *); void peek(token *); int peekscan(tok_kind, token *); void get_token(token *); #endif /* _RPC_SCAN_H_ */ [FILE:26114:files/rpc_svcout.c] #include #include #include "rpc_parse.h" #include "rpc_scan.h" #include "rpc_util.h" static char RQSTP[] = "rqstp"; static char TRANSP[] = "transp"; static char ARG[] = "argument"; static char RESULT[] = "result"; static char ROUTINE[] = "local"; static char RETVAL[] = "retval"; char _errbuf[256]; /* For all messages */ void internal_proctype(proc_list *); static void write_real_program(definition *); static void write_program(definition *, const char *); static void printerr(const char *, const char *); static void printif(const char *, const char *, const char *, const char *); static void write_inetmost(const char *); static void print_return(const char *); static void print_pmapunset(const char *); static void print_err_message(const char *); static void write_timeout_func(void); static void write_pm_most(const char *, int); static void write_rpc_svc_fg(const char *, const char *); static void open_log_file(const char *, const char *); static void write_msg_out(void); static void p_xdrfunc(const char *rname, const char *typename) { f_print(fout, "\t\txdr_%s = (xdrproc_t) xdr_%s;\n", rname, stringfix(typename)); } void internal_proctype(proc_list *plist) { f_print(fout, "static "); ptype(plist->res_prefix, plist->res_type, 1); f_print(fout, "*"); } /* * write most of the service, that is, everything but the registrations. */ void write_most(const char *infile, int netflag, int nomain) { if (inetdflag || pmflag) { const char *var_type; var_type = (nomain? "extern" : "static"); f_print(fout, "%s int _rpcpmstart;", var_type); f_print(fout, "\t\t/* Started by a port monitor ? */\n"); if (!tirpcflag || tirpc_socket) { f_print(fout, "%s int _rpcfdtype;", var_type); f_print(fout, "\n\t\t /* Whether Stream or " "Datagram ? */\n"); } if (timerflag) { f_print(fout, " /* States a server can be in " "wrt request */\n\n"); f_print(fout, "#define\t_IDLE 0\n"); f_print(fout, "#define\t_SERVED 1\n"); f_print(fout, "#define\t_SERVING 2\n\n"); f_print(fout, "static int _rpcsvcstate = _IDLE;"); f_print(fout, "\t /* Set when a request is " "serviced */\n"); if (mtflag) { f_print(fout, "pthread_mutex_t _svcstate_lock;"); f_print(fout, "\t\t\t/* Mutex lock for " "variable _rpcsvcstate */\n"); } } write_svc_aux(nomain); } /* write out dispatcher and stubs */ write_programs(NULL); if (nomain) return; f_print(fout, "\nint\n"); f_print(fout, "main()\n"); f_print(fout, "{\n"); if (inetdflag) { write_inetmost(infile); /* Includes call to write_rpc_svc_fg() */ } else { if (tirpcflag) { if (netflag) { f_print(fout, "\tregister SVCXPRT *%s;\n", TRANSP); f_print(fout, "\tstruct netconfig *nconf = NULL;\n"); } f_print(fout, "\tpid_t pid;\n"); f_print(fout, "\tint i;\n"); if (pmflag) { if (tirpc_socket) { f_print(fout, "\tstruct sockaddr_storage saddr;\n"); f_print(fout, "\tsocklen_t asize = sizeof (saddr);\n\n"); } else f_print(fout, "\tchar mname[FMNAMESZ + 1];\n\n"); } if (mtflag & timerflag) f_print(fout, "\tmutex_init(&_svcstate_lock, " "USYNC_THREAD, NULL);\n"); if (pmflag) { write_pm_most(infile, netflag); f_print(fout, "\telse {\n"); write_rpc_svc_fg(infile, "\t\t"); f_print(fout, "\t}\n"); } else write_rpc_svc_fg(infile, "\t\t"); } else { f_print(fout, "\tregister SVCXPRT *%s;\n", TRANSP); f_print(fout, "\n"); print_pmapunset("\t"); } } if (logflag && !inetdflag) open_log_file(infile, "\t"); } /* * write a registration for the given transport */ void write_netid_register(const char *transp) { list *l; definition *def; version_list *vp; const char *sp; char tmpbuf[32]; sp = ""; f_print(fout, "\n"); f_print(fout, "%s\tnconf = getnetconfigent(\"%s\");\n", sp, transp); f_print(fout, "%s\tif (nconf == NULL) {\n", sp); sprintf(_errbuf, "cannot find %s netid.", transp); sprintf(tmpbuf, "%s\t\t", sp); print_err_message(tmpbuf); f_print(fout, "%s\t\texit(1);\n", sp); f_print(fout, "%s\t}\n", sp); if (tirpcflag) { f_print(fout, "%s\t%s = svc_tli_create(RPC_ANYFD, ", sp, TRANSP); f_print(fout,"nconf, 0, RPC_MAXDATASIZE, RPC_MAXDATASIZE);\n"); } else { f_print(fout, "%s\t%s = svc_tli_create(RPC_ANYFD, nconf, 0, 0, 0);\n", sp, TRANSP); } f_print(fout, "%s\tif (%s == NULL) {\n", sp, TRANSP); sprintf(_errbuf, "cannot create %s service.", transp); print_err_message(tmpbuf); f_print(fout, "%s\t\texit(1);\n", sp); f_print(fout, "%s\t}\n", sp); for (l = defined; l != NULL; l = l->next) { def = (definition *) l->val; if (def->def_kind != DEF_PROGRAM) continue; for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) { f_print(fout, "%s\trpcb_unset(%s, %s, nconf);\n", sp, def->def_name, vp->vers_name); f_print(fout, "%s\tif (!svc_reg(%s, %s, %s, ", sp, TRANSP, def->def_name, vp->vers_name); pvname(def->def_name, vp->vers_num); f_print(fout, ", nconf)) {\n"); sprintf(_errbuf, "unable to register (%s, %s, %s).", def->def_name, vp->vers_name, transp); print_err_message(tmpbuf); f_print(fout, "%s\t\texit(1);\n", sp); f_print(fout, "%s\t}\n", sp); } } f_print(fout, "%s\tfreenetconfigent(nconf);\n", sp); } /* * write a registration for the given transport for TLI */ void write_nettype_register(const char *transp) { list *l; definition *def; version_list *vp; for (l = defined; l != NULL; l = l->next) { def = (definition *) l->val; if (def->def_kind != DEF_PROGRAM) continue; for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) { f_print(fout, "\tif (!svc_create("); pvname(def->def_name, vp->vers_num); f_print(fout, ", %s, %s, \"%s\")) {\n", def->def_name, vp->vers_name, transp); sprintf(_errbuf, "unable to create (%s, %s) for %s.", def->def_name, vp->vers_name, transp); print_err_message("\t\t"); f_print(fout, "\t\texit(1);\n"); f_print(fout, "\t}\n"); } } } /* * write the rest of the service */ void write_rest(void) { f_print(fout, "\n"); if (inetdflag) { f_print(fout, "\tif (%s == NULL) {\n", TRANSP); sprintf(_errbuf, "could not create a handle"); print_err_message("\t\t"); f_print(fout, "\t\texit(1);\n"); f_print(fout, "\t}\n"); if (timerflag) { f_print(fout, "\tif (_rpcpmstart) {\n"); f_print(fout, "\t\tsignal(SIGALRM, closedown);\n"); f_print(fout, "\t\talarm(_RPCSVC_CLOSEDOWN/2);\n"); f_print(fout, "\t}\n"); } } f_print(fout, "\tsvc_run();\n"); sprintf(_errbuf, "svc_run returned"); print_err_message("\t"); f_print(fout, "\texit(1);\n"); f_print(fout, "\t/* NOTREACHED */\n"); f_print(fout, "}\n"); } void write_programs(const char *storage) { list *l; definition *def; /* write out stubs for procedure definitions */ for (l = defined; l != NULL; l = l->next) { def = (definition *) l->val; if (def->def_kind == DEF_PROGRAM) write_real_program(def); } /* write out dispatcher for each program */ for (l = defined; l != NULL; l = l->next) { def = (definition *) l->val; if (def->def_kind == DEF_PROGRAM) write_program(def, storage); } } /* * write out definition of internal function (e.g. _printmsg_1(...)) * which calls server's defintion of actual function (e.g. printmsg_1(...)). * Unpacks single user argument of printmsg_1 to call-by-value format * expected by printmsg_1. */ static void write_real_program(definition *def) { version_list *vp; proc_list *proc; decl_list *l; if (!newstyle) return; /* not needed for old style */ for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) { for (proc = vp->procs; proc != NULL; proc = proc->next) { f_print(fout, "\n"); if (!mtflag) internal_proctype(proc); else f_print(fout, "int"); f_print(fout, "\n_"); pvname(proc->proc_name, vp->vers_num); f_print(fout, "("); /* arg name */ if (proc->arg_num > 1) f_print(fout, "%s", proc->args.argname); else ptype(proc->args.decls->decl.prefix, proc->args.decls->decl.type, 0); if (mtflag) { f_print(fout, " *argp, void *%s, struct svc_req *%s)\n", RESULT, RQSTP); } else f_print(fout, " *argp, struct svc_req *%s)\n", RQSTP); f_print(fout, "{\n"); f_print(fout, "\treturn ("); pvname_svc(proc->proc_name, vp->vers_num); f_print(fout, "("); if (proc->arg_num < 2) { /* single argument */ if (!streq(proc->args.decls->decl.type, "void")) f_print(fout, "*argp, "); /* non-void */ } else { for (l = proc->args.decls; l != NULL; l = l->next) f_print(fout, "argp->%s, ", l->decl.name); } if (mtflag) f_print(fout, "%s, ",RESULT); f_print(fout, "%s));\n}\n", RQSTP); } } } static void write_program(definition *def, const char *storage) { version_list *vp; proc_list *proc; int filled; for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) { f_print(fout, "\n"); if (storage != NULL) f_print(fout, "%s ", storage); f_print(fout, "void\n"); pvname(def->def_name, vp->vers_num); f_print(fout, "(struct svc_req *%s, ", RQSTP); f_print(fout, "SVCXPRT *%s)\n", TRANSP); f_print(fout, "{\n"); filled = 0; f_print(fout, "\tunion {\n"); for (proc = vp->procs; proc != NULL; proc = proc->next) { if (proc->arg_num < 2) { /* single argument */ if (streq(proc->args.decls->decl.type, "void")) continue; filled = 1; f_print(fout, "\t\t"); ptype(proc->args.decls->decl.prefix, proc->args.decls->decl.type, 0); pvname(proc->proc_name, vp->vers_num); f_print(fout, "_arg;\n"); } else { filled = 1; f_print(fout, "\t\t%s", proc->args.argname); f_print(fout, " "); pvname(proc->proc_name, vp->vers_num); f_print(fout, "_arg;\n"); } } if (!filled) f_print(fout, "\t\tint fill;\n"); f_print(fout, "\t} %s;\n", ARG); if (mtflag) { f_print(fout, "\tunion {\n"); for (proc = vp->procs; proc != NULL; proc = proc->next) { if (streq(proc->res_type, "void")) continue; f_print(fout, "\t\t"); ptype(proc->res_prefix, proc->res_type, 0); pvname(proc->proc_name, vp->vers_num); f_print(fout, "_res;\n"); } f_print(fout, "\t} %s;\n", RESULT); f_print(fout, "\tbool_t %s;\n", RETVAL); } else { f_print(fout, "\tchar *%s;\n", RESULT); } f_print(fout, "\txdrproc_t xdr_%s, xdr_%s;\n", ARG, RESULT); if (mtflag) f_print(fout, "\tbool_t (*%s)(char *, void *, struct svc_req *);\n", ROUTINE); else f_print(fout, "\tchar *(*%s)(char *, struct svc_req *);\n", ROUTINE); f_print(fout, "\n"); if (timerflag) { if (mtflag) f_print(fout, "\tpthread_mutex_lock(&_svcstate_lock);\n"); f_print(fout, "\t_rpcsvcstate = _SERVING;\n"); if (mtflag) f_print(fout, "\tpthread_mutex_unlock(&_svcstate_lock);\n"); } f_print(fout, "\tswitch (%s->rq_proc) {\n", RQSTP); if (!nullproc(vp->procs)) { f_print(fout, "\tcase NULLPROC:\n"); f_print(fout, "\t\tsvc_sendreply(%s,\n\t\t\t" "(xdrproc_t) xdr_void, NULL);\n", TRANSP); print_return("\t\t"); f_print(fout, "\n"); } for (proc = vp->procs; proc != NULL; proc = proc->next) { f_print(fout, "\tcase %s:\n", proc->proc_name); if (proc->arg_num < 2) { /* single argument */ p_xdrfunc(ARG, proc->args.decls->decl.type); } else { p_xdrfunc(ARG, proc->args.argname); } p_xdrfunc(RESULT, proc->res_type); if (mtflag) f_print(fout, "\t\t%s = (bool_t (*) (char *, void *, struct svc_req *))", ROUTINE); else f_print(fout, "\t\t%s = (char *(*)(char *, struct svc_req *)) ", ROUTINE); if (newstyle) { /* new style: calls internal routine */ f_print(fout, "_"); } if (!newstyle) pvname_svc(proc->proc_name, vp->vers_num); else pvname(proc->proc_name, vp->vers_num); f_print(fout, ";\n"); f_print(fout, "\t\tbreak;\n\n"); } f_print(fout, "\tdefault:\n"); printerr("noproc", TRANSP); print_return("\t\t"); f_print(fout, "\t}\n"); f_print(fout, "\tmemset((char *)&%s, 0, sizeof (%s));\n", ARG, ARG); printif("getargs", TRANSP, "(caddr_t) &", ARG); printerr("decode", TRANSP); print_return("\t\t"); f_print(fout, "\t}\n"); if (!mtflag) f_print(fout, "\t%s = (*%s)((char *)&%s, %s);\n", RESULT, ROUTINE, ARG, RQSTP); else f_print(fout, "\t%s = (bool_t) (*%s)((char *)&%s, (void *)&%s, %s);\n", RETVAL, ROUTINE, ARG, RESULT, RQSTP); if (mtflag) f_print(fout, "\tif (%s > 0 && !svc_sendreply(%s, xdr_%s, (char *)&%s)) {\n", RETVAL, TRANSP, RESULT, RESULT); else f_print(fout, "\tif (%s != NULL && !svc_sendreply(%s, xdr_%s, %s)) {\n", RESULT, TRANSP, RESULT, RESULT); printerr("systemerr", TRANSP); f_print(fout, "\t}\n"); printif("freeargs", TRANSP, "(caddr_t) &", ARG); sprintf(_errbuf, "unable to free arguments"); print_err_message("\t\t"); f_print(fout, "\t\texit(1);\n"); f_print(fout, "\t}\n"); /* print out free routine */ if (mtflag) { f_print(fout,"\tif (!"); pvname(def->def_name, vp->vers_num); f_print(fout,"_freeresult(%s, xdr_%s, (caddr_t) &%s))\n", TRANSP, RESULT, RESULT); sprintf(_errbuf, "unable to free results"); print_err_message("\t\t"); f_print(fout, "\n"); } print_return("\t"); f_print(fout, "}\n"); } } static void printerr(const char *err, const char *transp) { f_print(fout, "\t\tsvcerr_%s(%s);\n", err, transp); } static void printif(const char *proc, const char *transp, const char *prefix, const char *arg) { f_print(fout, "\tif (!svc_%s(%s, xdr_%s, (char *)%s%s)) {\n", proc, transp, arg, prefix, arg); } int nullproc(proc_list *proc) { for (; proc != NULL; proc = proc->next) { if (streq(proc->proc_num, "0")) return(1); } return(0); } static void write_inetmost(const char *infile) { f_print(fout, "\tregister SVCXPRT *%s;\n", TRANSP); f_print(fout, "\tint sock;\n"); f_print(fout, "\tint proto;\n"); f_print(fout, "\tstruct sockaddr_in saddr;\n"); f_print(fout, "\tsocklen_t asize = sizeof (saddr);\n"); f_print(fout, "\n"); f_print(fout, "\tif (getsockname(0, " "(struct sockaddr *)&saddr, &asize) == 0) {\n"); f_print(fout, "\t\tsocklen_t ssize = sizeof (int);\n\n"); f_print(fout, "\t\tif (saddr.sin_family != AF_INET)\n"); f_print(fout, "\t\t\texit(1);\n"); f_print(fout, "\t\tif (getsockopt(0, SOL_SOCKET, SO_TYPE,\n"); f_print(fout, "\t\t\t\t(char *)&_rpcfdtype, &ssize) == -1)\n"); f_print(fout, "\t\t\texit(1);\n"); f_print(fout, "\t\tsock = 0;\n"); f_print(fout, "\t\t_rpcpmstart = 1;\n"); f_print(fout, "\t\tproto = 0;\n"); open_log_file(infile, "\t\t"); f_print(fout, "\t} else {\n"); write_rpc_svc_fg(infile, "\t\t"); f_print(fout, "\t\tsock = RPC_ANYSOCK;\n"); print_pmapunset("\t\t"); f_print(fout, "\t}\n"); } static void print_return(const char *space) { if (exitnow) f_print(fout, "%sexit(0);\n", space); else { if (timerflag) { if (mtflag) f_print(fout, "%spthread_mutex_lock(&_svcstate_lock);\n", space); f_print(fout, "%s_rpcsvcstate = _SERVED;\n", space); if (mtflag) f_print(fout, "%spthread_mutex_unlock(&_svcstate_lock);\n", space); } f_print(fout, "%sreturn;\n", space); } } static void print_pmapunset(const char *space) { list *l; definition *def; version_list *vp; for (l = defined; l != NULL; l = l->next) { def = (definition *) l->val; if (def->def_kind == DEF_PROGRAM) { for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) { f_print(fout, "%spmap_unset(%s, %s);\n", space, def->def_name, vp->vers_name); } } } } static void print_err_message(const char *space) { if (logflag) f_print(fout, "%ssyslog(LOG_ERR, \"%s\");\n", space, _errbuf); else if (inetdflag || pmflag) f_print(fout, "%s_msgout(\"%s\");\n", space, _errbuf); else f_print(fout, "%sfprintf(stderr, \"%s\");\n", space, _errbuf); } /* * Write the server auxiliary function (_msgout, timeout) */ void write_svc_aux(int nomain) { if (!logflag) write_msg_out(); if (!nomain) write_timeout_func(); } /* * Write the _msgout function */ static void write_msg_out(void) { f_print(fout, "\n"); /* * Avoid making _msgout() static -- it's useful to have it visible * in the toplevel RPC server code. */ f_print(fout, "static\n"); f_print(fout, "void _msgout(const char* msg)\n"); f_print(fout, "{\n"); f_print(fout, "#ifdef RPC_SVC_FG\n"); if (inetdflag || pmflag) f_print(fout, "\tif (_rpcpmstart)\n"); f_print(fout, "\t\tsyslog(LOG_ERR, \"%%s\", msg);\n"); f_print(fout, "\telse\n"); f_print(fout, "\t\tfprintf(stderr, \"%%s\\n\", msg);\n"); f_print(fout, "#else\n"); f_print(fout, "\tsyslog(LOG_ERR, \"%%s\", msg);\n"); f_print(fout, "#endif\n"); f_print(fout, "}\n"); } /* * Write the timeout function */ static void write_timeout_func(void) { if (!timerflag) return; f_print(fout, "\n"); f_print(fout, "static void\n"); f_print(fout, "closedown(int sig)\n"); f_print(fout, "{\n"); if (mtflag) f_print(fout, "\tpthread_mutex_lock(&_svcstate_lock);\n"); f_print(fout, "\tif (_rpcsvcstate == _IDLE) {\n"); f_print(fout, "\t\textern fd_set svc_fdset;\n"); f_print(fout, "\t\tstatic int size;\n"); f_print(fout, "\t\tint i, openfd;\n"); if (tirpcflag && pmflag) { f_print(fout, "\t\tstruct t_info tinfo;\n\n"); f_print(fout, "\t\tif (!t_getinfo(0, &tinfo) && (tinfo.servtype == T_CLTS))\n"); } else { f_print(fout, "\n\t\tif (_rpcfdtype == SOCK_DGRAM)\n"); } f_print(fout, "\t\t\texit(0);\n"); f_print(fout, "\t\tif (size == 0) {\n"); if (tirpcflag) { f_print(fout, "\t\t\tstruct rlimit rl;\n\n"); f_print(fout, "\t\t\trl.rlim_max = 0;\n"); f_print(fout, "\t\t\tgetrlimit(RLIMIT_NOFILE, &rl);\n"); f_print(fout, "\t\t\tif ((size = rl.rlim_max) == 0) {\n"); if (mtflag) f_print(fout, "\t\t\t\tpthread_mutex_unlock(&_svcstate_lock);\n"); f_print(fout, "\t\t\t\treturn;\n\t\t\t}\n"); } else { f_print(fout, "\t\t\tsize = getdtablesize();\n"); } f_print(fout, "\t\t}\n"); f_print(fout, "\t\tfor (i = 0, openfd = 0; i < size && openfd < 2; i++)\n"); f_print(fout, "\t\t\tif (FD_ISSET(i, &svc_fdset))\n"); f_print(fout, "\t\t\t\topenfd++;\n"); f_print(fout, "\t\tif (openfd <= 1)\n"); f_print(fout, "\t\t\texit(0);\n"); f_print(fout, "\t}\n"); f_print(fout, "\tif (_rpcsvcstate == _SERVED)\n"); f_print(fout, "\t\t_rpcsvcstate = _IDLE;\n\n"); if (mtflag) f_print(fout, "\tpthread_mutex_unlock(&_svcstate_lock);\n"); f_print(fout, "\tsignal(SIGALRM, closedown);\n"); f_print(fout, "\talarm(_RPCSVC_CLOSEDOWN/2);\n"); f_print(fout, "}\n"); } /* * Write the most of port monitor support */ static void write_pm_most(const char *infile, int netflag) { list *l; definition *def; version_list *vp; if (tirpc_socket) { f_print(fout, "\tif (getsockname(0, (struct sockaddr *)&saddr, &asize) == 0) {\n"); f_print(fout, "\t\tsocklen_t ssize = sizeof (int);\n"); } else { f_print(fout, "\tif (!ioctl(0, I_LOOK, mname) &&\n"); f_print(fout, "\t\t(!strcmp(mname, \"sockmod\") ||"); f_print(fout, " !strcmp(mname, \"timod\"))) {\n"); } f_print(fout, "\t\tchar *netid;\n"); if (!netflag) { /* Not included by -n option */ f_print(fout, "\t\tstruct netconfig *nconf = NULL;\n"); f_print(fout, "\t\tSVCXPRT *%s;\n", TRANSP); } if (timerflag) f_print(fout, "\t\tint pmclose;\n"); /* * Not necessary, defined in /usr/include/stdlib * f_print(fout, "\t\textern char *getenv();\n"); */ f_print(fout, "\n"); if (tirpc_socket) { f_print(fout, "\t\tif (saddr.ss_family != AF_INET &&\n"); f_print(fout, "\t\t saddr.ss_family != AF_INET6)\n"); f_print(fout, "\t\t\texit(1);\n"); f_print(fout, "\t\tif (getsockopt(0, SOL_SOCKET, SO_TYPE,\n"); f_print(fout, "\t\t\t\t(char *)&_rpcfdtype, &ssize) == -1)\n"); f_print(fout, "\t\t\texit(1);\n"); } f_print(fout, "\t\t_rpcpmstart = 1;\n"); open_log_file(infile, "\t\t"); f_print(fout, "\n\t\tif ((netid = \ getenv(\"NLSPROVIDER\")) == NULL) {\n"); if (timerflag) { f_print(fout, "\t\t/* started from inetd */\n"); f_print(fout, "\t\t\tpmclose = 1;\n"); } f_print(fout, "\t\t} else {\n"); f_print(fout, "\t\t\tif ((nconf = getnetconfigent(netid)) == NULL)\n"); sprintf(_errbuf, "cannot get transport info"); print_err_message("\t\t\t\t"); if (timerflag) { if (tirpc_socket) f_print(fout, "\n\t\t\tpmclose = 1;\t/* XXX */\n"); else f_print(fout, "\n\t\t\tpmclose = (t_getstate(0) != T_DATAXFER);\n"); } f_print(fout, "\t\t}\n"); /* * A kludgy support for inetd services. Inetd only works with * sockmod, and RPC works only with timod, hence all this jugglery */ if (!tirpc_socket) { f_print(fout, "\t\tif (strcmp(mname, \"sockmod\") == 0) {\n"); f_print(fout, "\t\t\tif (ioctl(0, I_POP, 0) || "); f_print(fout, "ioctl(0, I_PUSH, \"timod\")) {\n"); sprintf(_errbuf, "could not get the right module"); print_err_message("\t\t\t\t"); f_print(fout, "\t\t\t\texit(1);\n"); f_print(fout, "\t\t\t}\n"); f_print(fout, "\t\t}\n"); } if (tirpcflag) { f_print(fout, "\t\tif ((%s = svc_tli_create(0, nconf, NULL, \ RPC_MAXDATASIZE, RPC_MAXDATASIZE)) \ == NULL) {\n", TRANSP); } else { f_print(fout, "\t\tif ((%s = svc_tli_create(0, nconf, NULL, 0, 0)) \ == NULL) {\n", TRANSP); } sprintf(_errbuf, "cannot create server handle"); print_err_message("\t\t\t"); f_print(fout, "\t\t\texit(1);\n"); f_print(fout, "\t\t}\n"); f_print(fout, "\t\tif (nconf)\n"); f_print(fout, "\t\t\tfreenetconfigent(nconf);\n"); for (l = defined; l != NULL; l = l->next) { def = (definition *) l->val; if (def->def_kind != DEF_PROGRAM) continue; for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) { f_print(fout, "\t\tif (!svc_reg(%s, %s, %s, ", TRANSP, def->def_name, vp->vers_name); pvname(def->def_name, vp->vers_num); f_print(fout, ", 0)) {\n"); sprintf(_errbuf, "unable to register (%s, %s).", def->def_name, vp->vers_name); print_err_message("\t\t\t"); f_print(fout, "\t\t\texit(1);\n"); f_print(fout, "\t\t}\n"); } } if (timerflag) { f_print(fout, "\t\tif (pmclose) {\n"); f_print(fout, "\t\t\tsignal(SIGALRM, closedown);\n"); f_print(fout, "\t\t\talarm(_RPCSVC_CLOSEDOWN/2);\n"); f_print(fout, "\t\t}\n"); } f_print(fout, "\t\tsvc_run();\n"); f_print(fout, "\t\texit(1);\n"); f_print(fout, "\t\t/* NOTREACHED */\n"); f_print(fout, "\t}"); } /* * Support for backgrounding the server if self started. */ static void write_rpc_svc_fg(const char *infile, const char *sp) { f_print(fout, "#ifndef RPC_SVC_FG\n"); f_print(fout, "%sint size;\n", sp); if (tirpcflag) f_print(fout, "%sstruct rlimit rl;\n", sp); if (inetdflag) f_print(fout, "%sint pid, i;\n\n", sp); f_print(fout, "%spid = fork();\n", sp); f_print(fout, "%sif (pid < 0) {\n", sp); f_print(fout, "%s\tperror(\"cannot fork\");\n", sp); f_print(fout, "%s\texit(1);\n", sp); f_print(fout, "%s}\n", sp); f_print(fout, "%sif (pid)\n", sp); f_print(fout, "%s\texit(0);\n", sp); /* get number of file descriptors */ if (tirpcflag) { f_print(fout, "%srl.rlim_max = 0;\n", sp); f_print(fout, "%sgetrlimit(RLIMIT_NOFILE, &rl);\n", sp); f_print(fout, "%sif ((size = rl.rlim_max) == 0)\n", sp); f_print(fout, "%s\texit(1);\n", sp); } else { f_print(fout, "%ssize = getdtablesize();\n", sp); } f_print(fout, "%sfor (i = 0; i < size; i++)\n", sp); f_print(fout, "%s\tclose(i);\n", sp); /* Redirect stderr and stdout to console */ f_print(fout, "%si = open(\"/dev/console\", 2);\n", sp); f_print(fout, "%sdup2(i, 1);\n", sp); f_print(fout, "%sdup2(i, 2);\n", sp); /* This removes control of the controlling terminal */ if (tirpcflag) { f_print(fout, "%ssetsid();\n", sp); } else { f_print(fout, "%si = open(\"/dev/tty\", 2);\n", sp); f_print(fout, "%sif (i >= 0) {\n", sp); f_print(fout, "%s\tioctl(i, TIOCNOTTY, NULL);\n", sp); f_print(fout, "%s\tclose(i);\n", sp); f_print(fout, "%s}\n", sp); } if (!logflag) open_log_file(infile, sp); f_print(fout, "#endif\n"); if (logflag) open_log_file(infile, sp); } static void open_log_file(const char *infile, const char *sp) { char *s; s = strrchr(infile, '.'); if (s) *s = '\0'; f_print(fout, "%sopenlog(\"%s\", LOG_PID, LOG_DAEMON);\n", sp, infile); if (s) *s = '.'; } /* * write a registration for the given transport for Inetd */ void write_inetd_register(const char *transp) { list *l; definition *def; version_list *vp; const char *sp; int isudp; char tmpbuf[32]; if (inetdflag) sp = "\t"; else sp = ""; if (streq(transp, "udp")) isudp = 1; else isudp = 0; f_print(fout, "\n"); if (inetdflag) { f_print(fout, "\tif ((_rpcfdtype == 0) || (_rpcfdtype == %s)) {\n", isudp ? "SOCK_DGRAM" : "SOCK_STREAM"); } f_print(fout, "%s\t%s = svc%s_create(%s", sp, TRANSP, transp, inetdflag? "sock": "RPC_ANYSOCK"); if (!isudp) f_print(fout, ", 0, 0"); f_print(fout, ");\n"); f_print(fout, "%s\tif (%s == NULL) {\n", sp, TRANSP); sprintf(_errbuf, "cannot create %s service.", transp); sprintf(tmpbuf, "%s\t\t", sp); print_err_message(tmpbuf); f_print(fout, "%s\t\texit(1);\n", sp); f_print(fout, "%s\t}\n", sp); if (inetdflag) { f_print(fout, "%s\tif (!_rpcpmstart)\n\t", sp); f_print(fout, "%s\tproto = IPPROTO_%s;\n", sp, isudp ? "UDP": "TCP"); } for (l = defined; l != NULL; l = l->next) { def = (definition *) l->val; if (def->def_kind != DEF_PROGRAM) continue; for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) { f_print(fout, "%s\tif (!svc_register(%s, %s, %s, ", sp, TRANSP, def->def_name, vp->vers_name); pvname(def->def_name, vp->vers_num); if (inetdflag) f_print(fout, ", proto)) {\n"); else f_print(fout, ", IPPROTO_%s)) {\n", isudp ? "UDP": "TCP"); sprintf(_errbuf, "unable to register (%s, %s, %s).", def->def_name, vp->vers_name, transp); print_err_message(tmpbuf); f_print(fout, "%s\t\texit(1);\n", sp); f_print(fout, "%s\t}\n", sp); } } if (inetdflag) f_print(fout, "\t}\n"); } [FILE:3001:files/rpc_tblout.c] #include #include #include #include "rpc_parse.h" #include "rpc_scan.h" #include "rpc_util.h" #define TABSIZE 8 #define TABCOUNT 5 #define TABSTOP (TABSIZE*TABCOUNT) static char tabstr[TABCOUNT+1] = "\t\t\t\t\t"; static char tbl_hdr[] = "struct rpcgen_table %s_table[] = {\n"; static char tbl_end[] = "};\n"; static char null_entry[] = "\n\t(char *(*)())0,\n\ \t(xdrproc_t) xdr_void,\t\t\t0,\n\ \t(xdrproc_t) xdr_void,\t\t\t0,\n"; static char tbl_nproc[] = "int %s_nproc =\n\tsizeof(%s_table)/sizeof(%s_table[0]);\n\n"; static void write_table(definition *); static void printit(const char *, const char *); void write_tables(void) { list *l; definition *def; f_print(fout, "\n"); for (l = defined; l != NULL; l = l->next) { def = (definition *) l->val; if (def->def_kind == DEF_PROGRAM) { write_table(def); } } } static void write_table(definition *def) { version_list *vp; proc_list *proc; int current; int expected; char progvers[100]; int warning; for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) { warning = 0; s_print(progvers, "%s_%s", locase(def->def_name), vp->vers_num); /* print the table header */ f_print(fout, tbl_hdr, progvers); if (nullproc(vp->procs)) { expected = 0; } else { expected = 1; f_print(fout, "%s", null_entry); } for (proc = vp->procs; proc != NULL; proc = proc->next) { current = atoi(proc->proc_num); if (current != expected++) { f_print(fout, "\n/*\n * WARNING: table out of order\n */\n"); if (warning == 0) { warnx("WARNING %s table is out of order", progvers); warning = 1; nonfatalerrors = 1; } expected = current + 1; } f_print(fout, "\n\t(char *(*)())RPCGEN_ACTION("); /* routine to invoke */ if(!newstyle) pvname_svc(proc->proc_name, vp->vers_num); else { if (newstyle) f_print(fout, "_"); /* calls internal func */ pvname(proc->proc_name, vp->vers_num); } f_print(fout, "),\n"); /* argument info */ if (proc->arg_num > 1) { printit(NULL, proc->args.argname); } else { /* * do we have to do something special for * newstyle */ printit(proc->args.decls->decl.prefix, proc->args.decls->decl.type); } /* result info */ printit(proc->res_prefix, proc->res_type); } /* print the table trailer */ f_print(fout, "%s", tbl_end); f_print(fout, tbl_nproc, progvers, progvers, progvers); } } static void printit(const char *prefix, const char *type) { int len; int tabs; len = fprintf(fout, "\txdr_%s,", stringfix(type)); /* account for leading tab expansion */ len += TABSIZE - 1; /* round up to tabs required */ tabs = (TABSTOP - len + TABSIZE - 1)/TABSIZE; f_print(fout, "%s", &tabstr[TABCOUNT-tabs]); if (streq(type, "void")) { f_print(fout, "0"); } else { f_print(fout, "sizeof ( "); /* XXX: should "follow" be 1 ??? */ ptype(prefix, type, 0); f_print(fout, ")"); } f_print(fout, ",\n"); } [FILE:7428:files/rpc_util.c] #include #include #include #include #include #include "rpc_parse.h" #include "rpc_scan.h" #include "rpc_util.h" #define ARGEXT "argument" char curline[MAXLINESIZE]; /* current read line */ char *where = curline; /* current point in line */ int linenum = 0; /* current line number */ const char *infilename; /* input filename */ #define NFILES 7 const char *outfiles[NFILES]; /* output file names */ int nfiles; FILE *fout; /* file pointer of current output */ FILE *fin; /* file pointer of current input */ list *defined; /* list of defined things */ static void printwhere(void); /* * Reinitialize the world */ void reinitialize(void) { memset(curline, 0, MAXLINESIZE); where = curline; linenum = 0; defined = NULL; } /* * string equality */ int streq(const char *a, const char *b) { return(strcmp(a, b) == 0); } /* * find a value in a list */ definition * findval(list *lst, const char *val, int (*cmp)(definition *, const char *)) { for (; lst != NULL; lst = lst->next) { if ((*cmp) (lst->val, val)) return(lst->val); } return(NULL); } /* * store a value in a list */ void storeval(list **lstp, definition *val) { list **l; list *lst; for (l = lstp; *l != NULL; l = (list **) & (*l)->next) ; lst = XALLOC(list); lst->val = val; lst->next = NULL; *l = lst; } static int findit(definition *def, const char *type) { return(streq(def->def_name, type)); } static const char * fixit(const char *type, const char *orig) { definition *def; def = (definition *) FINDVAL(defined, type, findit); if (def == NULL || def->def_kind != DEF_TYPEDEF) return(orig); switch (def->def.ty.rel) { case REL_VECTOR: if (streq(def->def.ty.old_type, "opaque")) return("char"); else return(def->def.ty.old_type); case REL_ALIAS: return(fixit(def->def.ty.old_type, orig)); default: return(orig); } } const char * fixtype(const char *type) { return(fixit(type, type)); } const char * stringfix(const char *type) { if (streq(type, "string")) return("wrapstring"); else return(type); } void ptype(const char *prefix, const char *type, int follow) { if (prefix != NULL) { if (streq(prefix, "enum")) f_print(fout, "enum "); else f_print(fout, "struct "); } if (streq(type, "bool")) f_print(fout, "bool_t "); else if (streq(type, "string")) f_print(fout, "char *"); else f_print(fout, "%s ", follow ? fixtype(type) : type); } static int typedefed(definition *def, const char *type) { if (def->def_kind != DEF_TYPEDEF || def->def.ty.old_prefix != NULL) return(0); else return(streq(def->def_name, type)); } int isvectordef(const char *type, relation rel) { definition *def; for (;;) { switch (rel) { case REL_VECTOR: return(!streq(type, "string")); case REL_ARRAY: return(0); case REL_POINTER: return(0); case REL_ALIAS: def = (definition *) FINDVAL(defined, type, typedefed); if (def == NULL) { return(0); } type = def->def.ty.old_type; rel = def->def.ty.rel; } } return(0); } char * locase(const char *str) { char c; static char buf[100]; char *p = buf; while ((c = *str++) != 0) *p++ = (c >= 'A' && c <= 'Z') ? (c - 'A' + 'a') : c; *p = 0; return(buf); } void pvname_svc(const char *pname, const char *vnum) { f_print(fout, "%s_%s_svc", locase(pname), vnum); } void pvname(const char *pname, const char *vnum) { f_print(fout, "%s_%s", locase(pname), vnum); } /* * print a useful (?) error message, and then die */ void error(const char *msg) { printwhere(); warnx("%s, line %d: %s", infilename, linenum, msg); crash(); } /* * Something went wrong, unlink any files that we may have created and then * die. */ void crash(void) { int i; for (i = 0; i < nfiles; i++) unlink(outfiles[i]); exit(1); } void record_open(const char *file) { if (nfiles < NFILES) { outfiles[nfiles++] = file; } else { warnx("too many files"); crash(); } } static char expectbuf[100]; static const char *toktostr(tok_kind); /* * error, token encountered was not the expected one */ void expected1(tok_kind exp1) { s_print(expectbuf, "expected '%s'", toktostr(exp1)); error(expectbuf); } /* * error, token encountered was not one of two expected ones */ void expected2(tok_kind exp1, tok_kind exp2) { s_print(expectbuf, "expected '%s' or '%s'", toktostr(exp1), toktostr(exp2)); error(expectbuf); } /* * error, token encountered was not one of 3 expected ones */ void expected3(tok_kind exp1, tok_kind exp2, tok_kind exp3) { s_print(expectbuf, "expected '%s', '%s' or '%s'", toktostr(exp1), toktostr(exp2), toktostr(exp3)); error(expectbuf); } void tabify(FILE *f, int tab) { while (tab--) fputc('\t', f); } static token tokstrings[] = { {TOK_IDENT, "identifier"}, {TOK_CONST, "const"}, {TOK_RPAREN, ")"}, {TOK_LPAREN, "("}, {TOK_RBRACE, "}"}, {TOK_LBRACE, "{"}, {TOK_LBRACKET, "["}, {TOK_RBRACKET, "]"}, {TOK_STAR, "*"}, {TOK_COMMA, ","}, {TOK_EQUAL, "="}, {TOK_COLON, ":"}, {TOK_SEMICOLON, ";"}, {TOK_UNION, "union"}, {TOK_STRUCT, "struct"}, {TOK_SWITCH, "switch"}, {TOK_CASE, "case"}, {TOK_DEFAULT, "default"}, {TOK_ENUM, "enum"}, {TOK_TYPEDEF, "typedef"}, {TOK_INT, "int"}, {TOK_SHORT, "short"}, {TOK_LONG, "long"}, {TOK_UNSIGNED, "unsigned"}, {TOK_DOUBLE, "double"}, {TOK_FLOAT, "float"}, {TOK_CHAR, "char"}, {TOK_STRING, "string"}, {TOK_OPAQUE, "opaque"}, {TOK_BOOL, "bool"}, {TOK_VOID, "void"}, {TOK_PROGRAM, "program"}, {TOK_VERSION, "version"}, {TOK_EOF, "??????"} }; static const char * toktostr(tok_kind kind) { token *sp; for (sp = tokstrings; sp->kind != TOK_EOF && sp->kind != kind; sp++) ; return(sp->str); } static void printbuf(void) { char c; int i; int cnt; # define TABSIZE 4 for (i = 0; (c = curline[i]); i++) { if (c == '\t') { cnt = 8 - (i % TABSIZE); c = ' '; } else { cnt = 1; } while (cnt--) fputc(c, stderr); } } static void printwhere(void) { int i; char c; int cnt; printbuf(); for (i = 0; i < where - curline; i++) { c = curline[i]; if (c == '\t') cnt = 8 - (i % TABSIZE); else cnt = 1; while (cnt--) { fputc('^', stderr); } } fputc('\n', stderr); } char * make_argname(const char *pname, const char *vname) { char *name; name = xmalloc(strlen(pname) + strlen(vname) + strlen(ARGEXT) + 3); sprintf(name, "%s_%s_%s", locase(pname), vname, ARGEXT); return(name); } bas_type *typ_list_h; bas_type *typ_list_t; void add_type(int len, const char *type) { bas_type *ptr; ptr = XALLOC(bas_type); ptr->name = type; ptr->length = len; ptr->next = NULL; if (typ_list_t == NULL) { typ_list_t = ptr; typ_list_h = ptr; } else { typ_list_t->next = ptr; typ_list_t = ptr; } } bas_type * find_type(const char *type) { bas_type * ptr; ptr = typ_list_h; while (ptr != NULL) { if (strcmp(ptr->name, type) == 0) return(ptr); else ptr = ptr->next; } return(NULL); } void * xmalloc(size_t size) { void *p; if ((p = malloc(size)) == NULL) { warnx("malloc failed"); crash(); } return (p); } void * xrealloc(void *ptr, size_t size) { void *p; if ((p = realloc(ptr, size)) == NULL) { warnx("realloc failed"); crash(); } return (p); } char * xstrdup(const char *str) { char *p; if ((p = strdup(str)) == NULL) { warnx("strdup failed"); crash(); } return (p); } [FILE:3915:files/rpc_util.h] /* * rpc_util.h, Useful definitions for the RPC protocol compiler */ #include #include #define XALLOC(object) (object *) xmalloc(sizeof(object)) #define s_print (void) sprintf #define f_print (void) fprintf #ifndef __unused #define __unused __attribute__((__unused__)) #endif struct list { definition *val; struct list *next; }; typedef struct list list; struct xdrfunc { const char *name; int pointerp; struct xdrfunc *next; }; typedef struct xdrfunc xdrfunc; struct commandline { int cflag; /* xdr C routines */ int hflag; /* header file */ int lflag; /* client side stubs */ int mflag; /* server side stubs */ int nflag; /* netid flag */ int sflag; /* server stubs for the given transport */ int tflag; /* dispatch Table file */ int Ssflag; /* produce server sample code */ int Scflag; /* produce client sample code */ int makefileflag; /* Generate a template Makefile */ const char *infile; /* input module name */ const char *outfile; /* output module name */ }; #define PUT 1 #define GET 2 /* * Global variables */ #define MAXLINESIZE 1024 extern char curline[MAXLINESIZE]; extern char *where; extern int linenum; extern int tirpc_socket; extern const char *infilename; extern FILE *fout; extern FILE *fin; extern list *defined; extern bas_type *typ_list_h; extern bas_type *typ_list_t; extern xdrfunc *xdrfunc_head, *xdrfunc_tail; /* * All the option flags */ extern int inetdflag; extern int pmflag; extern int tblflag; extern int logflag; extern int newstyle; extern int CCflag; /* C++ flag */ extern int tirpcflag; /* flag for generating tirpc code */ extern int inline_size; /* if this is 0, then do not generate inline code */ extern int mtflag; /* * Other flags related with inetd jumpstart. */ extern int indefinitewait; extern int exitnow; extern int timerflag; extern int nonfatalerrors; extern pid_t childpid; /* * rpc_util routines */ void reinitialize(void); void crash(void); void add_type(int, const char *); void storeval(list **, definition *); void *xmalloc(size_t); void *xrealloc(void *, size_t); char *xstrdup(const char *); char *make_argname(const char *, const char *); #define STOREVAL(list,item) \ storeval(list,item) definition *findval(list *, const char *, int (*)(definition *, const char *)); #define FINDVAL(list,item,finder) \ findval(list, item, finder) const char *fixtype(const char *); const char *stringfix(const char *); char *locase(const char *); void pvname_svc(const char *, const char *); void pvname(const char *, const char *); void ptype(const char *, const char *, int); int isvectordef(const char *, relation); int streq(const char *, const char *); void error(const char *); void expected1(tok_kind); void expected2(tok_kind, tok_kind); void expected3(tok_kind, tok_kind, tok_kind); void tabify(FILE *, int); void record_open(const char *); bas_type *find_type(const char *); /* * rpc_cout routines */ void emit(definition *); /* * rpc_hout routines */ void pdeclaration(const char *, declaration *, int, const char *); void print_datadef(definition *, int); void print_funcdef(definition *, int); void print_xdr_func_def(const char *, int); /* * rpc_svcout routines */ void write_most(const char *, int, int); void write_rest(void); void write_programs(const char *); void write_svc_aux(int); void write_inetd_register(const char *); void write_netid_register(const char *); void write_nettype_register(const char *); int nullproc(proc_list *); /* * rpc_clntout routines */ void write_stubs(void); void printarglist(proc_list *, const char *, const char *, const char *); /* * rpc_tblout routines */ void write_tables(void); /* * rpc_sample routines */ void write_sample_svc(definition *); int write_sample_clnt(definition *); void write_sample_clnt_main(void); void add_sample_msg(void); [FILE:10989:files/rpcgen.1] .Dd September 2, 2005 .Dt RPCGEN 1 .Os .Sh NAME .Nm rpcgen .Nd an RPC protocol compiler .Sh SYNOPSIS .Nm .Ar infile .Nm .Op Fl a .Op Fl b .Op Fl C .Oo .Fl D Ns Ar name Ns Op Ar =value .Oc .Op Fl i Ar size .Op Fl I Fl P Op Fl K Ar seconds .Op Fl L .Op Fl M .Op Fl N .Op Fl T .Op Fl Y Ar pathname .Ar infile .Nm .Oo .Fl c | .Fl h | .Fl l | .Fl m | .Fl t | .Fl \&Sc | .Fl \&Ss | .Fl \&Sm .Oc .Op Fl o Ar outfile .Op Ar infile .Nm .Op Fl s Ar nettype .Op Fl o Ar outfile .Op Ar infile .Nm .Op Fl n Ar netid .Op Fl o Ar outfile .Op Ar infile .\" .SH AVAILABILITY .\" .LP .\" SUNWcsu .Sh DESCRIPTION The .Nm utility is a tool that generates C code to implement an .Tn RPC protocol. The input to .Nm is a language similar to C known as .Tn RPC Language (Remote Procedure Call Language). .Pp The .Nm utility is normally used as in the first synopsis where it takes an input file and generates three output files. If the .Ar infile is named .Pa proto.x , then .Nm generates a header in .Pa proto.h , XDR routines in .Pa proto_xdr.c , server-side stubs in .Pa proto_svc.c , and client-side stubs in .Pa proto_clnt.c . With the .Fl T option, it also generates the .Tn RPC dispatch table in .Pa proto_tbl.i . .Pp The .Nm utility can also generate sample client and server files that can be customized to suit a particular application. The .Fl \&Sc , .Fl \&Ss and .Fl \&Sm options generate sample client, server and makefile, respectively. The .Fl a option generates all files, including sample files. If the .Ar infile is .Pa proto.x , then the client side sample file is written to .Pa proto_client.c , the server side sample file to .Pa proto_server.c and the sample makefile to .Pa makefile.proto . .Pp If option .Fl I is set, the server created can be started both by the port monitors (for example, .Xr inetd 8 ) or by itself. When it is started by a port monitor, it creates servers only for the transport for which the file descriptor .Em 0 was passed. The name of the transport may be specified by setting up the environment variable .Ev NLSPROVIDER . When the server generated by .Nm is executed, it creates server handles for all the transports specified in .Ev NETPATH environment variable, or if it is unset, it creates server handles for all the visible transports from .Pa /etc/netconfig file. Note: the transports are chosen at run time and not at compile time. When the server is self-started, it backgrounds itself by default. A special define symbol .Em RPC_SVC_FG can be used to run the server process in foreground. .Pp The second synopsis provides special features which allow for the creation of more sophisticated .Tn RPC servers. These features include support for user provided .Em #defines and .Tn RPC dispatch tables. The entries in the .Tn RPC dispatch table contain: .Bl -bullet -offset indent -compact .It pointers to the service routine corresponding to that procedure, .It a pointer to the input and output arguments, .It the size of these routines. .El A server can use the dispatch table to check authorization and then to execute the service routine; a client library may use it to deal with the details of storage management and XDR data conversion. .Pp The other three synopses shown above are used when one does not want to generate all the output files, but only a particular one. See the .Sx EXAMPLES section below for examples of .Nm usage. When .Nm is executed with the .Fl s option, it creates servers for that particular class of transports. When executed with the .Fl n option, it creates a server for the transport specified by .Ar netid . If .Ar infile is not specified, .Nm accepts the standard input. .Pp The C preprocessor, .Em cc -E is run on the input file before it is actually interpreted by .Nm . For each type of output file, .Nm defines a special preprocessor symbol for use by the .Nm programmer: .Bl -tag -width indent .It RPC_HDR defined when compiling into headers .It RPC_XDR defined when compiling into XDR routines .It RPC_SVC defined when compiling into server-side stubs .It RPC_CLNT defined when compiling into client-side stubs .It RPC_TBL defined when compiling into RPC dispatch tables .El .Pp Any line beginning with .Dq % is passed directly into the output file, uninterpreted by .Nm . To specify the path name of the C preprocessor use .Fl Y flag. .Pp For every data type referred to in .Ar infile , .Nm assumes that there exists a routine with the string .Em xdr_ prepended to the name of the data type. If this routine does not exist in the .Tn RPC/XDR library, it must be provided. Providing an undefined data type allows customization of .Xr xdr 3 routines. .Sh OPTIONS The following options are available: .Bl -tag -width indent .It Fl a Generate all files, including sample files. .It Fl b Backward compatibility mode. Generate transport specific .Tn RPC code for older versions of the operating system. .It Fl c Compile into .Tn XDR routines. .It Fl C Generate ANSI C code. This is always done, the flag is only provided for backwards compatibility. .It Fl D Ns Ar name .It Fl D Ns Ar name=value .\".It Fl D Ns Ar name Ns Op Ar =value Define a symbol .Ar name . Equivalent to the .Em #define directive in the source. If no .Ar value is given, .Ar value is defined as .Em 1 . This option may be specified more than once. .It Fl h Compile into C data-definitions (a header). .Fl T option can be used in conjunction to produce a header which supports .Tn RPC dispatch tables. .It Fl i Ar size Size at which to start generating inline code. This option is useful for optimization. The default size is 5. .Pp Note: in order to provide backwards compatibility with the older .Nm on the .Dx platform, the default is actually 0 (which means that inline code generation is disabled by default). You must specify a non-zero value explicitly to override this default. .It Fl I Compile support for .Xr inetd 8 in the server side stubs. Such servers can be self-started or can be started by .Xr inetd 8 . When the server is self-started, it backgrounds itself by default. A special define symbol .Em RPC_SVC_FG can be used to run the server process in foreground, or the user may simply compile without the .Fl I option. .Pp If there are no pending client requests, the .Xr inetd 8 servers exit after 120 seconds (default). The default can be changed with the .Fl K option. All the error messages for .Xr inetd 8 servers are always logged with .Xr syslog 3 . .Pp Note: Contrary to some systems, in .Dx this option is needed to generate servers that can be invoked through portmonitors and .Xr inetd 8 . .It Fl K Ar seconds By default, services created using .Nm and invoked through port monitors wait 120 seconds after servicing a request before exiting. That interval can be changed using the .Fl K flag. To create a server that exits immediately upon servicing a request, use .Fl K Ar 0 . To create a server that never exits, the appropriate argument is .Fl K Ar -1 . .Pp When monitoring for a server, some portmonitors .Em always spawn a new process in response to a service request. If it is known that a server will be used with such a monitor, the server should exit immediately on completion. For such servers, .Nm should be used with .Fl K Ar 0 . .It Fl l Compile into client-side stubs. .It Fl L When the servers are started in foreground, use .Xr syslog 3 to log the server errors instead of printing them on the standard error. .It Fl m Compile into server-side stubs, but do not generate a .Qq main routine. This option is useful for doing callback-routines and for users who need to write their own .Qq main routine to do initialization. .It Fl M Generate multithread-safe stubs for passing arguments and results between rpcgen generated code and user written code. This option is useful for users who want to use threads in their code. However, the .Xr rpc_svc_calls 3 functions are not yet MT-safe, which means that rpcgen generated server-side code will not be MT-safe. .It Fl N Allow procedures to have multiple arguments. It also uses the style of parameter passing that closely resembles C. So, when passing an argument to a remote procedure, you do not have to pass a pointer to the argument, but can pass the argument itself. This behavior is different from the old style of .Nm generated code. To maintain backward compatibility, this option is not the default. .It Fl n Ar netid Compile into server-side stubs for the transport specified by .Ar netid . There should be an entry for .Ar netid in the netconfig database. This option may be specified more than once, so as to compile a server that serves multiple transports. .It Fl o Ar outfile Specify the name of the output file. If none is specified, standard output is used .Fl ( c , .Fl h , .Fl l , .Fl m , .Fl n , .Fl s , .Fl \&Sc , .Fl \&Sm , .Fl \&Ss , and .Fl t modes only). .It Fl P Compile support for port monitors in the server side stubs. .Pp Note: Contrary to some systems, in .Dx this option is needed to generate servers that can be monitored. .Pp If the .Fl I option has been specified, .Fl P is turned off automatically. .It Fl s Ar nettype Compile into server-side stubs for all the transports belonging to the class .Ar nettype . The supported classes are .Em netpath , .Em visible , .Em circuit_n , .Em circuit_v , .Em datagram_n , .Em datagram_v , .Em tcp , and .Em udp (see .Xr rpc 3 for the meanings associated with these classes). This option may be specified more than once. Note: the transports are chosen at run time and not at compile time. .It Fl \&Sc Generate sample client code that uses remote procedure calls. .It Fl \&Sm Generate a sample .Pa Makefile which can be used for compiling the application. .It Fl \&Ss Generate sample server code that uses remote procedure calls. .It Fl t Compile into .Tn RPC dispatch table. .It Fl T Generate the code to support .Tn RPC dispatch tables. .Pp The options .Fl c , .Fl h , .Fl l , .Fl m , .Fl s , .Fl \&Sc , .Fl \&Sm , .Fl \&Ss , and .Fl t are used exclusively to generate a particular type of file, while the options .Fl D and .Fl T are global and can be used with the other options. .It Fl Y Ar pathname Give the name of the directory where .Nm will start looking for the C-preprocessor. .El .Sh EXAMPLES The following example: .Dl example% rpcgen -T prot.x .Pp generates all the five files: .Pa prot.h , .Pa prot_clnt.c , .Pa prot_svc.c , .Pa prot_xdr.c and .Pa prot_tbl.i . .Pp The following example sends the C data-definitions (header) to the standard output. .Dl example% rpcgen -h prot.x .Pp To send the test version of the .Fl D Ns Ar TEST , server side stubs for all the transport belonging to the class .Ar datagram_n to standard output, use: .Dl example% rpcgen -s datagram_n -DTEST prot.x .Pp To create the server side stubs for the transport indicated by .Ar netid tcp, use: .Dl example% rpcgen -n tcp -o prot_svc.c prot.x .Sh SEE ALSO .Xr cc 1 , .Xr rpc 3 , .Xr rpc_svc_calls 3 , .Xr syslog 3 , .Xr xdr 3 , .Xr inetd 8 .Rs .%T The rpcgen chapter in the NETP manual .Re