void RvalDestroy(Rval rval) { Rlist *clist, *next = NULL; CfDebug("DeleteRvalItem(%c)", rval.type); if (DEBUG) { RvalShow(stdout, rval); } CfDebug("\n"); if (rval.item == NULL) { CfDebug("DeleteRval NULL\n"); return; } switch (rval.type) { case RVAL_TYPE_SCALAR: ThreadLock(cft_lock); free((char *) rval.item); ThreadUnlock(cft_lock); break; case RVAL_TYPE_LIST: /* rval is now a list whose first item is clist->item */ for (clist = (Rlist *) rval.item; clist != NULL; clist = next) { next = clist->next; if (clist->item) { RvalDestroy((Rval) {clist->item, clist->type}); } free(clist); } break; case RVAL_TYPE_FNCALL: FnCallDestroy((FnCall *) rval.item); break; default: CfDebug("Nothing to do\n"); return; } }
void ArgTemplate(FnCall *fp, const FnCallArg *argtemplate, Rlist *realargs) { int argnum, i; Rlist *rp = fp->args; char id[CF_BUFSIZE], output[CF_BUFSIZE]; const FnCallType *fn = FnCallTypeGet(fp->name); snprintf(id, CF_MAXVARSIZE, "built-in FnCall %s-arg", fp->name); for (argnum = 0; rp != NULL && argtemplate[argnum].pattern != NULL; argnum++) { if (rp->type != RVAL_TYPE_FNCALL) { /* Nested functions will not match to lval so don't bother checking */ SyntaxTypeMatch err = CheckConstraintTypeMatch(id, (Rval) {rp->item, rp->type}, argtemplate[argnum].dtype, argtemplate[argnum].pattern, 1); if (err != SYNTAX_TYPE_MATCH_OK && err != SYNTAX_TYPE_MATCH_ERROR_UNEXPANDED) { FatalError("in %s: %s", id, SyntaxTypeMatchToString(err)); } } rp = rp->next; } if (argnum != RlistLen(realargs) && !fn->varargs) { snprintf(output, CF_BUFSIZE, "Argument template mismatch handling function %s(", fp->name); RlistShow(stderr, realargs); fprintf(stderr, ")\n"); for (i = 0, rp = realargs; i < argnum; i++) { printf(" arg[%d] range %s\t", i, argtemplate[i].pattern); if (rp != NULL) { RvalShow(stdout, (Rval) {rp->item, rp->type}); rp = rp->next; } else { printf(" ? "); } printf("\n"); } FatalError("Bad arguments"); } for (rp = realargs; rp != NULL; rp = rp->next) { CfDebug("finalarg: %s\n", (char *) rp->item); } CfDebug("End ArgTemplate\n"); }
static FnCallResult CallFunction(EvalContext *ctx, FnCall *fp, Rlist *expargs) { Rlist *rp = fp->args; const FnCallType *fncall_type = FnCallTypeGet(fp->name); int argnum = 0; for (argnum = 0; rp != NULL && fncall_type->args[argnum].pattern != NULL; argnum++) { if (rp->val.type != RVAL_TYPE_FNCALL) { /* Nested functions will not match to lval so don't bother checking */ SyntaxTypeMatch err = CheckConstraintTypeMatch(fp->name, rp->val, fncall_type->args[argnum].dtype, fncall_type->args[argnum].pattern, 1); if (err != SYNTAX_TYPE_MATCH_OK && err != SYNTAX_TYPE_MATCH_ERROR_UNEXPANDED) { FatalError(ctx, "In function '%s', '%s'", fp->name, SyntaxTypeMatchToString(err)); } } rp = rp->next; } char output[CF_BUFSIZE]; if (argnum != RlistLen(expargs) && !(fncall_type->options & FNCALL_OPTION_VARARG)) { snprintf(output, CF_BUFSIZE, "Argument template mismatch handling function %s(", fp->name); RlistShow(stderr, expargs); fprintf(stderr, ")\n"); rp = expargs; for (int i = 0; i < argnum; i++) { printf(" arg[%d] range %s\t", i, fncall_type->args[i].pattern); if (rp != NULL) { RvalShow(stdout, rp->val); rp = rp->next; } else { printf(" ? "); } printf("\n"); } FatalError(ctx, "Bad arguments"); } return (*fncall_type->impl) (ctx, fp, expargs); }
void PromiseBanner(Promise *pp) { char handle[CF_MAXVARSIZE]; const char *sp; if ((sp = PromiseGetHandle(pp)) || (sp = PromiseID(pp))) { strncpy(handle, sp, CF_MAXVARSIZE - 1); } else { strcpy(handle, "(enterprise only)"); } CfOut(OUTPUT_LEVEL_VERBOSE, "", "\n"); CfOut(OUTPUT_LEVEL_VERBOSE, "", " .........................................................\n"); if (VERBOSE || DEBUG) { printf("%s> Promise's handle: %s\n", VPREFIX, handle); printf("%s> Promise made by: \"%s\"", VPREFIX, pp->promiser); } if (pp->promisee.item) { if (VERBOSE) { printf("\n%s> Promise made to (stakeholders): ", VPREFIX); RvalShow(stdout, pp->promisee); } } if (VERBOSE) { printf("\n"); } if (pp->ref) { CfOut(OUTPUT_LEVEL_VERBOSE, "", "\n"); CfOut(OUTPUT_LEVEL_VERBOSE, "", " Comment: %s\n", pp->ref); } CfOut(OUTPUT_LEVEL_VERBOSE, "", " .........................................................\n"); CfOut(OUTPUT_LEVEL_VERBOSE, "", "\n"); }
static void KeepPromiseBundles(Policy *policy, GenericAgentConfig *config, const ReportContext *report_context) { Bundle *bp; Rlist *rp, *params; FnCall *fp; char *name; Rval retval; int ok = true; if (config->bundlesequence) { CfOut(OUTPUT_LEVEL_INFORM, "", " >> Using command line specified bundlesequence"); retval = (Rval) { config->bundlesequence, RVAL_TYPE_LIST }; } else if (GetVariable("control_common", "bundlesequence", &retval) == DATA_TYPE_NONE) { // TODO: somewhat frenzied way of telling user about an error CfOut(OUTPUT_LEVEL_ERROR, "", " !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); CfOut(OUTPUT_LEVEL_ERROR, "", " !! No bundlesequence in the common control body"); CfOut(OUTPUT_LEVEL_ERROR, "", " !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); exit(1); } // TODO: should've been checked a long time ago, remove? if (retval.type != RVAL_TYPE_LIST) { FatalError("Promised bundlesequence was not a list"); } for (rp = (Rlist *) retval.item; rp != NULL; rp = rp->next) { switch (rp->type) { case RVAL_TYPE_SCALAR: name = (char *) rp->item; params = NULL; if (strcmp(name, CF_NULL_VALUE) == 0) { continue; } break; case RVAL_TYPE_FNCALL: fp = (FnCall *) rp->item; name = (char *) fp->name; params = (Rlist *) fp->args; break; default: name = NULL; params = NULL; CfOut(OUTPUT_LEVEL_ERROR, "", "Illegal item found in bundlesequence: "); RvalShow(stdout, (Rval) { rp->item, rp->type }); printf(" = %c\n", rp->type); ok = false; break; } if (!config->ignore_missing_bundles) { if (!(PolicyGetBundle(policy, NULL, "agent", name) || (PolicyGetBundle(policy, NULL, "common", name)))) { CfOut(OUTPUT_LEVEL_ERROR, "", "Bundle \"%s\" listed in the bundlesequence was not found\n", name); ok = false; } } } if (!ok) { FatalError("Errors in agent bundles"); } if (VERBOSE || DEBUG) { printf("%s> -> Bundlesequence => ", VPREFIX); RvalShow(stdout, retval); printf("\n"); } /* If all is okay, go ahead and evaluate */ for (rp = (Rlist *) retval.item; rp != NULL; rp = rp->next) { switch (rp->type) { case RVAL_TYPE_FNCALL: fp = (FnCall *) rp->item; name = (char *) fp->name; params = (Rlist *) fp->args; break; default: name = (char *) rp->item; params = NULL; break; } if ((bp = PolicyGetBundle(policy, NULL, "agent", name)) || (bp = PolicyGetBundle(policy, NULL, "common", name))) { char ns[CF_BUFSIZE]; snprintf(ns,CF_BUFSIZE,"%s_meta", name); NewScope(ns); SetBundleOutputs(bp->name); AugmentScope(bp->name, bp->ns, bp->args, params); BannerBundle(bp, params); THIS_BUNDLE = bp->name; DeletePrivateClassContext(); // Each time we change bundle ScheduleAgentOperations(bp, report_context); ResetBundleOutputs(bp->name); } } }
Promise *DeRefCopyPromise(EvalContext *ctx, const Promise *pp) { Promise *pcopy; Rval returnval; if (pp->promisee.item) { CfDebug("CopyPromise(%s->", pp->promiser); if (DEBUG) { RvalShow(stdout, pp->promisee); } CfDebug("\n"); } else { CfDebug("CopyPromise(%s->)\n", pp->promiser); } pcopy = xcalloc(1, sizeof(Promise)); if (pp->promiser) { pcopy->promiser = xstrdup(pp->promiser); } if (pp->promisee.item) { pcopy->promisee = RvalCopy(pp->promisee); if (pcopy->promisee.type == RVAL_TYPE_LIST) { Rlist *rval_list = RvalRlistValue(pcopy->promisee); RlistFlatten(ctx, &rval_list); pcopy->promisee.item = rval_list; } } if (pp->classes) { pcopy->classes = xstrdup(pp->classes); } /* FIXME: may it happen? */ if ((pp->promisee.item != NULL && pcopy->promisee.item == NULL)) { ProgrammingError("Unable to copy promise"); } pcopy->parent_promise_type = pp->parent_promise_type; pcopy->offset.line = pp->offset.line; pcopy->comment = pp->comment ? xstrdup(pp->comment) : NULL; pcopy->has_subbundles = pp->has_subbundles; pcopy->conlist = SeqNew(10, ConstraintDestroy); pcopy->org_pp = pp->org_pp; pcopy->offset = pp->offset; CfDebug("Copying promise constraints\n\n"); /* No further type checking should be necessary here, already done by CheckConstraintTypeMatch */ for (size_t i = 0; i < SeqLength(pp->conlist); i++) { Constraint *cp = SeqAt(pp->conlist, i); Body *bp = NULL; FnCall *fp = NULL; char *bodyname = NULL; /* A body template reference could look like a scalar or fn to the parser w/w () */ Policy *policy = PolicyFromPromise(pp); Seq *bodies = policy ? policy->bodies : NULL; switch (cp->rval.type) { case RVAL_TYPE_SCALAR: bodyname = (char *) cp->rval.item; if (cp->references_body) { bp = IsBody(bodies, PromiseGetNamespace(pp), bodyname); } fp = NULL; break; case RVAL_TYPE_FNCALL: fp = (FnCall *) cp->rval.item; bodyname = fp->name; bp = IsBody(bodies, PromiseGetNamespace(pp), bodyname); break; default: bp = NULL; fp = NULL; bodyname = NULL; break; } /* First case is: we have a body template to expand lval = body(args), .. */ if (bp) { EvalContextStackPushBodyFrame(ctx, bp); if (strcmp(bp->type, cp->lval) != 0) { Log(LOG_LEVEL_ERR, "Body type mismatch for body reference \"%s\" in promise at line %zu of %s (%s != %s)\n", bodyname, pp->offset.line, PromiseGetBundle(pp)->source_path, bp->type, cp->lval); } /* Keep the referent body type as a boolean for convenience when checking later */ { Constraint *cp_copy = PromiseAppendConstraint(pcopy, cp->lval, (Rval) {xstrdup("true"), RVAL_TYPE_SCALAR }, cp->classes, false); cp_copy->offset = cp->offset; } CfDebug("Handling body-lval \"%s\"\n", cp->lval); if (bp->args != NULL) { /* There are arguments to insert */ if (fp == NULL || fp->args == NULL) { Log(LOG_LEVEL_ERR, "Argument mismatch for body reference \"%s\" in promise at line %zu of %s", bodyname, pp->offset.line, PromiseGetBundle(pp)->source_path); } if (fp && bp && fp->args && bp->args && !ScopeMapBodyArgs(ctx, "body", fp->args, bp->args)) { Log(LOG_LEVEL_ERR, "Number of arguments does not match for body reference \"%s\" in promise at line %zu of %s\n", bodyname, pp->offset.line, PromiseGetBundle(pp)->source_path); } for (size_t k = 0; k < SeqLength(bp->conlist); k++) { Constraint *scp = SeqAt(bp->conlist, k); CfDebug("Doing arg-mapped sublval = %s (promises.c)\n", scp->lval); returnval = ExpandPrivateRval(ctx, "body", scp->rval); { Constraint *scp_copy = PromiseAppendConstraint(pcopy, scp->lval, returnval, scp->classes, false); scp_copy->offset = scp->offset; } } ScopeClear("body"); } else { /* No arguments to deal with or body undeclared */ if (fp != NULL) { Log(LOG_LEVEL_ERR, "An apparent body \"%s()\" was undeclared or could have incorrect args, but used in a promise near line %zu of %s (possible unquoted literal value)", bodyname, pp->offset.line, PromiseGetBundle(pp)->source_path); } else { for (size_t k = 0; k < SeqLength(bp->conlist); k++) { Constraint *scp = SeqAt(bp->conlist, k); CfDebug("Doing sublval = %s (promises.c)\n", scp->lval); Rval newrv = RvalCopy(scp->rval); if (newrv.type == RVAL_TYPE_LIST) { Rlist *new_list = RvalRlistValue(newrv); RlistFlatten(ctx, &new_list); newrv.item = new_list; } { Constraint *scp_copy = PromiseAppendConstraint(pcopy, scp->lval, newrv, scp->classes, false); scp_copy->offset = scp->offset; } } } } EvalContextStackPopFrame(ctx); } else { Policy *policy = PolicyFromPromise(pp); if (cp->references_body && !IsBundle(policy->bundles, bodyname)) { Log(LOG_LEVEL_ERR, "Apparent body \"%s()\" was undeclared, but used in a promise near line %zu of %s (possible unquoted literal value)", bodyname, pp->offset.line, PromiseGetBundle(pp)->source_path); } Rval newrv = RvalCopy(cp->rval); if (newrv.type == RVAL_TYPE_LIST) { Rlist *new_list = RvalRlistValue(newrv); RlistFlatten(ctx, &new_list); newrv.item = new_list; } { Constraint *cp_copy = PromiseAppendConstraint(pcopy, cp->lval, newrv, cp->classes, false); cp_copy->offset = cp->offset; } } } return pcopy; }