Esempio n. 1
0
PromiseResult VerifyMethod(EvalContext *ctx, char *attrname, Attributes a, const Promise *pp)
{
    Bundle *bp;
    void *vp;
    FnCall *fp;
    char method_name[CF_EXPANDSIZE];
    Rlist *args = NULL;
    CfLock thislock;
    char lockname[CF_BUFSIZE];

    if (a.havebundle)
    {
        if ((vp = PromiseGetConstraintAsRval(pp, attrname, RVAL_TYPE_FNCALL)))
        {
            fp = (FnCall *) vp;
            ExpandScalar(ctx, PromiseGetBundle(pp)->ns, PromiseGetBundle(pp)->name, fp->name, method_name);
            args = fp->args;
        }
        else if ((vp = PromiseGetConstraintAsRval(pp, attrname, RVAL_TYPE_SCALAR)))
        {
            ExpandScalar(ctx, PromiseGetBundle(pp)->ns, PromiseGetBundle(pp)->name, (char *) vp, method_name);
            args = NULL;
        }
        else
        {
            return PROMISE_RESULT_NOOP;
        }
    }

    GetLockName(lockname, "method", pp->promiser, args);

    thislock = AcquireLock(ctx, lockname, VUQNAME, CFSTARTTIME, a.transaction, pp, false);
    if (thislock.lock == NULL)
    {
        return PROMISE_RESULT_SKIPPED;
    }

    PromiseBanner(pp);

    char ns[CF_MAXVARSIZE] = "";
    char bundle_name[CF_MAXVARSIZE] = "";
    SplitScopeName(method_name, ns, bundle_name);
    
    bp = PolicyGetBundle(PolicyFromPromise(pp), EmptyString(ns) ? NULL : ns, "agent", bundle_name);
    if (!bp)
    {
        bp = PolicyGetBundle(PolicyFromPromise(pp), EmptyString(ns) ? NULL : ns, "common", bundle_name);
    }

    PromiseResult result = PROMISE_RESULT_NOOP;
    if (bp)
    {
        BannerSubBundle(bp, args);

        EvalContextStackPushBundleFrame(ctx, bp, args, a.inherit);
        BundleResolve(ctx, bp);

        result = ScheduleAgentOperations(ctx, bp);

        GetReturnValue(ctx, bp, pp);

        EvalContextStackPopFrame(ctx);

        switch (result)
        {
        case PROMISE_RESULT_FAIL:
            cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_FAIL, pp, a, "Method '%s' failed in some repairs or aborted", bp->name);
            break;

        case PROMISE_RESULT_CHANGE:
            cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_CHANGE, pp, a, "Method '%s' invoked repairs", bp->name);
            break;

        default:
            cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, a, "Method '%s' verified", bp->name);
            break;

        }

        for (const Rlist *rp = bp->args; rp; rp = rp->next)
        {
            const char *lval = RlistScalarValue(rp);
            VarRef *ref = VarRefParseFromBundle(lval, bp);
            EvalContextVariableRemove(ctx, ref);
            VarRefDestroy(ref);
        }
    }
    else
    {
        if (IsCf3VarString(method_name))
        {
            Log(LOG_LEVEL_ERR,
                  "A variable seems to have been used for the name of the method. In this case, the promiser also needs to contain the unique name of the method");
        }
        if (bp && (bp->name))
        {
            cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Method '%s' was used but was not defined", bp->name);
            result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
        }
        else
        {
            cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a,
                 "A method attempted to use a bundle '%s' that was apparently not defined", method_name);
            result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
        }
    }

    
    YieldCurrentLock(thislock);
    return result;
}
Esempio n. 2
0
Promise *DeRefCopyPromise(EvalContext *ctx, const Promise *pp)
{
    Promise *pcopy;

    pcopy = xcalloc(1, sizeof(Promise));

    if (pp->promiser)
    {
        pcopy->promiser = xstrdup(pp->promiser);
    }

    if (pp->promisee.item)
    {
        pcopy->promisee = RvalCopy(pp->promisee);
        if (pcopy->promisee.type == RVAL_TYPE_LIST)
        {
            Rlist *rval_list = RvalRlistValue(pcopy->promisee);
            RlistFlatten(ctx, &rval_list);
            pcopy->promisee.item = rval_list;
        }
    }

    if (pp->classes)
    {
        pcopy->classes = xstrdup(pp->classes);
    }

/* FIXME: may it happen? */
    if ((pp->promisee.item != NULL && pcopy->promisee.item == NULL))
    {
        ProgrammingError("Unable to copy promise");
    }

    pcopy->parent_promise_type = pp->parent_promise_type;
    pcopy->offset.line = pp->offset.line;
    pcopy->comment = pp->comment ? xstrdup(pp->comment) : NULL;
    pcopy->has_subbundles = pp->has_subbundles;
    pcopy->conlist = SeqNew(10, ConstraintDestroy);
    pcopy->org_pp = pp->org_pp;
    pcopy->offset = pp->offset;

/* No further type checking should be necessary here, already done by CheckConstraintTypeMatch */

    for (size_t i = 0; i < SeqLength(pp->conlist); i++)
    {
        Constraint *cp = SeqAt(pp->conlist, i);

        Body *bp = NULL;
        FnCall *fp = NULL;

        /* A body template reference could look like a scalar or fn to the parser w/w () */
        const Policy *policy = PolicyFromPromise(pp);
        Seq *bodies = policy ? policy->bodies : NULL;

        char body_ns[CF_MAXVARSIZE] = "";
        char body_name[CF_MAXVARSIZE] = "";

        switch (cp->rval.type)
        {
        case RVAL_TYPE_SCALAR:
            if (cp->references_body)
            {
                SplitScopeName(RvalScalarValue(cp->rval), body_ns, body_name);
                if (EmptyString(body_ns))
                {
                    strncpy(body_ns, PromiseGetNamespace(pp), CF_MAXVARSIZE);
                }
                bp = IsBody(bodies, body_ns, body_name);
            }
            fp = NULL;
            break;
        case RVAL_TYPE_FNCALL:
            fp = RvalFnCallValue(cp->rval);
            SplitScopeName(fp->name, body_ns, body_name);
            if (EmptyString(body_ns))
            {
                strncpy(body_ns, PromiseGetNamespace(pp), CF_MAXVARSIZE);
            }
            bp = IsBody(bodies, body_ns, body_name);
            break;
        default:
            bp = NULL;
            fp = NULL;
            break;
        }

        /* First case is: we have a body template to expand lval = body(args), .. */

        if (bp)
        {
            EvalContextStackPushBodyFrame(ctx, pcopy, bp, fp ? fp->args : NULL);

            if (strcmp(bp->type, cp->lval) != 0)
            {
                Log(LOG_LEVEL_ERR,
                    "Body type mismatch for body reference '%s' in promise "
                    "at line %llu of file '%s', '%s' does not equal '%s'",
                    body_name, (unsigned long long)pp->offset.line,
                    PromiseGetBundle(pp)->source_path, bp->type, cp->lval);
            }

            /* Keep the referent body type as a boolean for convenience when checking later */

            if (IsDefinedClass(ctx, cp->classes))
            {
                Constraint *cp_copy = PromiseAppendConstraint(pcopy, cp->lval, (Rval) {xstrdup("true"), RVAL_TYPE_SCALAR }, false);
                cp_copy->offset = cp->offset;
            }

            if (bp->args != NULL)
            {
                /* There are arguments to insert */

                if (fp == NULL || fp->args == NULL)
                {
                    Log(LOG_LEVEL_ERR,
                        "Argument mismatch for body reference '%s' in promise "
                        "at line %llu of file '%s'",
                        body_name, (unsigned long long) pp->offset.line,
                        PromiseGetBundle(pp)->source_path);
                }

                for (size_t k = 0; k < SeqLength(bp->conlist); k++)
                {
                    Constraint *scp = SeqAt(bp->conlist, k);

                    if (IsDefinedClass(ctx, scp->classes))
                    {
                        Rval returnval = ExpandPrivateRval(ctx, NULL, "body", scp->rval.item, scp->rval.type);
                        Constraint *scp_copy = PromiseAppendConstraint(pcopy, scp->lval, returnval, false);
                        scp_copy->offset = scp->offset;
                    }
                }
            }
            else
            {
                /* No arguments to deal with or body undeclared */

                if (fp != NULL)
                {
                    Log(LOG_LEVEL_ERR,
                        "An apparent body \"%s()\" was undeclared or could "
                        "have incorrect args, but used in a promise near "
                        "line %llu of %s (possible unquoted literal value)",
                        body_name, (unsigned long long) pp->offset.line,
                        PromiseGetBundle(pp)->source_path);
                }
                else
                {
                    for (size_t k = 0; k < SeqLength(bp->conlist); k++)
                    {
                        Constraint *scp = SeqAt(bp->conlist, k);

                        if (IsDefinedClass(ctx, scp->classes))
                        {
                            Rval newrv = RvalCopy(scp->rval);
                            if (newrv.type == RVAL_TYPE_LIST)
                            {
                                Rlist *new_list = RvalRlistValue(newrv);
                                RlistFlatten(ctx, &new_list);
                                newrv.item = new_list;
                            }

                            Constraint *scp_copy = PromiseAppendConstraint(pcopy, scp->lval, newrv, false);
                            scp_copy->offset = scp->offset;
                        }
                    }
                }
            }

            EvalContextStackPopFrame(ctx);
        }
        else
        {
            const Policy *policy = PolicyFromPromise(pp);

            if (cp->references_body &&
                !IsBundle(policy->bundles,
                          EmptyString(body_ns) ? NULL : body_ns, body_name))
            {
                Log(LOG_LEVEL_ERR,
                    "Apparent body \"%s()\" was undeclared, but "
                    "used in a promise near line %llu of %s "
                    "(possible unquoted literal value)",
                    body_name, (unsigned long long)pp->offset.line,
                    PromiseGetBundle(pp)->source_path);
            }

            if (IsDefinedClass(ctx, cp->classes))
            {
                Rval newrv = RvalCopy(cp->rval);
                if (newrv.type == RVAL_TYPE_LIST)
                {
                    Rlist *new_list = RvalRlistValue(newrv);
                    RlistFlatten(ctx, &new_list);
                    newrv.item = new_list;
                }

                Constraint *cp_copy = PromiseAppendConstraint(pcopy, cp->lval, newrv, false);
                cp_copy->offset = cp->offset;
            }
        }
    }

    return pcopy;
}