void cfPS(EvalContext *ctx, LogLevel level, PromiseResult status, const Promise *pp, Attributes attr, const char *fmt, ...) { /* * This stub implementation of cfPS delegates to the new logging backend. * * Due to the fact very little of the code has been converted, this code * does a full initialization and shutdown of logging subsystem for each * cfPS. * * Instead, LoggingInit should be called at the moment EvalContext is * created, LoggingPromiseEnter/LoggingPromiseFinish should be called around * ExpandPromise and LoggingFinish should be called when EvalContext is * going to be destroyed. * * But it requires all calls to cfPS to be eliminated. */ /* FIXME: Ensure that NULL pp is never passed into cfPS */ if (pp) { PromiseLoggingInit(ctx); PromiseLoggingPromiseEnter(ctx, pp); if (level == LOG_LEVEL_ERR) { LogPromiseContext(ctx, pp); } } va_list ap; va_start(ap, fmt); VLog(level, fmt, ap); va_end(ap); if (pp) { char *last_msg = PromiseLoggingPromiseFinish(ctx, pp); PromiseLoggingFinish(ctx); /* Now complete the exits status classes and auditing */ ClassAuditLog(ctx, pp, attr, status); UpdatePromiseComplianceStatus(status, pp, last_msg); free(last_msg); } }
PromiseResult VerifyVarPromise(EvalContext *ctx, const Promise *pp, bool allow_duplicates) { ConvergeVariableOptions opts = CollectConvergeVariableOptions(ctx, pp, allow_duplicates); if (!opts.should_converge) { return PROMISE_RESULT_NOOP; } Attributes a = { {0} }; // More consideration needs to be given to using these //a.transaction = GetTransactionConstraints(pp); a.classes = GetClassDefinitionConstraints(ctx, pp); VarRef *ref = VarRefParseFromBundle(pp->promiser, PromiseGetBundle(pp)); if (strcmp("meta", pp->parent_promise_type->name) == 0) { VarRefSetMeta(ref, true); } DataType existing_value_type = CF_DATA_TYPE_NONE; const void *const existing_value = IsExpandable(pp->promiser) ? NULL : EvalContextVariableGet(ctx, ref, &existing_value_type); PromiseResult result = PROMISE_RESULT_NOOP; Rval rval = opts.cp_save->rval; if (rval.item != NULL) { DataType data_type = DataTypeFromString(opts.cp_save->lval); if (opts.cp_save->rval.type == RVAL_TYPE_FNCALL) { FnCall *fp = RvalFnCallValue(rval); const FnCallType *fn = FnCallTypeGet(fp->name); if (!fn) { assert(false && "Canary: should have been caught before this point"); FatalError(ctx, "While setting variable '%s' in bundle '%s', unknown function '%s'", pp->promiser, PromiseGetBundle(pp)->name, fp->name); } if (fn->dtype != DataTypeFromString(opts.cp_save->lval)) { FatalError(ctx, "While setting variable '%s' in bundle '%s', variable declared type '%s' but function '%s' returns type '%s'", pp->promiser, PromiseGetBundle(pp)->name, opts.cp_save->lval, fp->name, DataTypeToString(fn->dtype)); } if (existing_value_type != CF_DATA_TYPE_NONE) { // Already did this VarRefDestroy(ref); return PROMISE_RESULT_NOOP; } FnCallResult res = FnCallEvaluate(ctx, PromiseGetPolicy(pp), fp, pp); if (res.status == FNCALL_FAILURE) { /* We do not assign variables to failed fn calls */ RvalDestroy(res.rval); VarRefDestroy(ref); return PROMISE_RESULT_NOOP; } else { rval = res.rval; } } else { Buffer *conv = BufferNew(); bool malformed = false, misprint = false; if (strcmp(opts.cp_save->lval, "int") == 0) { long int asint = IntFromString(opts.cp_save->rval.item); if (asint == CF_NOINT) { malformed = true; } else if (0 > BufferPrintf(conv, "%ld", asint)) { misprint = true; } else { rval = RvalNew(BufferData(conv), opts.cp_save->rval.type); } } else if (strcmp(opts.cp_save->lval, "real") == 0) { double real_value; if (!DoubleFromString(opts.cp_save->rval.item, &real_value)) { malformed = true; } else if (0 > BufferPrintf(conv, "%lf", real_value)) { misprint = true; } else { rval = RvalNew(BufferData(conv), opts.cp_save->rval.type); } } else { rval = RvalCopy(opts.cp_save->rval); } BufferDestroy(conv); if (malformed) { /* Arises when opts->cp_save->rval.item isn't yet expanded. */ /* Has already been logged by *FromString */ VarRefDestroy(ref); return PromiseResultUpdate(result, PROMISE_RESULT_FAIL); } else if (misprint) { /* Even though no problems with memory allocation can * get here, there might be other problems. */ UnexpectedError("Problems writing to buffer"); VarRefDestroy(ref); return PROMISE_RESULT_NOOP; } else if (rval.type == RVAL_TYPE_LIST) { Rlist *rval_list = RvalRlistValue(rval); RlistFlatten(ctx, &rval_list); rval.item = rval_list; } } if (Epimenides(ctx, PromiseGetBundle(pp)->ns, PromiseGetBundle(pp)->name, pp->promiser, rval, 0)) { Log(LOG_LEVEL_ERR, "Variable '%s' contains itself indirectly - an unkeepable promise", pp->promiser); exit(EXIT_FAILURE); } else { /* See if the variable needs recursively expanding again */ Rval returnval = EvaluateFinalRval(ctx, PromiseGetPolicy(pp), ref->ns, ref->scope, rval, true, pp); RvalDestroy(rval); // freed before function exit rval = returnval; } if (existing_value_type != CF_DATA_TYPE_NONE) { if (!opts.ok_redefine) /* only on second iteration, else we ignore broken promises */ { if (THIS_AGENT_TYPE == AGENT_TYPE_COMMON && !CompareRval(existing_value, DataTypeToRvalType(existing_value_type), rval.item, rval.type)) { switch (rval.type) { case RVAL_TYPE_SCALAR: Log(LOG_LEVEL_VERBOSE, "Redefinition of a constant scalar '%s', was '%s' now '%s'", pp->promiser, (const char *)existing_value, RvalScalarValue(rval)); PromiseRef(LOG_LEVEL_VERBOSE, pp); break; case RVAL_TYPE_LIST: { Log(LOG_LEVEL_VERBOSE, "Redefinition of a constant list '%s'", pp->promiser); Writer *w = StringWriter(); RlistWrite(w, existing_value); char *oldstr = StringWriterClose(w); Log(LOG_LEVEL_VERBOSE, "Old value '%s'", oldstr); free(oldstr); w = StringWriter(); RlistWrite(w, rval.item); char *newstr = StringWriterClose(w); Log(LOG_LEVEL_VERBOSE, " New value '%s'", newstr); free(newstr); PromiseRef(LOG_LEVEL_VERBOSE, pp); } break; case RVAL_TYPE_CONTAINER: case RVAL_TYPE_FNCALL: case RVAL_TYPE_NOPROMISEE: break; } } RvalDestroy(rval); VarRefDestroy(ref); return result; } } if (IsCf3VarString(pp->promiser)) { // Unexpanded variables, we don't do anything with RvalDestroy(rval); VarRefDestroy(ref); return result; } if (!IsValidVariableName(pp->promiser)) { Log(LOG_LEVEL_ERR, "Variable identifier contains illegal characters"); PromiseRef(LOG_LEVEL_ERR, pp); RvalDestroy(rval); VarRefDestroy(ref); return result; } if (rval.type == RVAL_TYPE_LIST) { if (opts.drop_undefined) { for (Rlist *rp = RvalRlistValue(rval); rp; rp = rp->next) { if (IsNakedVar(RlistScalarValue(rp), '@')) { free(rp->val.item); rp->val.item = xstrdup(CF_NULL_VALUE); } } } for (const Rlist *rp = RvalRlistValue(rval); rp; rp = rp->next) { switch (rp->val.type) { case RVAL_TYPE_SCALAR: break; default: // Cannot assign variable because value is a list containing a non-scalar item VarRefDestroy(ref); RvalDestroy(rval); return result; } } } if (ref->num_indices > 0) { if (data_type == CF_DATA_TYPE_CONTAINER) { char *lval_str = VarRefToString(ref, true); Log(LOG_LEVEL_ERR, "Cannot assign a container to an indexed variable name '%s'. Should be assigned to '%s' instead", lval_str, ref->lval); free(lval_str); VarRefDestroy(ref); RvalDestroy(rval); return result; } else { DataType existing_type = CF_DATA_TYPE_NONE; VarRef *base_ref = VarRefCopyIndexless(ref); if (EvalContextVariableGet(ctx, ref, &existing_type) && existing_type == CF_DATA_TYPE_CONTAINER) { char *lval_str = VarRefToString(ref, true); char *base_ref_str = VarRefToString(base_ref, true); Log(LOG_LEVEL_ERR, "Cannot assign value to indexed variable name '%s', because a container is already assigned to the base name '%s'", lval_str, base_ref_str); free(lval_str); free(base_ref_str); VarRefDestroy(base_ref); VarRefDestroy(ref); RvalDestroy(rval); return result; } VarRefDestroy(base_ref); } } DataType required_datatype = DataTypeFromString(opts.cp_save->lval); if (rval.type != DataTypeToRvalType(required_datatype)) { char *ref_str = VarRefToString(ref, true); char *value_str = RvalToString(rval); Log(LOG_LEVEL_ERR, "Variable '%s' expected a variable of type '%s', but was given incompatible value '%s'", ref_str, DataTypeToString(required_datatype), value_str); PromiseRef(LOG_LEVEL_ERR, pp); free(ref_str); free(value_str); VarRefDestroy(ref); RvalDestroy(rval); return PromiseResultUpdate(result, PROMISE_RESULT_FAIL); } if (!EvalContextVariablePut(ctx, ref, rval.item, required_datatype, "source=promise")) { Log(LOG_LEVEL_VERBOSE, "Unable to converge %s.%s value (possibly empty or infinite regression)", ref->scope, pp->promiser); PromiseRef(LOG_LEVEL_VERBOSE, pp); result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL); } else { Rlist *promise_meta = PromiseGetConstraintAsList(ctx, "meta", pp); if (promise_meta) { StringSet *class_meta = EvalContextVariableTags(ctx, ref); Buffer *print; for (const Rlist *rp = promise_meta; rp; rp = rp->next) { StringSetAdd(class_meta, xstrdup(RlistScalarValue(rp))); print = StringSetToBuffer(class_meta, ','); Log(LOG_LEVEL_DEBUG, "Added tag %s to class %s, tags now [%s]", RlistScalarValue(rp), pp->promiser, BufferData(print)); BufferDestroy(print); } } } } else { Log(LOG_LEVEL_ERR, "Variable %s has no promised value", pp->promiser); Log(LOG_LEVEL_ERR, "Rule from %s at/before line %llu", PromiseGetBundle(pp)->source_path, (unsigned long long)opts.cp_save->offset.line); result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL); } /* * FIXME: Variable promise are exempt from normal evaluation logic still, so * they are not pushed to evaluation stack before being evaluated. Due to * this reason, we cannot call cfPS here to set classes, as it will error * out with ProgrammingError. * * In order to support 'classes' body for variables as well, we call * ClassAuditLog explicitly. */ ClassAuditLog(ctx, pp, a, result); VarRefDestroy(ref); RvalDestroy(rval); return result; }
PromiseResult VerifyReportPromise(EvalContext *ctx, const Promise *pp) { CfLock thislock; char unique_name[CF_EXPANDSIZE]; Attributes a = GetReportsAttributes(ctx, pp); // We let AcquireLock worry about making a unique name snprintf(unique_name, CF_EXPANDSIZE - 1, "%s", pp->promiser); thislock = AcquireLock(ctx, unique_name, VUQNAME, CFSTARTTIME, a.transaction, pp, false); // Handle return values before locks, as we always do this if (a.report.result) { // User-unwritable value last-result contains the useresult if (strlen(a.report.result) > 0) { snprintf(unique_name, CF_BUFSIZE, "last-result[%s]", a.report.result); } else { snprintf(unique_name, CF_BUFSIZE, "last-result"); } VarRef *ref = VarRefParseFromBundle(unique_name, PromiseGetBundle(pp)); EvalContextVariablePut(ctx, ref, pp->promiser, CF_DATA_TYPE_STRING, "source=bundle"); VarRefDestroy(ref); if (thislock.lock) { YieldCurrentLock(thislock); } return PROMISE_RESULT_NOOP; } if (thislock.lock == NULL) { return PROMISE_RESULT_SKIPPED; } PromiseBanner(ctx, pp); if (a.transaction.action == cfa_warn) { cfPS(ctx, LOG_LEVEL_WARNING, PROMISE_RESULT_WARN, pp, a, "Need to repair reports promise: %s", pp->promiser); YieldCurrentLock(thislock); return PROMISE_RESULT_WARN; } if (a.report.to_file) { ReportToFile(a.report.to_file, pp->promiser); } else { ReportToLog(pp->promiser); } PromiseResult result = PROMISE_RESULT_NOOP; if (a.report.haveprintfile) { if (!PrintFile(a.report.filename, a.report.numlines)) { result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL); } } YieldCurrentLock(thislock); ClassAuditLog(ctx, pp, a, result); return result; }
void cfPS(EvalContext *ctx, OutputLevel level, PromiseResult status, const char *errstr, const Promise *pp, Attributes attr, const char *fmt, ...) { if ((fmt == NULL) || (strlen(fmt) == 0)) { return; } va_list ap; va_start(ap, fmt); char buffer[CF_BUFSIZE]; vsnprintf(buffer, CF_BUFSIZE - 1, fmt, ap); va_end(ap); if (Chop(buffer, CF_EXPANDSIZE) == -1) { CfOut(OUTPUT_LEVEL_ERROR, "", "Chop was called on a string that seemed to have no terminator"); } Item *mess = NULL; AppendItem(&mess, buffer, NULL); if ((errstr == NULL) || (strlen(errstr) > 0)) { char output[CF_BUFSIZE]; snprintf(output, CF_BUFSIZE - 1, " !!! System reports error for %s: \"%s\"", errstr, GetErrorStr()); AppendItem(&mess, output, NULL); } if (level == OUTPUT_LEVEL_ERROR) { AmendErrorMessageWithPromiseInformation(ctx, &mess, pp); } int verbose = (attr.transaction.report_level == OUTPUT_LEVEL_VERBOSE) || VERBOSE; switch (level) { case OUTPUT_LEVEL_INFORM: if (INFORM || (attr.transaction.report_level == OUTPUT_LEVEL_INFORM) || VERBOSE || (attr.transaction.report_level == OUTPUT_LEVEL_VERBOSE) || DEBUG) { LogListStdout(mess, verbose); } if (attr.transaction.log_level == OUTPUT_LEVEL_INFORM) { SystemLog(mess, level); } break; case OUTPUT_LEVEL_VERBOSE: if (VERBOSE || (attr.transaction.log_level == OUTPUT_LEVEL_VERBOSE) || DEBUG) { LogListStdout(mess, verbose); } if (attr.transaction.log_level == OUTPUT_LEVEL_VERBOSE) { SystemLog(mess, level); } break; case OUTPUT_LEVEL_ERROR: LogListStdout(mess, verbose); if (attr.transaction.log_level == OUTPUT_LEVEL_ERROR) { SystemLog(mess, level); } break; case OUTPUT_LEVEL_NONE: break; default: ProgrammingError("Unexpected output level (%d) passed to cfPS", level); } if (pp != NULL) { LogPromiseResult(pp->promiser, pp->promisee.type, pp->promisee.item, status, attr.transaction.log_level, mess); } /* Now complete the exits status classes and auditing */ if (pp != NULL) { ClassAuditLog(ctx, pp, attr, status); UpdatePromiseComplianceStatus(status, pp, buffer); } DeleteItemList(mess); }
void VerifyVarPromise(EvalContext *ctx, const Promise *pp, bool allow_duplicates) { ConvergeVariableOptions opts = CollectConvergeVariableOptions(ctx, pp, allow_duplicates); if (!opts.should_converge) { return; } char *scope = NULL; if (strcmp("meta", pp->parent_promise_type->name) == 0) { scope = StringConcatenate(2, PromiseGetBundle(pp)->name, "_meta"); } else { scope = xstrdup(PromiseGetBundle(pp)->name); } //More consideration needs to be given to using these //a.transaction = GetTransactionConstraints(pp); Attributes a = { {0} }; a.classes = GetClassDefinitionConstraints(ctx, pp); Rval existing_var_rval; DataType existing_var_type = DATA_TYPE_NONE; EvalContextVariableGet(ctx, (VarRef) { NULL, scope, pp->promiser }, &existing_var_rval, &existing_var_type); Buffer *qualified_scope = BufferNew(); int result = 0; if (strcmp(PromiseGetNamespace(pp), "default") == 0) { result = BufferSet(qualified_scope, scope, strlen(scope)); if (result < 0) { /* * Even though there will be no problems with memory allocation, there * might be other problems. */ UnexpectedError("Problems writing to buffer"); free(scope); BufferDestroy(&qualified_scope); return; } } else { if (strchr(scope, ':') == NULL) { result = BufferPrintf(qualified_scope, "%s:%s", PromiseGetNamespace(pp), scope); if (result < 0) { /* * Even though there will be no problems with memory allocation, there * might be other problems. */ UnexpectedError("Problems writing to buffer"); free(scope); BufferDestroy(&qualified_scope); return; } } else { result = BufferSet(qualified_scope, scope, strlen(scope)); if (result < 0) { /* * Even though there will be no problems with memory allocation, there * might be other problems. */ UnexpectedError("Problems writing to buffer"); free(scope); BufferDestroy(&qualified_scope); return; } } } PromiseResult promise_result; Rval rval = opts.cp_save->rval; if (rval.item != NULL) { FnCall *fp = (FnCall *) rval.item; if (opts.cp_save->rval.type == RVAL_TYPE_FNCALL) { if (existing_var_type != DATA_TYPE_NONE) { // Already did this free(scope); BufferDestroy(&qualified_scope); return; } FnCallResult res = FnCallEvaluate(ctx, fp, pp); if (res.status == FNCALL_FAILURE) { /* We do not assign variables to failed fn calls */ RvalDestroy(res.rval); free(scope); BufferDestroy(&qualified_scope); return; } else { rval = res.rval; } } else { Buffer *conv = BufferNew(); if (strcmp(opts.cp_save->lval, "int") == 0) { result = BufferPrintf(conv, "%ld", IntFromString(opts.cp_save->rval.item)); if (result < 0) { /* * Even though there will be no problems with memory allocation, there * might be other problems. */ UnexpectedError("Problems writing to buffer"); free(scope); BufferDestroy(&qualified_scope); BufferDestroy(&conv); return; } rval = RvalCopy((Rval) {(char *)BufferData(conv), opts.cp_save->rval.type}); } else if (strcmp(opts.cp_save->lval, "real") == 0) { double real_value = 0.0; if (DoubleFromString(opts.cp_save->rval.item, &real_value)) { result = BufferPrintf(conv, "%lf", real_value); } else { result = BufferPrintf(conv, "(double conversion error)"); } if (result < 0) { /* * Even though there will be no problems with memory allocation, there * might be other problems. */ UnexpectedError("Problems writing to buffer"); free(scope); BufferDestroy(&conv); BufferDestroy(&qualified_scope); return; } rval = RvalCopy((Rval) {(char *)BufferData(conv), opts.cp_save->rval.type}); } else { rval = RvalCopy(opts.cp_save->rval); } if (rval.type == RVAL_TYPE_LIST) { Rlist *rval_list = RvalRlistValue(rval); RlistFlatten(ctx, &rval_list); rval.item = rval_list; } BufferDestroy(&conv); } if (Epimenides(ctx, PromiseGetBundle(pp)->name, pp->promiser, rval, 0)) { Log(LOG_LEVEL_ERR, "Variable \"%s\" contains itself indirectly - an unkeepable promise", pp->promiser); exit(1); } else { /* See if the variable needs recursively expanding again */ Rval returnval = EvaluateFinalRval(ctx, BufferData(qualified_scope), rval, true, pp); RvalDestroy(rval); // freed before function exit rval = returnval; } if (existing_var_type != DATA_TYPE_NONE) { if (opts.ok_redefine) /* only on second iteration, else we ignore broken promises */ { ScopeDeleteVariable(BufferData(qualified_scope), pp->promiser); } else if ((THIS_AGENT_TYPE == AGENT_TYPE_COMMON) && (CompareRval(existing_var_rval, rval) == false)) { switch (rval.type) { case RVAL_TYPE_SCALAR: Log(LOG_LEVEL_VERBOSE, "Redefinition of a constant scalar \"%s\" (was %s now %s)", pp->promiser, RvalScalarValue(existing_var_rval), RvalScalarValue(rval)); PromiseRef(LOG_LEVEL_VERBOSE, pp); break; case RVAL_TYPE_LIST: { Log(LOG_LEVEL_VERBOSE, "Redefinition of a constant list \"%s\".", pp->promiser); Writer *w = StringWriter(); RlistWrite(w, existing_var_rval.item); char *oldstr = StringWriterClose(w); Log(LOG_LEVEL_VERBOSE, "Old value: %s", oldstr); free(oldstr); w = StringWriter(); RlistWrite(w, rval.item); char *newstr = StringWriterClose(w); Log(LOG_LEVEL_VERBOSE, " New value: %s", newstr); free(newstr); PromiseRef(LOG_LEVEL_VERBOSE, pp); } break; default: break; } } } if (IsCf3VarString(pp->promiser)) { // Unexpanded variables, we don't do anything with RvalDestroy(rval); free(scope); BufferDestroy(&qualified_scope); return; } if (!FullTextMatch("[a-zA-Z0-9_\200-\377.]+(\\[.+\\])*", pp->promiser)) { Log(LOG_LEVEL_ERR, "Variable identifier contains illegal characters"); PromiseRef(LOG_LEVEL_ERR, pp); RvalDestroy(rval); free(scope); BufferDestroy(&qualified_scope); return; } if (opts.drop_undefined && rval.type == RVAL_TYPE_LIST) { for (Rlist *rp = rval.item; rp != NULL; rp = rp->next) { if (IsNakedVar(rp->item, '@')) { free(rp->item); rp->item = xstrdup(CF_NULL_VALUE); } } } if (!EvalContextVariablePut(ctx, (VarRef) { NULL, BufferData(qualified_scope), pp->promiser }, rval, DataTypeFromString(opts.cp_save->lval))) { Log(LOG_LEVEL_VERBOSE, "Unable to converge %s.%s value (possibly empty or infinite regression)", BufferData(qualified_scope), pp->promiser); PromiseRef(LOG_LEVEL_VERBOSE, pp); promise_result = PROMISE_RESULT_FAIL; } else { promise_result = PROMISE_RESULT_CHANGE; } } else { Log(LOG_LEVEL_ERR, "Variable %s has no promised value", pp->promiser); Log(LOG_LEVEL_ERR, "Rule from %s at/before line %zu", PromiseGetBundle(pp)->source_path, opts.cp_save->offset.line); promise_result = PROMISE_RESULT_FAIL; } /* * FIXME: Variable promise are exempt from normal evaluation logic still, so * they are not pushed to evaluation stack before being evaluated. Due to * this reason, we cannot call cfPS here to set classes, as it will error * out with ProgrammingError. * * In order to support 'classes' body for variables as well, we call * ClassAuditLog explicitly. */ ClassAuditLog(ctx, pp, a, promise_result); free(scope); BufferDestroy(&qualified_scope); RvalDestroy(rval); }
void cfPS(OutputLevel level, char status, char *errstr, const Promise *pp, Attributes attr, char *fmt, ...) { va_list ap; char buffer[CF_BUFSIZE], output[CF_BUFSIZE], *v, handle[CF_MAXVARSIZE]; const char *sp; Item *mess = NULL; int verbose; Rval retval; if ((fmt == NULL) || (strlen(fmt) == 0)) { return; } va_start(ap, fmt); vsnprintf(buffer, CF_BUFSIZE - 1, fmt, ap); va_end(ap); if (Chop(buffer, CF_EXPANDSIZE) == -1) { CfOut(OUTPUT_LEVEL_ERROR, "", "Chop was called on a string that seemed to have no terminator"); } AppendItem(&mess, buffer, NULL); if ((errstr == NULL) || (strlen(errstr) > 0)) { snprintf(output, CF_BUFSIZE - 1, " !!! System reports error for %s: \"%s\"", errstr, GetErrorStr()); AppendItem(&mess, output, NULL); } if (level == OUTPUT_LEVEL_ERROR) { if (GetVariable("control_common", "version", &retval) != DATA_TYPE_NONE) { v = (char *) retval.item; } else { v = "not specified"; } if ((sp = ConstraintGetRvalValue("handle", pp, RVAL_TYPE_SCALAR)) || (sp = PromiseID(pp))) { strncpy(handle, sp, CF_MAXVARSIZE - 1); } else { strcpy(handle, "(unknown)"); } if (INFORM || VERBOSE || DEBUG) { snprintf(output, CF_BUFSIZE - 1, "I: Report relates to a promise with handle \"%s\"", handle); AppendItem(&mess, output, NULL); } if (pp && (pp->audit)) { snprintf(output, CF_BUFSIZE - 1, "I: Made in version \'%s\' of \'%s\' near line %zu", v, pp->audit->filename, pp->offset.line); } else { snprintf(output, CF_BUFSIZE - 1, "I: Promise is made internally by cfengine"); } AppendItem(&mess, output, NULL); if (pp != NULL) { switch (pp->promisee.type) { case RVAL_TYPE_SCALAR: snprintf(output, CF_BUFSIZE - 1, "I: The promise was made to: \'%s\'", (char *) pp->promisee.item); AppendItem(&mess, output, NULL); break; case RVAL_TYPE_LIST: snprintf(output, CF_BUFSIZE - 1, "I: The promise was made to (stakeholders): "); RlistPrint(output+strlen(output), CF_BUFSIZE, (Rlist *)pp->promisee.item); AppendItem(&mess, output, NULL); break; default: break; } if (pp->ref) { snprintf(output, CF_BUFSIZE - 1, "I: Comment: %s\n", pp->ref); AppendItem(&mess, output, NULL); } } } verbose = (attr.transaction.report_level == OUTPUT_LEVEL_VERBOSE) || VERBOSE; switch (level) { case OUTPUT_LEVEL_INFORM: if (INFORM || verbose || DEBUG || (attr.transaction.report_level == OUTPUT_LEVEL_INFORM)) { LogList(stdout, mess, verbose); } if (attr.transaction.log_level == OUTPUT_LEVEL_INFORM) { MakeLog(mess, level); } break; case OUTPUT_LEVEL_REPORTING: case OUTPUT_LEVEL_CMDOUT: if (attr.report.to_file) { FileReport(mess, verbose, attr.report.to_file); } else { LogList(stdout, mess, verbose); } if (attr.transaction.log_level == OUTPUT_LEVEL_INFORM) { MakeLog(mess, level); } break; case OUTPUT_LEVEL_VERBOSE: if (verbose || DEBUG) { LogList(stdout, mess, verbose); } if (attr.transaction.log_level == OUTPUT_LEVEL_VERBOSE) { MakeLog(mess, level); } break; case OUTPUT_LEVEL_ERROR: if (attr.report.to_file) { FileReport(mess, verbose, attr.report.to_file); } else { LogList(stdout, mess, verbose); } if (attr.transaction.log_level == OUTPUT_LEVEL_ERROR) { MakeLog(mess, level); } break; case OUTPUT_LEVEL_LOG: MakeLog(mess, level); break; default: break; } if (pp != NULL) { LogPromiseResult(pp->promiser, pp->promisee.type, pp->promisee.item, status, attr.transaction.log_level, mess); } /* Now complete the exits status classes and auditing */ if (pp != NULL) { ClassAuditLog(pp, attr, status, buffer); } DeleteItemList(mess); }
void cfPS(enum cfreport level, char status, char *errstr, const Promise *pp, Attributes attr, char *fmt, ...) { va_list ap; char buffer[CF_BUFSIZE], output[CF_BUFSIZE], *v, handle[CF_MAXVARSIZE]; const char *sp; Item *ip, *mess = NULL; int verbose; Rval retval; if ((fmt == NULL) || (strlen(fmt) == 0)) { return; } va_start(ap, fmt); vsnprintf(buffer, CF_BUFSIZE - 1, fmt, ap); va_end(ap); Chop(buffer); AppendItem(&mess, buffer, NULL); if ((errstr == NULL) || (strlen(errstr) > 0)) { snprintf(output, CF_BUFSIZE - 1, " !!! System reports error for %s: \"%s\"", errstr, GetErrorStr()); AppendItem(&mess, output, NULL); } if (level == cf_error) { if (GetVariable("control_common", "version", &retval) != cf_notype) { v = (char *) retval.item; } else { v = "not specified"; } if ((sp = GetConstraintValue("handle", pp, CF_SCALAR)) || (sp = PromiseID(pp))) { strncpy(handle, sp, CF_MAXVARSIZE - 1); } else { strcpy(handle, "(unknown)"); } if (INFORM || VERBOSE || DEBUG) { snprintf(output, CF_BUFSIZE - 1, "I: Report relates to a promise with handle \"%s\"", handle); AppendItem(&mess, output, NULL); } if (pp && pp->audit) { snprintf(output, CF_BUFSIZE - 1, "I: Made in version \'%s\' of \'%s\' near line %zu", v, pp->audit->filename, pp->offset.line); } else { snprintf(output, CF_BUFSIZE - 1, "I: Promise is made internally by cfengine"); } AppendItem(&mess, output, NULL); if (pp != NULL) { switch (pp->promisee.rtype) { case CF_SCALAR: snprintf(output, CF_BUFSIZE - 1, "I: The promise was made to: \'%s\'", (char *) pp->promisee.item); AppendItem(&mess, output, NULL); break; case CF_LIST: snprintf(output, CF_BUFSIZE - 1, "I: The promise was made to (stakeholders): "); PrintRlist(output+strlen(output), CF_BUFSIZE, (Rlist *)pp->promisee.item); AppendItem(&mess, output, NULL); break; } if (pp->ref) { snprintf(output, CF_BUFSIZE - 1, "I: Comment: %s\n", pp->ref); AppendItem(&mess, output, NULL); } } } verbose = (attr.transaction.report_level == cf_verbose) || VERBOSE; switch (level) { case cf_inform: if (INFORM || verbose || DEBUG || attr.transaction.report_level == cf_inform) { LogList(stdout, mess, verbose); } if (attr.transaction.log_level == cf_inform) { MakeLog(mess, level); } break; case cf_reporting: case cf_cmdout: if (attr.report.to_file) { FileReport(mess, verbose, attr.report.to_file); } else { LogList(stdout, mess, verbose); } if (attr.transaction.log_level == cf_inform) { MakeLog(mess, level); } break; case cf_verbose: if (verbose || DEBUG) { LogList(stdout, mess, verbose); } if (attr.transaction.log_level == cf_verbose) { MakeLog(mess, level); } break; case cf_error: if (attr.report.to_file) { FileReport(mess, verbose, attr.report.to_file); } else { LogList(stdout, mess, verbose); } if (attr.transaction.log_level == cf_error) { MakeLog(mess, level); } break; case cf_log: MakeLog(mess, level); break; default: break; } if (pp != NULL) { LogPromiseResult(pp->promiser, pp->promisee.rtype, pp->promisee.item, status, attr.transaction.log_level, mess); } /* Now complete the exits status classes and auditing */ if (pp != NULL) { for (ip = mess; ip != NULL; ip = ip->next) { ClassAuditLog(pp, attr, ip->name, status, buffer); } } DeleteItemList(mess); }