Пример #1
0
void RvalDestroy(Rval rval)
{
    if (rval.item == NULL)
    {
        return;
    }

    switch (rval.type)
    {
    case RVAL_TYPE_SCALAR:
        ThreadLock(cft_lock);
        free(RvalScalarValue(rval));
        ThreadUnlock(cft_lock);
        return;

    case RVAL_TYPE_LIST:
        RlistDestroy(RvalRlistValue(rval));
        return;

    case RVAL_TYPE_FNCALL:
        FnCallDestroy(RvalFnCallValue(rval));
        break;

    case RVAL_TYPE_CONTAINER:
        JsonDestroy(RvalContainerValue(rval));
        break;

    case RVAL_TYPE_NOPROMISEE:
        return;
    }
}
Пример #2
0
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;
    }
}
Пример #3
0
void RvalDestroy(Rval rval)
{
    Rlist *clist, *next = NULL;

    if (rval.item == NULL)
    {
        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:
        return;
    }
}
Пример #4
0
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;
}
Пример #5
0
int ScopeMapBodyArgs(EvalContext *ctx, const char *scopeid, Rlist *give, const Rlist *take)
{
    Rlist *rpg = NULL;
    const Rlist *rpt = NULL;
    FnCall *fp;
    DataType dtg = DATA_TYPE_NONE, dtt = DATA_TYPE_NONE;
    char *lval;
    void *rval;
    int len1, len2;

    CfDebug("MapBodyArgs(begin)\n");

    len1 = RlistLen(give);
    len2 = RlistLen(take);

    if (len1 != len2)
    {
        CfOut(OUTPUT_LEVEL_ERROR, "", " !! Argument mismatch in body template give[+args] = %d, take[-args] = %d", len1, len2);
        return false;
    }

    for (rpg = give, rpt = take; rpg != NULL && rpt != NULL; rpg = rpg->next, rpt = rpt->next)
    {
        dtg = StringDataType(ctx, scopeid, (char *) rpg->item);
        dtt = StringDataType(ctx, scopeid, (char *) rpt->item);

        if (dtg != dtt)
        {
            CfOut(OUTPUT_LEVEL_ERROR, "", "Type mismatch between logical/formal parameters %s/%s\n", (char *) rpg->item,
                  (char *) rpt->item);
            CfOut(OUTPUT_LEVEL_ERROR, "", "%s is %s whereas %s is %s\n", (char *) rpg->item, CF_DATATYPES[dtg],
                  (char *) rpt->item, CF_DATATYPES[dtt]);
        }

        switch (rpg->type)
        {
        case RVAL_TYPE_SCALAR:
            lval = (char *) rpt->item;
            rval = rpg->item;
            CfDebug("MapBodyArgs(SCALAR,%s,%s)\n", lval, (char *) rval);
            EvalContextVariablePut(ctx, (VarRef) { NULL, scopeid, lval }, (Rval) { rval, RVAL_TYPE_SCALAR }, dtg);
            break;

        case RVAL_TYPE_LIST:
            lval = (char *) rpt->item;
            rval = rpg->item;
            EvalContextVariablePut(ctx, (VarRef) { NULL, scopeid, lval }, (Rval) { rval, RVAL_TYPE_LIST }, dtg);
            break;

        case RVAL_TYPE_FNCALL:
            fp = (FnCall *) rpg->item;
            dtg = DATA_TYPE_NONE;
            {
                const FnCallType *fncall_type = FnCallTypeGet(fp->name);
                if (fncall_type)
                {
                    dtg = fncall_type->dtype;
                }
            }

            FnCallResult res = FnCallEvaluate(ctx, fp, NULL);

            if (res.status == FNCALL_FAILURE && THIS_AGENT_TYPE != AGENT_TYPE_COMMON)
            {
                // Unresolved variables
                if (VERBOSE)
                {
                    printf
                        (" !! Embedded function argument does not resolve to a name - probably too many evaluation levels for ");
                    FnCallShow(stdout, fp);
                    printf(" (try simplifying)\n");
                }
            }
            else
            {
                FnCallDestroy(fp);

                rpg->item = res.rval.item;
                rpg->type = res.rval.type;

                lval = (char *) rpt->item;
                rval = rpg->item;

                EvalContextVariablePut(ctx, (VarRef) { NULL, scopeid, lval }, (Rval) {rval, RVAL_TYPE_SCALAR }, dtg);
            }

            break;

        default:
            /* Nothing else should happen */
            ProgrammingError("Software error: something not a scalar/function in argument literal");
        }
    }

    CfDebug("MapBodyArgs(end)\n");
    return true;
}
Пример #6
0
int ScopeMapBodyArgs(EvalContext *ctx, const char *ns, const char *scope, Rlist *give, const Rlist *take)
{
    Rlist *rpg = NULL;
    const Rlist *rpt = NULL;
    FnCall *fp;
    DataType dtg = DATA_TYPE_NONE, dtt = DATA_TYPE_NONE;
    char *lval;
    void *rval;
    int len1, len2;

    len1 = RlistLen(give);
    len2 = RlistLen(take);

    if (len1 != len2)
    {
        Log(LOG_LEVEL_ERR, "Argument mismatch in body template give[+args] = %d, take[-args] = %d", len1, len2);
        return false;
    }

    for (rpg = give, rpt = take; rpg != NULL && rpt != NULL; rpg = rpg->next, rpt = rpt->next)
    {
        dtg = StringDataType(ctx, (char *) rpg->item);
        dtt = StringDataType(ctx, (char *) rpt->item);

        if (dtg != dtt)
        {
            Log(LOG_LEVEL_ERR, "Type mismatch between logical/formal parameters %s/%s", (char *) rpg->item,
                  (char *) rpt->item);
            Log(LOG_LEVEL_ERR, "%s is %s whereas %s is %s", (char *) rpg->item, DataTypeToString(dtg),
                  (char *) rpt->item, DataTypeToString(dtt));
        }

        switch (rpg->type)
        {
        case RVAL_TYPE_SCALAR:
            {
                lval = (char *) rpt->item;
                rval = rpg->item;
                VarRef *ref = VarRefParseFromNamespaceAndScope(lval, ns, scope, CF_NS, '.');
                EvalContextVariablePut(ctx, ref, (Rval) { rval, RVAL_TYPE_SCALAR }, dtg);
            }
            break;

        case RVAL_TYPE_LIST:
            {
                lval = (char *) rpt->item;
                rval = rpg->item;
                VarRef *ref = VarRefParseFromNamespaceAndScope(lval, ns, scope, CF_NS, '.');
                EvalContextVariablePut(ctx, ref, (Rval) { rval, RVAL_TYPE_LIST }, dtg);
                VarRefDestroy(ref);
            }
            break;

        case RVAL_TYPE_FNCALL:
            fp = (FnCall *) rpg->item;
            dtg = DATA_TYPE_NONE;
            {
                const FnCallType *fncall_type = FnCallTypeGet(fp->name);
                if (fncall_type)
                {
                    dtg = fncall_type->dtype;
                }
            }

            FnCallResult res = FnCallEvaluate(ctx, fp, NULL);

            if (res.status == FNCALL_FAILURE && THIS_AGENT_TYPE != AGENT_TYPE_COMMON)
            {
                Log(LOG_LEVEL_VERBOSE, "Embedded function argument does not resolve to a name - probably too many evaluation levels for '%s'",
                    fp->name);
            }
            else
            {
                FnCallDestroy(fp);

                rpg->item = res.rval.item;
                rpg->type = res.rval.type;

                lval = (char *) rpt->item;
                rval = rpg->item;

                VarRef *ref = VarRefParseFromNamespaceAndScope(lval, ns, scope, CF_NS, '.');
                EvalContextVariablePut(ctx, ref, (Rval) {rval, RVAL_TYPE_SCALAR }, dtg);
                VarRefDestroy(ref);
            }

            break;

        default:
            /* Nothing else should happen */
            ProgrammingError("Software error: something not a scalar/function in argument literal");
        }
    }

    return true;
}
Пример #7
0
static void ParserStateReset(ParserState *p, bool discard)
{
    p->agent_type = AGENT_TYPE_COMMON;
    p->warnings = PARSER_WARNING_ALL;
    p->policy = NULL;

    int i = CF_MAX_NESTING;
    while (i-- > 0) /* Clear stacks from top down */
    {
        if (discard)
        {
            free(p->currentfnid[i]);
            RlistDestroy(p->giveargs[i]);
            FnCallDestroy(p->currentfncall[i]);
        }
        else
        {
            assert(!p->currentfnid[i]);
            assert(!p->giveargs[i]);
            assert(!p->currentfncall[i]);
        }
        p->currentfnid[i] = NULL;
        p->giveargs[i] = NULL;
        p->currentfncall[i] = NULL;
    }

    free(p->current_line);
    p->current_line = NULL;
    p->line_no = 1;
    p->line_pos = 1;
    p->error_count = 0;
    p->warning_count = 0;
    p->list_nesting = 0;
    p->arg_nesting = 0;

    free(p->current_namespace);
    p->current_namespace = xstrdup("default");

    p->currentid[0] = '\0';
    if (p->currentstring)
    {
        free(p->currentstring);
    }
    p->currentstring = NULL;
    p->currenttype[0] = '\0';
    if (p->currentclasses)
    {
        free(p->currentclasses);
    }
    p->currentclasses = NULL;
    p->currentRlist = NULL;
    p->currentpromise = NULL;
    p->currentbody = NULL;
    if (p->promiser)
    {
        free(p->promiser);
    }
    p->promiser = NULL;
    p->blockid[0] = '\0';
    p->blocktype[0] = '\0';
    p->rval = RvalNew(NULL, RVAL_TYPE_NOPROMISEE);
}
Пример #8
0
Файл: expand.c Проект: tzz/core
Rval EvaluateFinalRval(EvalContext *ctx, const Policy *policy, const char *ns, const char *scope,
                       Rval rval, bool forcelist, const Promise *pp)
{
    assert(ctx);
    assert(policy);

    Rval returnval, newret;
    if ((rval.type == RVAL_TYPE_SCALAR) && IsNakedVar(rval.item, '@'))        /* Treat lists specially here */
    {
        char naked[CF_MAXVARSIZE];
        GetNaked(naked, rval.item);

        if (!IsExpandable(naked))
        {
            VarRef *ref = VarRefParseFromScope(naked, scope);
            DataType value_type = DATA_TYPE_NONE;
            const void *value = EvalContextVariableGet(ctx, ref, &value_type);

            if (!value || DataTypeToRvalType(value_type) != RVAL_TYPE_LIST)
            {
                returnval = ExpandPrivateRval(ctx, NULL, "this", rval.item, rval.type);
            }
            else
            {
                returnval.item = ExpandList(ctx, ns, scope, value, true);
                returnval.type = RVAL_TYPE_LIST;
            }

            VarRefDestroy(ref);
        }
        else
        {
            returnval = ExpandPrivateRval(ctx, NULL, "this", rval.item, rval.type);
        }
    }
    else
    {
        if (forcelist)          /* We are replacing scalar @(name) with list */
        {
            returnval = ExpandPrivateRval(ctx, ns, scope, rval.item, rval.type);
        }
        else
        {
            if (FnCallIsBuiltIn(rval))
            {
                returnval = RvalCopy(rval);
            }
            else
            {
                returnval = ExpandPrivateRval(ctx, NULL, "this", rval.item, rval.type);
            }
        }
    }

    switch (returnval.type)
    {
    case RVAL_TYPE_SCALAR:
    case RVAL_TYPE_CONTAINER:
        break;

    case RVAL_TYPE_LIST:
        for (Rlist *rp = RvalRlistValue(returnval); rp; rp = rp->next)
        {
            if (rp->val.type == RVAL_TYPE_FNCALL)
            {
                FnCall *fp = RlistFnCallValue(rp);
                FnCallResult res = FnCallEvaluate(ctx, policy, fp, pp);

                FnCallDestroy(fp);
                rp->val = res.rval;
            }
            else
            {
                if (EvalContextStackCurrentPromise(ctx))
                {
                    if (IsCf3VarString(RlistScalarValue(rp)))
                    {
                        newret = ExpandPrivateRval(ctx, NULL, "this", rp->val.item, rp->val.type);
                        free(rp->val.item);
                        rp->val.item = newret.item;
                    }
                }
            }

            /* returnval unchanged */
        }
        break;

    case RVAL_TYPE_FNCALL:
        if (FnCallIsBuiltIn(returnval))
        {
            FnCall *fp = RvalFnCallValue(returnval);
            returnval = FnCallEvaluate(ctx, policy, fp, pp).rval;
            FnCallDestroy(fp);
        }
        break;

    default:
        returnval.item = NULL;
        returnval.type = RVAL_TYPE_NOPROMISEE;
        break;
    }

    return returnval;
}
Пример #9
0
Rval EvaluateFinalRval(EvalContext *ctx, const Policy *policy,
                       const char *ns, const char *scope,
                       Rval rval, bool forcelist, const Promise *pp)
{
    assert(ctx);
    assert(policy);
    Rval returnval;

    /* Treat lists specially. */
    if (rval.type == RVAL_TYPE_SCALAR && IsNakedVar(rval.item, '@'))
    {
        char naked[CF_MAXVARSIZE];
        GetNaked(naked, rval.item);

        if (IsExpandable(naked))                /* example: @(blah_$(blue)) */
        {
            returnval = ExpandPrivateRval(ctx, NULL, "this", rval.item, rval.type);
        }
        else
        {
            VarRef *ref = VarRefParseFromScope(naked, scope);
            DataType value_type;
            const void *value = EvalContextVariableGet(ctx, ref, &value_type);
            VarRefDestroy(ref);

            if (DataTypeToRvalType(value_type) == RVAL_TYPE_LIST)
            {
                returnval.item = ExpandList(ctx, ns, scope, value, true);
                returnval.type = RVAL_TYPE_LIST;
            }
            else
            {
                returnval = ExpandPrivateRval(ctx, NULL, "this", rval.item, rval.type);
            }
        }
    }
    else if (forcelist) /* We are replacing scalar @(name) with list */
    {
        returnval = ExpandPrivateRval(ctx, ns, scope, rval.item, rval.type);
    }
    else if (FnCallIsBuiltIn(rval))
    {
        returnval = RvalCopy(rval);
    }
    else
    {
        returnval = ExpandPrivateRval(ctx, NULL, "this", rval.item, rval.type);
    }

    switch (returnval.type)
    {
    case RVAL_TYPE_SCALAR:
    case RVAL_TYPE_CONTAINER:
        break;

    case RVAL_TYPE_LIST:
        for (Rlist *rp = RvalRlistValue(returnval); rp; rp = rp->next)
        {
            switch (rp->val.type)
            {
            case RVAL_TYPE_FNCALL:
            {
                FnCall *fp = RlistFnCallValue(rp);
                rp->val = FnCallEvaluate(ctx, policy, fp, pp).rval;
                FnCallDestroy(fp);
                break;
            }
            case RVAL_TYPE_SCALAR:
                if (EvalContextStackCurrentPromise(ctx) &&
                    IsCf3VarString(RlistScalarValue(rp)))
                {
                    void *prior = rp->val.item;
                    rp->val = ExpandPrivateRval(ctx, NULL, "this",
                                                prior, RVAL_TYPE_SCALAR);
                    free(prior);
                }
                /* else: returnval unchanged. */
                break;
            default:
                assert(!"Bad type for entry in Rlist");
            }
        }
        break;

    case RVAL_TYPE_FNCALL:
        if (FnCallIsBuiltIn(returnval))
        {
            FnCall *fp = RvalFnCallValue(returnval);
            returnval = FnCallEvaluate(ctx, policy, fp, pp).rval;
            FnCallDestroy(fp);
        }
        break;

    default:
        assert(returnval.item == NULL); /* else we're leaking it */
        returnval.item = NULL;
        returnval.type = RVAL_TYPE_NOPROMISEE;
        break;
    }

    return returnval;
}
Пример #10
0
static bool EvalClassExpression(EvalContext *ctx, Constraint *cp, const Promise *pp)
{
    assert(pp);

    if (cp == NULL) // ProgrammingError ?  We'll crash RSN anyway ...
    {
        Log(LOG_LEVEL_ERR,
            "EvalClassExpression internal diagnostic discovered an ill-formed condition");
    }

    if (!IsDefinedClass(ctx, pp->classes))
    {
        return false;
    }

    if (IsDefinedClass(ctx, pp->promiser))
    {
        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)
    {
        Rval rval;
        FnCall *fp;

    case RVAL_TYPE_FNCALL:
        fp = RvalFnCallValue(cp->rval);
        /* Special expansion of functions for control, best effort only: */
        FnCallResult res = FnCallEvaluate(ctx, PromiseGetPolicy(pp), fp, pp);

        FnCallDestroy(fp);
        cp->rval = res.rval;
        break;

    case RVAL_TYPE_LIST:
        for (Rlist *rp = cp->rval.item; rp != NULL; rp = rp->next)
        {
            rval = EvaluateFinalRval(ctx, PromiseGetPolicy(pp), NULL,
                                     "this", rp->val, true, pp);
            RvalDestroy(rp->val);
            rp->val = rval;
        }
        break;

    default:
        rval = ExpandPrivateRval(ctx, NULL, "this", cp->rval.item, cp->rval.type);
        RvalDestroy(cp->rval);
        cp->rval = rval;
        break;
    }

    if (strcmp(cp->lval, "expression") == 0)
    {
        return (cp->rval.type == RVAL_TYPE_SCALAR &&
                IsDefinedClass(ctx, RvalScalarValue(cp->rval)));
    }

    if (strcmp(cp->lval, "not") == 0)
    {
        return (cp->rval.type == RVAL_TYPE_SCALAR &&
                !IsDefinedClass(ctx, RvalScalarValue(cp->rval)));
    }

    /* 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 selection
    if (strcmp(cp->lval, "select_class") == 0)
    {
        return SelectClass(ctx, cp->rval.item, pp);
    }

    // Class distributions
    if (strcmp(cp->lval, "dist") == 0)
    {
        return DistributeClass(ctx, cp->rval.item, pp);
    }

    /* Combine with and/or/xor: */
    if (strcmp(cp->lval, "or") == 0)
    {
        return EvalBoolCombination(ctx, cp->rval.item, c_or);
    }
    else if (strcmp(cp->lval, "and") == 0)
    {
        return EvalBoolCombination(ctx, cp->rval.item, c_and);
    }
    else if (strcmp(cp->lval, "xor") == 0)
    {
        return EvalBoolCombination(ctx, cp->rval.item, c_xor);
    }

    return false;
}
Пример #11
0
void ScopeMapBodyArgs(EvalContext *ctx, const Body *body, const Rlist *args)
{
    const Rlist *arg = NULL;
    const Rlist *param = NULL;

    for (arg = args, param = body->args; arg != NULL && param != NULL; arg = arg->next, param = param->next)
    {
        DataType arg_type = StringDataType(ctx, RlistScalarValue(arg));
        DataType param_type = StringDataType(ctx, RlistScalarValue(param));

        if (arg_type != param_type)
        {
            Log(LOG_LEVEL_ERR, "Type mismatch between logical/formal parameters %s/%s", (char *) arg->item,
                  (char *) param->item);
            Log(LOG_LEVEL_ERR, "%s is %s whereas %s is %s", (char *) arg->item, DataTypeToString(arg_type),
                  (char *) param->item, DataTypeToString(param_type));
        }

        switch (arg->type)
        {
        case RVAL_TYPE_SCALAR:
            {
                const char *lval = RlistScalarValue(param);
                void *rval = arg->item;
                VarRef *ref = VarRefParseFromNamespaceAndScope(lval, NULL, "body", CF_NS, '.');
                EvalContextVariablePut(ctx, ref, (Rval) { rval, RVAL_TYPE_SCALAR }, arg_type);
            }
            break;

        case RVAL_TYPE_LIST:
            {
                const char *lval = RlistScalarValue(param->item);
                void *rval = arg->item;
                VarRef *ref = VarRefParseFromNamespaceAndScope(lval, NULL, "body", CF_NS, '.');
                EvalContextVariablePut(ctx, ref, (Rval) { rval, RVAL_TYPE_LIST }, arg_type);
                VarRefDestroy(ref);
            }
            break;

        case RVAL_TYPE_FNCALL:
            {
                FnCall *fp = arg->item;
                arg_type = DATA_TYPE_NONE;
                {
                    const FnCallType *fncall_type = FnCallTypeGet(fp->name);
                    if (fncall_type)
                    {
                        arg_type = fncall_type->dtype;
                    }
                }

                FnCallResult res = FnCallEvaluate(ctx, fp, NULL);

                if (res.status == FNCALL_FAILURE && THIS_AGENT_TYPE != AGENT_TYPE_COMMON)
                {
                    Log(LOG_LEVEL_VERBOSE, "Embedded function argument does not resolve to a name - probably too many evaluation levels for '%s'",
                        fp->name);
                }
                else
                {
                    FnCallDestroy(fp);

                    const char *lval = RlistScalarValue(param);
                    void *rval = res.rval.item;

                    VarRef *ref = VarRefParseFromNamespaceAndScope(lval, NULL, "body", CF_NS, '.');
                    EvalContextVariablePut(ctx, ref, (Rval) {rval, RVAL_TYPE_SCALAR }, res.rval.type);
                    VarRefDestroy(ref);
                }
            }

            break;

        default:
            /* Nothing else should happen */
            ProgrammingError("Software error: something not a scalar/function in argument literal");
        }
    }
}
Пример #12
0
static int EvalClassExpression(EvalContext *ctx, Constraint *cp, const Promise *pp)
{
    assert(pp);

    int result_and = true;
    int result_or = false;
    int result_xor = 0;
    int result = 0, total = 0;
    char buffer[CF_MAXVARSIZE];
    Rlist *rp;

    if (cp == NULL) // ProgrammingError ?  We'll crash RSN anyway ...
    {
        Log(LOG_LEVEL_ERR, "EvalClassExpression internal diagnostic discovered an ill-formed condition");
    }

    if (!IsDefinedClass(ctx, pp->classes))
    {
        return false;
    }

    if (IsDefinedClass(ctx, pp->promiser))
    {
        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)
    {
        Rval rval;
        FnCall *fp;

    case RVAL_TYPE_FNCALL:
        fp = RvalFnCallValue(cp->rval);
        /* Special expansion of functions for control, best effort only: */
        FnCallResult res = FnCallEvaluate(ctx, PromiseGetPolicy(pp), 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, PromiseGetPolicy(pp), NULL, "this", rp->val, true, pp);
            RvalDestroy(rp->val);
            rp->val = rval;
        }
        break;

    default:
        rval = ExpandPrivateRval(ctx, NULL, "this", cp->rval.item, cp->rval.type);
        RvalDestroy(cp->rval);
        cp->rval = rval;
        break;
    }

    if (strcmp(cp->lval, "expression") == 0)
    {
        return (cp->rval.type == RVAL_TYPE_SCALAR &&
                IsDefinedClass(ctx, RvalScalarValue(cp->rval)));
    }

    if (strcmp(cp->lval, "not") == 0)
    {
        return (cp->rval.type == RVAL_TYPE_SCALAR &&
                !IsDefinedClass(ctx, RvalScalarValue(cp->rval)));
    }

