Ejemplo n.º 1
0
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);
    }
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
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);
}
Ejemplo n.º 5
0
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);
}
Ejemplo n.º 6
0
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);
}
Ejemplo n.º 7
0
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);
}