PromiseResult VerifyMeasurementPromise(EvalContext *ctx, double *measurement, const Promise *pp) { if (EvalContextPromiseIsDone(ctx, pp)) { if (pp->comment) { Log(LOG_LEVEL_VERBOSE, "Skipping static observation '%s' (comment: %s), already done", pp->promiser, pp->comment); } else { Log(LOG_LEVEL_VERBOSE, "Skipping static observation '%s', already done", pp->promiser); } return PROMISE_RESULT_NOOP; } PromiseBanner(pp); Attributes a = GetMeasurementAttributes(ctx, pp); if (!CheckMeasureSanity(a.measure, pp)) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_INTERRUPTED, pp, a, "Measurement promise is not valid"); return PROMISE_RESULT_INTERRUPTED; } return VerifyMeasurement(ctx, measurement, a, pp); }
void VerifyDatabasePromises(EvalContext *ctx, Promise *pp) { Attributes a = { {0} }; if (EvalContextPromiseIsDone(ctx, pp)) { return; } PromiseBanner(pp); a = GetDatabaseAttributes(ctx, pp); if (!CheckDatabaseSanity(a, pp)) { return; } if (strcmp(a.database.type, "sql") == 0) { VerifySQLPromise(ctx, a, pp); return; } if (strcmp(a.database.type, "ms_registry") == 0) { #if defined(__MINGW32__) VerifyRegistryPromise(ctx, a, pp); #endif return; } }
static int EvalClassExpression(EvalContext *ctx, Constraint *cp, Promise *pp) { int result_and = true; int result_or = false; int result_xor = 0; int result = 0, total = 0; char buffer[CF_MAXVARSIZE]; Rlist *rp; FnCall *fp; Rval rval; if (cp == NULL) { Log(LOG_LEVEL_ERR, "EvalClassExpression internal diagnostic discovered an ill-formed condition"); } if (!IsDefinedClass(ctx, pp->classes, PromiseGetNamespace(pp))) { return false; } if (EvalContextPromiseIsDone(ctx, pp)) { return false; } if (IsDefinedClass(ctx, pp->promiser, PromiseGetNamespace(pp))) { if (PromiseGetConstraintAsInt(ctx, "persistence", pp) == 0) { Log(LOG_LEVEL_VERBOSE, " ?> Cancelling cached persistent class %s", pp->promiser); EvalContextHeapPersistentRemove(pp->promiser); } return false; } switch (cp->rval.type) { case RVAL_TYPE_FNCALL: fp = (FnCall *) cp->rval.item; /* Special expansion of functions for control, best effort only */ FnCallResult res = FnCallEvaluate(ctx, fp, pp); FnCallDestroy(fp); cp->rval = res.rval; break; case RVAL_TYPE_LIST: for (rp = (Rlist *) cp->rval.item; rp != NULL; rp = rp->next) { rval = EvaluateFinalRval(ctx, "this", (Rval) {rp->item, rp->type}, true, pp); RvalDestroy((Rval) {rp->item, rp->type}); rp->item = rval.item; rp->type = rval.type; } break; default: rval = ExpandPrivateRval(ctx, "this", cp->rval); RvalDestroy(cp->rval); cp->rval = rval; break; } if (strcmp(cp->lval, "expression") == 0) { if (cp->rval.type != RVAL_TYPE_SCALAR) { return false; } if (IsDefinedClass(ctx, (char *) cp->rval.item, PromiseGetNamespace(pp))) { return true; } else { return false; } } if (strcmp(cp->lval, "not") == 0) { if (cp->rval.type != RVAL_TYPE_SCALAR) { return false; } if (IsDefinedClass(ctx, (char *) cp->rval.item, PromiseGetNamespace(pp))) { return false; } else { return true; } } // Class selection if (strcmp(cp->lval, "select_class") == 0) { char splay[CF_MAXVARSIZE]; int i, n; double hash; total = 0; for (rp = (Rlist *) cp->rval.item; rp != NULL; rp = rp->next) { total++; } if (total == 0) { Log(LOG_LEVEL_ERR, "No classes to select on RHS"); PromiseRef(LOG_LEVEL_ERR, pp); return false; } snprintf(splay, CF_MAXVARSIZE, "%s+%s+%ju", VFQNAME, VIPADDRESS, (uintmax_t)getuid()); hash = (double) OatHash(splay, CF_HASHTABLESIZE); n = (int) (total * hash / (double) CF_HASHTABLESIZE); for (rp = (Rlist *) cp->rval.item, i = 0; rp != NULL; rp = rp->next, i++) { if (i == n) { EvalContextHeapAddSoft(ctx, rp->item, PromiseGetNamespace(pp)); return true; } } } /* If we get here, anything remaining on the RHS must be a clist */ if (cp->rval.type != RVAL_TYPE_LIST) { Log(LOG_LEVEL_ERR, "RHS of promise body attribute '%s' is not a list", cp->lval); PromiseRef(LOG_LEVEL_ERR, pp); return true; } // Class distributions if (strcmp(cp->lval, "dist") == 0) { for (rp = (Rlist *) cp->rval.item; rp != NULL; rp = rp->next) { result = IntFromString(rp->item); if (result < 0) { Log(LOG_LEVEL_ERR, "Non-positive integer in class distribution"); PromiseRef(LOG_LEVEL_ERR, pp); return false; } total += result; } if (total == 0) { Log(LOG_LEVEL_ERR, "An empty distribution was specified on RHS"); PromiseRef(LOG_LEVEL_ERR, pp); return false; } double fluct = drand48(); double cum = 0.0; for (rp = (Rlist *) cp->rval.item; rp != NULL; rp = rp->next) { double prob = ((double) IntFromString(rp->item)) / ((double) total); cum += prob; if (fluct < cum) { break; } } snprintf(buffer, CF_MAXVARSIZE - 1, "%s_%s", pp->promiser, (char *) rp->item); /* FIXME: figure why explicit mark and get rid of it */ EvalContextMarkPromiseDone(ctx, pp); if (strcmp(PromiseGetBundle(pp)->type, "common") == 0) { EvalContextHeapAddSoft(ctx, buffer, PromiseGetNamespace(pp)); } else { EvalContextStackFrameAddSoft(ctx, buffer); } return true; } /* and/or/xor expressions */ for (rp = (Rlist *) cp->rval.item; rp != NULL; rp = rp->next) { if (rp->type != RVAL_TYPE_SCALAR) { return false; } result = IsDefinedClass(ctx, (char *) (rp->item), PromiseGetNamespace(pp)); result_and = result_and && result; result_or = result_or || result; result_xor ^= result; } // Class combinations if (strcmp(cp->lval, "or") == 0) { return result_or; } if (strcmp(cp->lval, "xor") == 0) { return (result_xor == 1) ? true : false; } if (strcmp(cp->lval, "and") == 0) { return result_and; } return false; }
/** * @brief Collects variable constraints controlling how the promise should be converged */ static ConvergeVariableOptions CollectConvergeVariableOptions(EvalContext *ctx, const Promise *pp, bool allow_redefine) { ConvergeVariableOptions opts = { 0 }; opts.should_converge = false; opts.drop_undefined = false; opts.ok_redefine = allow_redefine; opts.cp_save = NULL; if (EvalContextPromiseIsDone(ctx, pp)) { return opts; } if (!IsDefinedClass(ctx, pp->classes)) { return opts; } int num_values = 0; for (size_t i = 0; i < SeqLength(pp->conlist); i++) { Constraint *cp = SeqAt(pp->conlist, i); if (strcmp(cp->lval, "comment") == 0) { continue; } if (cp->rval.item == NULL) { continue; } if (strcmp(cp->lval, "ifvarclass") == 0) { switch (cp->rval.type) { case RVAL_TYPE_SCALAR: if (!IsDefinedClass(ctx, cp->rval.item)) { return opts; } break; case RVAL_TYPE_FNCALL: { bool excluded = false; /* eval it: e.g. ifvarclass => not("a_class") */ Rval res = FnCallEvaluate(ctx, PromiseGetPolicy(pp), cp->rval.item, pp).rval; /* Don't continue unless function was evaluated properly */ if (res.type != RVAL_TYPE_SCALAR) { RvalDestroy(res); return opts; } excluded = !IsDefinedClass(ctx, res.item); RvalDestroy(res); if (excluded) { return opts; } } break; default: Log(LOG_LEVEL_ERR, "Invalid ifvarclass type '%c': should be string or function", cp->rval.type); continue; } continue; } if (strcmp(cp->lval, "policy") == 0) { if (strcmp(cp->rval.item, "ifdefined") == 0) { opts.drop_undefined = true; opts.ok_redefine = false; } else if (strcmp(cp->rval.item, "constant") == 0) { opts.ok_redefine = false; } else { opts.ok_redefine |= true; } opts.ok_redefine &= allow_redefine; } else if (DataTypeFromString(cp->lval) != CF_DATA_TYPE_NONE) { num_values++; opts.cp_save = cp; } } if (opts.cp_save == NULL) { Log(LOG_LEVEL_WARNING, "Variable body for '%s' seems incomplete", pp->promiser); PromiseRef(LOG_LEVEL_INFO, pp); return opts; } if (num_values > 2) { Log(LOG_LEVEL_ERR, "Variable '%s' breaks its own promise with multiple values (code %d)", pp->promiser, num_values); PromiseRef(LOG_LEVEL_ERR, pp); return opts; } opts.should_converge = true; return opts; }