// 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) StringHash(splay, 0, 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)
            {
                EvalContextClassPutSoft(ctx, RlistScalarValue(rp), CONTEXT_SCOPE_NAMESPACE, "source=promise");
                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(RlistScalarValue(rp));

            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(RlistScalarValue(rp))) / ((double) total);
            cum += prob;

            if (fluct < cum)
            {
                break;
            }
        }

        snprintf(buffer, CF_MAXVARSIZE - 1, "%s_%s", pp->promiser, RlistScalarValue(rp));

        if (strcmp(PromiseGetBundle(pp)->type, "common") == 0)
        {
            EvalContextClassPutSoft(ctx, buffer, CONTEXT_SCOPE_NAMESPACE, "source=promise");
        }
        else
        {
            EvalContextClassPutSoft(ctx, buffer, CONTEXT_SCOPE_BUNDLE, "source=promise");
        }

        return true;
    }

    /* and/or/xor expressions */

    enum {
        c_or = 0, c_and, c_xor
    } logic;

    if (strcmp(cp->lval, "or") == 0)
    {
        logic = c_or;
    }
    else if (strcmp(cp->lval, "and") == 0)
    {
        logic = c_and;
    }
    else if (strcmp(cp->lval, "xor") == 0)
    {
        logic = c_xor;
    }

    for (rp = (Rlist *) cp->rval.item; rp != NULL; rp = rp->next)
    {
        // tolerate unexpanded entries here and interpret as "class not set"
        if (rp->val.type != RVAL_TYPE_SCALAR)
        {
            result = false;
        }
        else
        {
            result = IsDefinedClass(ctx, RlistScalarValue(rp));
        }

        // shortcut and and or
        switch (logic)
        {
        case c_or:
            if (result)
            {
                return true;
            }
            break;
        case c_and:
            if (!result)
            {
                return false;
            }
            break;
        default:
            break;
        }
        result_and = result_and && result;
        result_or = result_or || result;
        result_xor ^= result;
    }

// Class combinations

    switch (logic)
    {
    case c_or:
        return result_or;
    case c_xor:
        return result_xor == 1;
    case c_and:
        return result_and;
    }

    return false;
}