static void test_filter(void) { Rlist *list = NULL; for (int i = 0; i < 10; i++) { char *item = StringFromLong(i); RlistAppend(&list, item, RVAL_TYPE_SCALAR); } assert_int_equal(10, RlistLen(list)); int mod_by = 0; RlistFilter(&list, is_even, &mod_by, free); assert_int_equal(5, RlistLen(list)); int i = 0; for (Rlist *rp = list; rp; rp = rp->next) { int k = StringToLong(rp->val.item); assert_int_equal(i, k); i += 2; } RlistDestroy(list); }
static bool MethodsParseTreeCheck(const Promise *pp, Seq *errors) { bool success = true; for (size_t i = 0; i < SeqLength(pp->conlist); i++) { const Constraint *cp = SeqAt(pp->conlist, i); // ensure: if call and callee are resolved, then they have matching arity if (StringSafeEqual(cp->lval, "usebundle")) { if (cp->rval.type == RVAL_TYPE_FNCALL) { const FnCall *call = (const FnCall *)cp->rval.item; const Bundle *callee = PolicyGetBundle(PolicyFromPromise(pp), NULL, "agent", call->name); if (!callee) { callee = PolicyGetBundle(PolicyFromPromise(pp), NULL, "common", call->name); } if (callee) { if (RlistLen(call->args) != RlistLen(callee->args)) { SeqAppend(errors, PolicyErrorNew(POLICY_ELEMENT_TYPE_CONSTRAINT, cp, POLICY_ERROR_METHODS_BUNDLE_ARITY, call->name, RlistLen(callee->args), RlistLen(call->args))); success = false; } } } } } return success; }
static void test_filter(void) { Rlist *list = NULL; for (int i = 0; i < 10; i++) { void *item = xmemdup(&i, sizeof(int)); RlistAppendAlien(&list, item); } assert_int_equal(10, RlistLen(list)); int mod_by = 0; RlistFilter(&list, is_even, &mod_by, free); assert_int_equal(5, RlistLen(list)); int i = 0; for (Rlist *rp = list; rp; rp = rp->next) { int *k = rp->item; assert_int_equal(i, *k); free(k); rp->item = NULL; i += 2; } RlistDestroy(list); }
PromiseIterator *PromiseIteratorNew(EvalContext *ctx, const Promise *pp, const Rlist *lists, const Rlist *containers) { PromiseIterator *iter = xmalloc(sizeof(PromiseIterator)); iter->vars = SeqNew(RlistLen(lists), DeleteAssoc); iter->var_states = SeqNew(RlistLen(lists), NULL); iter->has_null_list = false; for (const Rlist *rp = lists; rp != NULL; rp = rp->next) { VarRef *ref = VarRefParseFromBundle(RlistScalarValue(rp), PromiseGetBundle(pp)); DataType dtype = CF_DATA_TYPE_NONE; const void *value = EvalContextVariableGet(ctx, ref, &dtype); if (!value) { Log(LOG_LEVEL_ERR, "Couldn't locate variable '%s' apparently in '%s'", RlistScalarValue(rp), PromiseGetBundle(pp)->name); VarRefDestroy(ref); continue; } VarRefDestroy(ref); CfAssoc *new_var = NewAssoc(RlistScalarValue(rp), (Rval) { (void *)value, DataTypeToRvalType(dtype) }, dtype); iter->has_null_list |= !AppendIterationVariable(iter, new_var); } for (const Rlist *rp = containers; rp; rp = rp->next) { VarRef *ref = VarRefParseFromBundle(RlistScalarValue(rp), PromiseGetBundle(pp)); DataType dtype = CF_DATA_TYPE_NONE; const JsonElement *value = EvalContextVariableGet(ctx, ref, &dtype); if (!value) { Log(LOG_LEVEL_ERR, "Couldn't locate variable '%s' apparently in '%s'", RlistScalarValue(rp), PromiseGetBundle(pp)->name); VarRefDestroy(ref); continue; } VarRefDestroy(ref); assert(dtype == CF_DATA_TYPE_CONTAINER); /* Mimics NewAssoc() but bypassing extra copying of ->rval: */ CfAssoc *new_var = xmalloc(sizeof(CfAssoc)); new_var->lval = xstrdup(RlistScalarValue(rp)); new_var->rval = (Rval) { ContainerToRlist(value), RVAL_TYPE_LIST }; new_var->dtype = CF_DATA_TYPE_STRING_LIST; iter->has_null_list |= !AppendIterationVariable(iter, new_var); } // We now have a control list of list-variables, with internal state in state_ptr return iter; }
static void test_length(void **state) { Rlist *list = NULL; assert_int_equal(RlistLen(list), 0); PrependRScalar(&list, "stuff", CF_SCALAR); assert_int_equal(RlistLen(list), 1); PrependRScalar(&list, "more-stuff", CF_SCALAR); assert_int_equal(RlistLen(list), 2); DeleteRlist(list); }
static void test_length(void) { Rlist *list = NULL; assert_int_equal(RlistLen(list), 0); RlistPrependScalar(&list, "stuff"); assert_int_equal(RlistLen(list), 1); RlistPrependScalar(&list, "more-stuff"); assert_int_equal(RlistLen(list), 2); RlistDestroy(list); }
static void test_length(void) { Rlist *list = NULL; assert_int_equal(RlistLen(list), 0); RlistPrepend(&list, "stuff", RVAL_TYPE_SCALAR); assert_int_equal(RlistLen(list), 1); RlistPrepend(&list, "more-stuff", RVAL_TYPE_SCALAR); assert_int_equal(RlistLen(list), 2); RlistDestroy(list); }
static void KeepPromiseBundles(EvalContext *ctx, const Policy *policy) { /* Dial up the generic promise expansion with a callback */ CleanReportBookFilterSet(); for (size_t i = 0; i < SeqLength(policy->bundles); i++) { Bundle *bp = SeqAt(policy->bundles, i); bool server_bundle = strcmp(bp->type, CF_AGENTTYPES[AGENT_TYPE_SERVER]) == 0; bool common_bundle = strcmp(bp->type, CF_AGENTTYPES[AGENT_TYPE_COMMON]) == 0; if (server_bundle || common_bundle) { if (RlistLen(bp->args) > 0) { Log(LOG_LEVEL_WARNING, "Cannot implicitly evaluate bundle '%s %s', as this bundle takes arguments.", bp->type, bp->name); continue; } } if (server_bundle) { EvaluateBundle(ctx, bp, SERVER_TYPESEQUENCE); } else if (common_bundle) { EvaluateBundle(ctx, bp, COMMON_TYPESEQUENCE); } } }
static JsonElement *RlistToJson(Rlist *list) { JsonElement *array = JsonArrayCreate(RlistLen(list)); for (Rlist *rp = list; rp; rp = rp->next) { switch (rp->val.type) { case RVAL_TYPE_SCALAR: JsonArrayAppendString(array, RlistScalarValue(rp)); break; case RVAL_TYPE_LIST: JsonArrayAppendArray(array, RlistToJson(RlistRlistValue(rp))); break; case RVAL_TYPE_FNCALL: JsonArrayAppendObject(array, FnCallToJson(RlistFnCallValue(rp))); break; default: assert(false && "Unsupported item type in rlist"); break; } } return array; }
static void test_expand_list_nested(void **state) { EvalContext *ctx = *state; { VarRef *lval = VarRefParse("default:bundle.i"); EvalContextVariablePut(ctx, lval, "one", CF_DATA_TYPE_STRING, NULL); VarRefDestroy(lval); } { VarRef *lval = VarRefParse("default:bundle.inner[one]"); Rlist *list = NULL; RlistAppendScalar(&list, "foo"); EvalContextVariablePut(ctx, lval, list, CF_DATA_TYPE_STRING_LIST, NULL); RlistDestroy(list); VarRefDestroy(lval); } Rlist *outer = NULL; RlistAppendScalar(&outer, "@{inner[$(i)]}"); Rlist *expanded = ExpandList(ctx, "default", "bundle", outer, true); assert_int_equal(1, RlistLen(expanded)); assert_string_equal("foo", RlistScalarValue(expanded)); RlistDestroy(outer); RlistDestroy(expanded); }
static void test_filter_everything(void) { Rlist *list = NULL; for (int i = 1; i < 10; i += 2) { void *item = xmemdup(&i, sizeof(int)); RlistAppendAlien(&list, item); } assert_int_equal(5, RlistLen(list)); int mod_by = 0; RlistFilter(&list, is_even, &mod_by, free); assert_int_equal(0, RlistLen(list)); assert_true(list == NULL); }
void ScopePushThis() { static const char RVAL_TYPE_STACK = 'k'; Scope *op = ScopeGet(NULL, "this"); if (!op) { return; } int frame_index = RlistLen(CF_STCK); char name[CF_MAXVARSIZE]; snprintf(name, CF_MAXVARSIZE, "this_%d", frame_index + 1); free(op->scope); free(op->ns); op->scope = xstrdup(name); Rlist *rp = xmalloc(sizeof(Rlist)); rp->next = CF_STCK; rp->item = op; rp->type = RVAL_TYPE_STACK; CF_STCK = rp; ScopeNew(NULL, "this"); }
void ScopePopThis() { if (RlistLen(CF_STCK) > 0) { Scope *current_this = ScopeGet(NULL, "this"); if (current_this) { ScopeDelete(current_this); } Rlist *rp = CF_STCK; CF_STCK = CF_STCK->next; Scope *new_this = rp->item; free(new_this->scope); new_this->scope = xstrdup("this"); new_this->ns = xstrdup("default"); free(rp); } else { ProgrammingError("Attempt to pop from empty stack"); } }
void ScopePushThis() { Scope *op; char name[CF_MAXVARSIZE]; op = ScopeGet("this"); if (op == NULL) { return; } int frame_index = RlistLen(CF_STCK) - 1; { Rlist *rp = xmalloc(sizeof(Rlist)); rp->next = CF_STCK; rp->item = op; rp->type = CF_STACK; CF_STCK = rp; } snprintf(name, CF_MAXVARSIZE, "this_%d", frame_index); free(op->scope); op->scope = xstrdup(name); }
static void test_filter_everything(void) { Rlist *list = NULL; for (int i = 1; i < 10; i += 2) { char *item = StringFromLong(i); RlistAppend(&list, item, RVAL_TYPE_SCALAR); } assert_int_equal(5, RlistLen(list)); int mod_by = 0; RlistFilter(&list, is_even, &mod_by, free); assert_int_equal(0, RlistLen(list)); assert_true(list == NULL); }
static FnCallResult CallFunction(EvalContext *ctx, const Policy *policy, const FnCall *fp, const Rlist *expargs) { const Rlist *rp = fp->args; const FnCallType *fncall_type = FnCallTypeGet(fp->name); int argnum = 0; for (argnum = 0; rp != NULL && fncall_type->args[argnum].pattern != NULL; argnum++) { if (rp->val.type != RVAL_TYPE_FNCALL) { /* Nested functions will not match to lval so don't bother checking */ SyntaxTypeMatch err = CheckConstraintTypeMatch(fp->name, rp->val, fncall_type->args[argnum].dtype, fncall_type->args[argnum].pattern, 1); if (err != SYNTAX_TYPE_MATCH_OK && err != SYNTAX_TYPE_MATCH_ERROR_UNEXPANDED) { FatalError(ctx, "In function '%s', error in variable '%s', '%s'", fp->name, (const char *)rp->val.item, SyntaxTypeMatchToString(err)); } } rp = rp->next; } char output[CF_BUFSIZE]; if (argnum != RlistLen(expargs) && !(fncall_type->options & FNCALL_OPTION_VARARG)) { snprintf(output, CF_BUFSIZE, "Argument template mismatch handling function %s(", fp->name); { Writer *w = FileWriter(stderr); RlistWrite(w, expargs); FileWriterDetach(w); } fprintf(stderr, ")\n"); rp = expargs; for (int i = 0; i < argnum; i++) { printf(" arg[%d] range %s\t", i, fncall_type->args[i].pattern); if (rp != NULL) { Writer *w = FileWriter(stdout); RvalWrite(w, rp->val); FileWriterDetach(w); rp = rp->next; } else { printf(" ? "); } printf("\n"); } FatalError(ctx, "Bad arguments"); } return (*fncall_type->impl) (ctx, policy, fp, expargs); }
static void test_map_iterators_from_rval_literal(void **state) { EvalContext *ctx = *state; Policy *p = PolicyNew(); Bundle *bp = PolicyAppendBundle(p, "default", "none", "agent", NULL, NULL); Rlist *lists = NULL; Rlist *scalars = NULL; Rlist *containers = NULL; MapIteratorsFromRval(ctx, bp, (Rval) { "snookie", RVAL_TYPE_SCALAR }, &scalars, &lists, &containers); assert_int_equal(0, RlistLen(lists)); assert_int_equal(0, RlistLen(scalars)); assert_int_equal(0, RlistLen(containers)); PolicyDestroy(p); }
static void test_regex_split_no_match() { Rlist *list = RlistFromRegexSplitNoOverflow(":one:two:three:", "/", 2); assert_int_equal(1, RlistLen(list)); assert_string_equal(RlistScalarValue(list), ":one:two:three:"); RlistDestroy(list); }
static void test_split_escaped(void) { Rlist *list = RlistFromSplitString("a\\,b\\c\\,d,w\\,x\\,y\\,z", ','); assert_int_equal(2, RlistLen(list)); assert_string_equal("a,b\\c,d", RlistScalarValue(list)); assert_string_equal("w,x,y,z", RlistScalarValue(list->next)); RlistDestroy(list); }
AgentConnection *NewServerConnection(FileCopy fc, bool background, int *err) { AgentConnection *conn; Rlist *rp; for (rp = fc.servers; rp != NULL; rp = rp->next) { const char *servername = RlistScalarValue(rp); if (ServerOffline(servername)) { continue; } if (background) { ThreadLock(&cft_serverlist); Rlist *srvlist_tmp = SERVERLIST; ThreadUnlock(&cft_serverlist); /* TODO not return NULL if >= CFA_MAXTREADS ? */ /* TODO RlistLen is O(n) operation. */ if (RlistLen(srvlist_tmp) < CFA_MAXTHREADS) { /* If background connection was requested, then don't cache it * in SERVERLIST since it will be closed right afterwards. */ conn = ServerConnection(servername, fc, err); return conn; } } else { conn = GetIdleConnectionToServer(servername); if (conn != NULL) { *err = 0; return conn; } /* This is first usage, need to open */ conn = ServerConnection(servername, fc, err); if (conn != NULL) { CacheServerConnection(conn, servername); return conn; } /* This server failed, trying next in list. */ Log(LOG_LEVEL_INFO, "Unable to establish connection with %s", servername); MarkServerOffline(servername); } } Log(LOG_LEVEL_ERR, "Unable to establish any connection with server."); return NULL; }
static bool MethodsParseTreeCheck(const Promise *pp, Seq *errors) { bool success = true; for (size_t i = 0; i < SeqLength(pp->conlist); i++) { const Constraint *cp = SeqAt(pp->conlist, i); // ensure: if call and callee are resolved, then they have matching arity if (StringSafeEqual(cp->lval, "usebundle")) { if (cp->rval.type == RVAL_TYPE_FNCALL) { // HACK: exploiting the fact that class-references and call-references are similar FnCall *call = RvalFnCallValue(cp->rval); ClassRef ref = ClassRefParse(call->name); if (!ClassRefIsQualified(ref)) { ClassRefQualify(&ref, PromiseGetNamespace(pp)); } const Bundle *callee = PolicyGetBundle(PolicyFromPromise(pp), ref.ns, "agent", ref.name); if (!callee) { callee = PolicyGetBundle(PolicyFromPromise(pp), ref.ns, "common", ref.name); } ClassRefDestroy(ref); if (callee) { if (RlistLen(call->args) != RlistLen(callee->args)) { SeqAppend(errors, PolicyErrorNew(POLICY_ELEMENT_TYPE_CONSTRAINT, cp, POLICY_ERROR_METHODS_BUNDLE_ARITY, call->name, RlistLen(callee->args), RlistLen(call->args))); success = false; } } } } } return success; }
void ArgTemplate(FnCall *fp, const FnCallArg *argtemplate, Rlist *realargs) { int argnum, i; Rlist *rp = fp->args; char id[CF_BUFSIZE], output[CF_BUFSIZE]; const FnCallType *fn = FnCallTypeGet(fp->name); snprintf(id, CF_MAXVARSIZE, "built-in FnCall %s-arg", fp->name); for (argnum = 0; rp != NULL && argtemplate[argnum].pattern != NULL; argnum++) { if (rp->type != RVAL_TYPE_FNCALL) { /* Nested functions will not match to lval so don't bother checking */ SyntaxTypeMatch err = CheckConstraintTypeMatch(id, (Rval) {rp->item, rp->type}, argtemplate[argnum].dtype, argtemplate[argnum].pattern, 1); if (err != SYNTAX_TYPE_MATCH_OK && err != SYNTAX_TYPE_MATCH_ERROR_UNEXPANDED) { FatalError("in %s: %s", id, SyntaxTypeMatchToString(err)); } } rp = rp->next; } if (argnum != RlistLen(realargs) && !fn->varargs) { snprintf(output, CF_BUFSIZE, "Argument template mismatch handling function %s(", fp->name); RlistShow(stderr, realargs); fprintf(stderr, ")\n"); for (i = 0, rp = realargs; i < argnum; i++) { printf(" arg[%d] range %s\t", i, argtemplate[i].pattern); if (rp != NULL) { RvalShow(stdout, (Rval) {rp->item, rp->type}); rp = rp->next; } else { printf(" ? "); } printf("\n"); } FatalError("Bad arguments"); } for (rp = realargs; rp != NULL; rp = rp->next) { CfDebug("finalarg: %s\n", (char *) rp->item); } CfDebug("End ArgTemplate\n"); }
static void test_regex_split_too_few_chunks() { Rlist *list = RlistFromRegexSplitNoOverflow("one:two:three", ":", 2); assert_int_equal(2, RlistLen(list)); assert_string_equal(RlistScalarValue(list), "one"); assert_string_equal(RlistScalarValue(list->next), "two:three"); RlistDestroy(list); }
static void test_reverse(void) { Rlist *list = RlistFromSplitString("a,b,c", ','); RlistReverse(&list); assert_int_equal(3, RlistLen(list)); assert_string_equal("c", RlistScalarValue(list)); assert_string_equal("b", RlistScalarValue(list->next)); assert_string_equal("a", RlistScalarValue(list->next->next)); RlistDestroy(list); }
static void test_prepend_scalar_idempotent(void) { Rlist *list = NULL; RlistPrependScalarIdemp(&list, "stuff"); RlistPrependScalarIdemp(&list, "stuff"); assert_string_equal(RlistScalarValue(list), "stuff"); assert_int_equal(RlistLen(list), 1); RlistDestroy(list); }
static void test_regex_split() { Rlist *list = RlistFromRegexSplitNoOverflow("one-->two-->three", "-+>", 3); assert_int_equal(3, RlistLen(list)); assert_string_equal(RlistScalarValue(list), "one"); assert_string_equal(RlistScalarValue(list->next), "two"); assert_string_equal(RlistScalarValue(list->next->next), "three"); RlistDestroy(list); }
static void test_prepend_scalar_idempotent(void **state) { Rlist *list = NULL; IdempPrependRScalar(&list, "stuff", CF_SCALAR); IdempPrependRScalar(&list, "stuff", CF_SCALAR); assert_string_equal(list->item, "stuff"); assert_int_equal(RlistLen(list), 1); DeleteRlist(list); }
static void test_regex_split_overlapping_delimiters() { Rlist *list = RlistFromRegexSplitNoOverflow("-one---two---three", "--", 3); assert_int_equal(3, RlistLen(list)); assert_string_equal(RlistScalarValue(list), "-one"); assert_string_equal(RlistScalarValue(list->next), "-two"); assert_string_equal(RlistScalarValue(list->next->next), "-three"); RlistDestroy(list); }
void ArgTemplate(FnCall *fp, const FnCallArg *argtemplate, Rlist *realargs) { int argnum, i; Rlist *rp = fp->args; char id[CF_BUFSIZE], output[CF_BUFSIZE]; const FnCallType *fn = FindFunction(fp->name); snprintf(id, CF_MAXVARSIZE, "built-in FnCall %s-arg", fp->name); for (argnum = 0; rp != NULL && argtemplate[argnum].pattern != NULL; argnum++) { if (rp->type != CF_FNCALL) { /* Nested functions will not match to lval so don't bother checking */ CheckConstraintTypeMatch(id, (Rval) {rp->item, rp->type}, argtemplate[argnum].dtype, argtemplate[argnum].pattern, 1); } rp = rp->next; } if (argnum != RlistLen(realargs) && !fn->varargs) { snprintf(output, CF_BUFSIZE, "Argument template mismatch handling function %s(", fp->name); ReportError(output); ShowRlist(stderr, realargs); fprintf(stderr, ")\n"); for (i = 0, rp = realargs; i < argnum; i++) { printf(" arg[%d] range %s\t", i, argtemplate[i].pattern); if (rp != NULL) { ShowRval(stdout, (Rval) {rp->item, rp->type}); rp = rp->next; } else { printf(" ? "); } printf("\n"); } FatalError("Bad arguments"); } for (rp = realargs; rp != NULL; rp = rp->next) { CfDebug("finalarg: %s\n", (char *) rp->item); } CfDebug("End ArgTemplate\n"); }
static void test_regex_split_real_regex() { //whole string is matched by regex in below example Rlist *list = RlistFromRegexSplitNoOverflow("one-two-three", ".+", 3); assert_int_equal(2, RlistLen(list)); assert_string_equal(RlistScalarValue(list), ""); assert_string_equal(RlistScalarValue(list->next), ""); RlistDestroy(list); list = RlistFromRegexSplitNoOverflow("one>>>two<<<three<><>four", "[<>]+", 4); assert_int_equal(4, RlistLen(list)); assert_string_equal(RlistScalarValue(list), "one"); assert_string_equal(RlistScalarValue(list->next), "two"); assert_string_equal(RlistScalarValue(list->next->next), "three"); assert_string_equal(RlistScalarValue(list->next->next->next), "four"); RlistDestroy(list); }