void CopyList(Item **dest, const Item *source) /* Copy or concat lists */ { if (*dest != NULL) { ProgrammingError("CopyList - list not initialized"); } if (source == NULL) { return; } for (const Item *ip = source; ip != NULL; ip = ip->next) { AppendItem(dest, ip->name, ip->classes); } }
void ScopePutMatch(int index, const char *value) { if (!SCOPE_MATCH) { SCOPE_MATCH = ScopeNew("match"); } Scope *ptr = SCOPE_MATCH; char lval[4] = { 0 }; snprintf(lval, 3, "%d", index); Rval rval = (Rval) { value, RVAL_TYPE_SCALAR }; CfAssoc *assoc = HashLookupElement(ptr->hashtable, lval); if (assoc) { if (CompareVariableValue(rval, assoc) == 0) { /* Identical value, keep as is */ } else { /* Different value, bark and replace */ if (!UnresolvedVariables(assoc, RVAL_TYPE_SCALAR)) { CfOut(OUTPUT_LEVEL_INFORM, "", " !! Duplicate selection of value for variable \"%s\" in scope %s", lval, ptr->scope); } RvalDestroy(assoc->rval); assoc->rval = RvalCopy(rval); assoc->dtype = DATA_TYPE_STRING; CfDebug("Stored \"%s\" in context %s\n", lval, "match"); } } else { if (!HashInsertElement(ptr->hashtable, lval, rval, DATA_TYPE_STRING)) { ProgrammingError("Hash table is full"); } } }
/** * @brief DNS lookup of hostname, store the address as string into dst of size * dst_size. * @return -1 in case of unresolvable hostname or other error. */ int Hostname2IPString(char *dst, const char *hostname, size_t dst_size) { int ret; struct addrinfo *response, *ap; struct addrinfo query = { .ai_family = AF_UNSPEC, .ai_socktype = SOCK_STREAM }; if (dst_size < CF_MAX_IP_LEN) { ProgrammingError("Hostname2IPString got %zu, needs at least" " %d length buffer for IPv6 portability!", dst_size, CF_MAX_IP_LEN); } ret = getaddrinfo(hostname, NULL, &query, &response); if ((ret) != 0) { Log(LOG_LEVEL_INFO, "Unable to lookup hostname '%s' or cfengine service. (getaddrinfo: %s)", hostname, gai_strerror(ret)); return -1; } for (ap = response; ap != NULL; ap = ap->ai_next) { /* No lookup, just convert numeric IP to string. */ int ret2 = getnameinfo(ap->ai_addr, ap->ai_addrlen, dst, dst_size, NULL, 0, NI_NUMERICHOST); if (ret2 == 0) { freeaddrinfo(response); return 0; /* Success */ } } freeaddrinfo(response); Log(LOG_LEVEL_ERR, "Hostname2IPString: ERROR even though getaddrinfo returned success!"); return -1; }
static bool VariableStateHasMore(const PromiseIterator *iter, size_t index) { CfAssoc *var = SeqAt(iter->vars, index); switch (var->rval.type) { case RVAL_TYPE_LIST: { const Rlist *state = SeqAt(iter->var_states, index); return state && state->next; } case RVAL_TYPE_CONTAINER: case RVAL_TYPE_FNCALL: case RVAL_TYPE_NOPROMISEE: case RVAL_TYPE_SCALAR: ProgrammingError("Unhandled case in switch %d", var->rval.type); } return false; }
static char FileStateToChar(FileState status) { switch(status) { case FILE_STATE_NEW: return 'N'; case FILE_STATE_REMOVED: return 'R'; case FILE_STATE_CONTENT_CHANGED: return 'C'; case FILE_STATE_STATS_CHANGED: return 'S'; default: ProgrammingError("Unhandled file status in switch: %d", status); } }
static const char *SpecialScopeToString(SpecialScope scope) { switch (scope) { case SPECIAL_SCOPE_CONST: return "const"; case SPECIAL_SCOPE_EDIT: return "edit"; case SPECIAL_SCOPE_MATCH: return "match"; case SPECIAL_SCOPE_MON: return "mon"; case SPECIAL_SCOPE_SYS: return "sys"; case SPECIAL_SCOPE_THIS: return "this"; default: ProgrammingError("Unhandled special scope"); } }
VersionCmpResult CompareVersions(EvalContext *ctx, const char *v1, const char *v2, Attributes a, Promise *pp) { switch (a.packages.package_select) { case PACKAGE_VERSION_COMPARATOR_EQ: case PACKAGE_VERSION_COMPARATOR_NONE: return CompareVersionsEqual(ctx, v1, v2, a, pp); case PACKAGE_VERSION_COMPARATOR_NEQ: return InvertResult(CompareVersionsEqual(ctx, v1, v2, a, pp)); case PACKAGE_VERSION_COMPARATOR_LT: return CompareVersionsLess(ctx, v1, v2, a, pp); case PACKAGE_VERSION_COMPARATOR_GT: return CompareVersionsLess(ctx, v2, v1, a, pp); case PACKAGE_VERSION_COMPARATOR_GE: return InvertResult(CompareVersionsLess(ctx, v1, v2, a, pp)); case PACKAGE_VERSION_COMPARATOR_LE: return InvertResult(CompareVersionsLess(ctx, v2, v1, a, pp)); default: ProgrammingError("Unexpected comparison value: %d", a.packages.package_select); } }
void PrintList(List *list) { ListIterator *i = NULL; i = ListIteratorGet(list); if (!i) { ProgrammingError("Unable to get iterator for hub list"); return; } do { HostProperties *hostprop = (HostProperties *)ListIteratorData(i); Log(LOG_LEVEL_NOTICE, "CFEngine Policy Server: hostname '%s', IP address '%s', port %d", hostprop->Hostname, hostprop->IPAddress, hostprop->Port); } while (ListIteratorNext(i) != -1); ListIteratorDestroy(&i); }
int sockaddr_AddrCompare(const void *sa1, const void *sa2) { int sa1_family = ((struct sockaddr *) sa1)->sa_family; int sa2_family = ((struct sockaddr *) sa2)->sa_family; if ((sa1_family != AF_INET && sa1_family != AF_INET6) || (sa2_family != AF_INET && sa2_family != AF_INET6)) { ProgrammingError("sockaddr_AddrCompare: Unknown address families %d %d", sa1_family, sa2_family); } if (sa1_family != sa2_family) { /* We consider any IPv4 address smaller than any IPv6 one. */ return (sa1_family == AF_INET) ? -1 : 1; } int result; switch (sa1_family) { case AF_INET: { struct in_addr *addr1 = & ((struct sockaddr_in *) sa1)->sin_addr; struct in_addr *addr2 = & ((struct sockaddr_in *) sa2)->sin_addr; result = memcmp(addr1, addr2, sizeof(*addr1)); } case AF_INET6: { struct in6_addr *addr1 = & ((struct sockaddr_in6 *) sa1)->sin6_addr; struct in6_addr *addr2 = & ((struct sockaddr_in6 *) sa2)->sin6_addr; result = memcmp(addr1, addr2, sizeof(*addr1)); } default: assert(0); result = 0; } return result; }
void RlistFlatten(EvalContext *ctx, Rlist **list) { for (Rlist *rp = *list; rp != NULL;) { if (rp->type != RVAL_TYPE_SCALAR) { rp = rp->next; continue; } char naked[CF_BUFSIZE] = ""; if (IsNakedVar(rp->item, '@')) { GetNaked(naked, rp->item); Rval rv; if (EvalContextVariableGet(ctx, (VarRef) { NULL, ScopeGetCurrent()->scope, naked }, &rv, NULL)) { switch (rv.type) { case RVAL_TYPE_LIST: for (const Rlist *srp = rv.item; srp != NULL; srp = srp->next) { RlistAppend(list, srp->item, srp->type); } Rlist *next = rp->next; RlistDestroyEntry(list, rp); rp = next; continue; default: ProgrammingError("List variable does not resolve to a list"); RlistAppend(list, rp->item, rp->type); break; } } } rp = rp->next; } }
const char *LogLevelToString(LogLevel level) { switch (level) { case LOG_LEVEL_CRIT: return "critical"; case LOG_LEVEL_ERR: return "error"; case LOG_LEVEL_WARNING: return "warning"; case LOG_LEVEL_NOTICE: return "notice"; case LOG_LEVEL_INFO: return "info"; case LOG_LEVEL_VERBOSE: return "verbose"; case LOG_LEVEL_DEBUG: return "debug"; default: ProgrammingError("Unknown log level passed to LogLevelToString: %d", level); } }
const char *LogLevelToString(LogLevel level) { switch (level) { case LOG_LEVEL_CRIT: return "CRITICAL"; case LOG_LEVEL_ERR: return "error"; case LOG_LEVEL_WARNING: return "warning"; case LOG_LEVEL_NOTICE: return "notice"; case LOG_LEVEL_INFO: return "info"; case LOG_LEVEL_VERBOSE: return "verbose"; case LOG_LEVEL_DEBUG: return "debug"; default: ProgrammingError("LogLevelToString: Unexpected log level %d", level); } }
char *sockaddr_ntop(struct sockaddr *sa) { #if defined(HAVE_GETADDRINFO) static char addrbuf[INET6_ADDRSTRLEN]; void *addr; #else static char addrbuf[20]; #endif switch (sa->sa_family) { case AF_INET: CfDebug("IPV4 address\n"); snprintf(addrbuf, 20, "%.19s", inet_ntoa(((struct sockaddr_in *) sa)->sin_addr)); break; #ifdef AF_LOCAL case AF_LOCAL: CfDebug("Local socket\n"); strcpy(addrbuf, "127.0.0.1"); break; #endif #if defined(HAVE_GETADDRINFO) case AF_INET6: CfDebug("IPV6 address\n"); addr = &((struct sockaddr_in6 *) sa)->sin6_addr; inet_ntop(sa->sa_family, addr, addrbuf, sizeof(addrbuf)); break; #endif default: CfDebug("Address family was %d\n", sa->sa_family); ProgrammingError("Software failure in sockaddr_ntop\n"); } CfDebug("sockaddr_ntop(%s)\n", addrbuf); return addrbuf; }
/* Return the port number in host byte order. */ uint16_t sockaddr_port(const void *sa) { int family = ((struct sockaddr *) sa)->sa_family; uint16_t port; switch (family) { case AF_INET: port = ((struct sockaddr_in *) sa)->sin_port; break; #ifdef HAVE_GETADDRINFO case AF_INET6: addr = ((struct sockaddr_in6 *) sa)->sin6_port; break; #endif default: ProgrammingError("sockaddr_port: address family was %d", family); } return ntohs(port); }
static StackFrame *LastStackFrameBundle(const EvalContext *ctx) { StackFrame *last_frame = LastStackFrame(ctx, 0); switch (last_frame->type) { case STACK_FRAME_TYPE_BUNDLE: return last_frame; case STACK_FRAME_TYPE_BODY: { assert(LastStackFrame(ctx, 1)); assert(LastStackFrame(ctx, 1)->type == STACK_FRAME_TYPE_PROMISE); StackFrame *previous_frame = LastStackFrame(ctx, 2); if (previous_frame) { assert(previous_frame->type == STACK_FRAME_TYPE_BUNDLE); return previous_frame; } else { return NULL; } } case STACK_FRAME_TYPE_PROMISE: { StackFrame *previous_frame = LastStackFrame(ctx, 1); assert(previous_frame); assert("Promise stack frame does not follow bundle stack frame" && previous_frame->type == STACK_FRAME_TYPE_BUNDLE); return previous_frame; } default: ProgrammingError("Unhandled stack frame type"); } }
void ScopePopThis() { Scope *op = NULL; if (RlistLen(CF_STCK) > 0) { ScopeClear("this"); { Rlist *rp = CF_STCK; if (CF_STCK == NULL) { ProgrammingError("Attempt to pop from empty stack"); } op = rp->item; if (rp->next == NULL) /* only one left */ { CF_STCK = (void *) NULL; } else { CF_STCK = rp->next; } free((char *) rp); } if (op == NULL) { return; } free(op->scope); op->scope = xstrdup("this"); } }
void UpdatePromiseCounters(PromiseResult status) { switch (status) { case PROMISE_RESULT_CHANGE: PR_REPAIRED++; break; case PROMISE_RESULT_NOOP: PR_KEPT++; break; case PROMISE_RESULT_WARN: case PROMISE_RESULT_TIMEOUT: case PROMISE_RESULT_FAIL: case PROMISE_RESULT_DENIED: case PROMISE_RESULT_INTERRUPTED: PR_NOTKEPT++; break; default: ProgrammingError("Unexpected status '%c' has been passed to UpdatePromiseCounters", status); } }
static int LogLevelToSyslogPriority(LogLevel level) { switch (level) { case LOG_LEVEL_CRIT: return LOG_CRIT; case LOG_LEVEL_ERR: return LOG_ERR; case LOG_LEVEL_WARNING: return LOG_WARNING; case LOG_LEVEL_NOTICE: return LOG_NOTICE; case LOG_LEVEL_INFO: return LOG_INFO; case LOG_LEVEL_VERBOSE: return LOG_DEBUG; /* FIXME: Do we really want to conflate those levels? */ case LOG_LEVEL_DEBUG: return LOG_DEBUG; default: ProgrammingError("LogLevelToSyslogPriority: Unexpected log level %d", level); } }
static bool VariableStateReset(PromiseIterator *iter, size_t index) { assert(index < SeqLength(iter->var_states)); CfAssoc *var = SeqAt(iter->vars, index); switch (var->rval.type) { case RVAL_TYPE_LIST: { Rlist *state = RvalRlistValue(var->rval); // find the first valid value, return false if there is none state = FirstRealEntry(state); SeqSet(iter->var_states, index, state); return state != NULL; } break; default: ProgrammingError("Unhandled case in switch"); } return false; }
static const char *LogLevelToColor(LogLevel level) { switch (level) { case LOG_LEVEL_CRIT: case LOG_LEVEL_ERR: return "\x1b[31m"; // red case LOG_LEVEL_WARNING: return "\x1b[33m"; // yellow case LOG_LEVEL_NOTICE: case LOG_LEVEL_INFO: return "\x1b[32m"; // green case LOG_LEVEL_VERBOSE: case LOG_LEVEL_DEBUG: return "\x1b[34m"; // blue default: ProgrammingError("Unknown log level passed to LogLevelToColor %d", level); } }
bool sockaddr_pton(int af, const void *src, void *genaddr) { switch (af) { case AF_INET: { struct sockaddr_in *addr = (struct sockaddr_in *) genaddr; memset(addr, 0, sizeof(struct sockaddr_in)); addr->sin_family = AF_INET; addr->sin_addr.s_addr = inet_addr(src); CfDebug("Coded ipv4 %s\n", sockaddr_ntop((struct sockaddr *) genaddr)); return addr->sin_addr.s_addr != INADDR_NONE; } #if defined(HAVE_GETADDRINFO) case AF_INET6: { int err; struct sockaddr_in6 *addr = (struct sockaddr_in6 *) genaddr; memset(addr, 0, sizeof(struct sockaddr_in6)); addr->sin6_family = AF_INET6; err = inet_pton(AF_INET6, src, &addr->sin6_addr); CfDebug("Coded ipv6 %s\n", sockaddr_ntop((struct sockaddr *) genaddr)); return err > 0; } #endif default: CfDebug("Address family was %d\n", af); ProgrammingError("Software failure in sockaddr_pton\n"); } }
Rval ExpandDanglers(EvalContext *ctx, const char *ns, const char *scope, Rval rval, const Promise *pp) { assert(ctx); assert(pp); switch (rval.type) { case RVAL_TYPE_SCALAR: if (IsCf3VarString(RvalScalarValue(rval))) { return EvaluateFinalRval(ctx, PromiseGetPolicy(pp), ns, scope, rval, false, pp); } else { return RvalCopy(rval); } break; case RVAL_TYPE_LIST: { Rlist *result_list = RlistCopy(RvalRlistValue(rval)); RlistFlatten(ctx, &result_list); return (Rval) { result_list, RVAL_TYPE_LIST }; } break; case RVAL_TYPE_CONTAINER: case RVAL_TYPE_FNCALL: case RVAL_TYPE_NOPROMISEE: return RvalCopy(rval); } ProgrammingError("Unhandled Rval type"); }
Promise *DeRefCopyPromise(EvalContext *ctx, const Promise *pp) { Promise *pcopy; Rval returnval; 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 %zu of file '%s', '%s' does not equal '%s'", body_name, 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, PromiseGetNamespace(pcopy))) { 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 %zu of file '%s'", body_name, pp->offset.line, PromiseGetBundle(pp)->source_path); } for (size_t k = 0; k < SeqLength(bp->conlist); k++) { Constraint *scp = SeqAt(bp->conlist, k); returnval = ExpandPrivateRval(ctx, NULL, "body", scp->rval.item, scp->rval.type); if (IsDefinedClass(ctx, scp->classes, PromiseGetNamespace(pcopy))) { 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 %zu of %s (possible unquoted literal value)", body_name, pp->offset.line, PromiseGetBundle(pp)->source_path); } else { for (size_t k = 0; k < SeqLength(bp->conlist); k++) { Constraint *scp = SeqAt(bp->conlist, k); Rval newrv = RvalCopy(scp->rval); if (newrv.type == RVAL_TYPE_LIST) { Rlist *new_list = RvalRlistValue(newrv); RlistFlatten(ctx, &new_list); newrv.item = new_list; } if (IsDefinedClass(ctx, scp->classes, PromiseGetNamespace(pcopy))) { 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 %zu of %s (possible unquoted literal value)", body_name, pp->offset.line, PromiseGetBundle(pp)->source_path); } Rval newrv = RvalCopy(cp->rval); if (newrv.type == RVAL_TYPE_LIST) { Rlist *new_list = RvalRlistValue(newrv); RlistFlatten(ctx, &new_list); newrv.item = new_list; } if (IsDefinedClass(ctx, cp->classes, PromiseGetNamespace(pcopy))) { Constraint *cp_copy = PromiseAppendConstraint(pcopy, cp->lval, newrv, false); cp_copy->offset = cp->offset; } } } return pcopy; }
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; }
void ScopeAugment(EvalContext *ctx, const Bundle *bp, const Promise *pp, const Rlist *arguments) { if (RlistLen(bp->args) != RlistLen(arguments)) { Log(LOG_LEVEL_ERR, "While constructing scope '%s'", bp->name); fprintf(stderr, "Formal = "); RlistShow(stderr, bp->args); fprintf(stderr, ", Actual = "); RlistShow(stderr, arguments); fprintf(stderr, "\n"); FatalError(ctx, "Augment scope, formal and actual parameter mismatch is fatal"); } const Bundle *pbp = NULL; if (pp != NULL) { pbp = PromiseGetBundle(pp); } for (const Rlist *rpl = bp->args, *rpr = arguments; rpl != NULL; rpl = rpl->next, rpr = rpr->next) { const char *lval = rpl->item; Log(LOG_LEVEL_VERBOSE, "Augment scope '%s' with variable '%s' (type: %c)", bp->name, lval, rpr->type); // CheckBundleParameters() already checked that there is no namespace collision // By this stage all functions should have been expanded, so we only have scalars left if (IsNakedVar(rpr->item, '@')) { DataType vtype; char naked[CF_BUFSIZE]; GetNaked(naked, rpr->item); Rval retval; if (pbp != NULL) { VarRef *ref = VarRefParseFromBundle(naked, pbp); EvalContextVariableGet(ctx, ref, &retval, &vtype); VarRefDestroy(ref); } else { VarRef *ref = VarRefParseFromBundle(naked, bp); EvalContextVariableGet(ctx, ref, &retval, &vtype); VarRefDestroy(ref); } switch (vtype) { case DATA_TYPE_STRING_LIST: case DATA_TYPE_INT_LIST: case DATA_TYPE_REAL_LIST: { VarRef *ref = VarRefParseFromBundle(lval, bp); EvalContextVariablePut(ctx, ref, (Rval) { retval.item, RVAL_TYPE_LIST}, DATA_TYPE_STRING_LIST); VarRefDestroy(ref); } break; default: { Log(LOG_LEVEL_ERR, "List parameter '%s' not found while constructing scope '%s' - use @(scope.variable) in calling reference", naked, bp->name); VarRef *ref = VarRefParseFromBundle(lval, bp); EvalContextVariablePut(ctx, ref, (Rval) { rpr->item, RVAL_TYPE_SCALAR }, DATA_TYPE_STRING); VarRefDestroy(ref); } break; } } else { switch(rpr->type) { case RVAL_TYPE_SCALAR: { VarRef *ref = VarRefParseFromBundle(lval, bp); EvalContextVariablePut(ctx, ref, (Rval) { rpr->item, RVAL_TYPE_SCALAR }, DATA_TYPE_STRING); VarRefDestroy(ref); } break; case RVAL_TYPE_FNCALL: { FnCall *subfp = rpr->item; Rval rval = FnCallEvaluate(ctx, subfp, pp).rval; if (rval.type == RVAL_TYPE_SCALAR) { VarRef *ref = VarRefParseFromBundle(lval, bp); EvalContextVariablePut(ctx, ref, (Rval) { rval.item, RVAL_TYPE_SCALAR }, DATA_TYPE_STRING); VarRefDestroy(ref); } else { Log(LOG_LEVEL_ERR, "Only functions returning scalars can be used as arguments"); } } break; default: ProgrammingError("An argument neither a scalar nor a list seemed to appear. Impossible"); } } } /* Check that there are no danglers left to evaluate in the hash table itself */ return; }
void ScopeDeRefListsInHashtable(char *scope, Rlist *namelist, Rlist *dereflist) // Go through scope and for each variable in name-list, replace with a // value from the deref "lol" (list of lists) clock { int len; Scope *ptr; Rlist *rp; CfAssoc *cplist; AssocHashTableIterator i; CfAssoc *assoc; if ((len = RlistLen(namelist)) != RlistLen(dereflist)) { CfOut(OUTPUT_LEVEL_ERROR, "", " !! Name list %d, dereflist %d\n", len, RlistLen(dereflist)); ProgrammingError("Software Error DeRefLists... correlated lists not same length"); } if (len == 0) { return; } ptr = ScopeGet(scope); i = HashIteratorInit(ptr->hashtable); while ((assoc = HashIteratorNext(&i))) { for (rp = dereflist; rp != NULL; rp = rp->next) { cplist = (CfAssoc *) rp->item; if (strcmp(cplist->lval, assoc->lval) == 0) { /* Link up temp hash to variable lol */ if (rp->state_ptr == NULL || rp->state_ptr->type == RVAL_TYPE_FNCALL) { /* Unexpanded function, or blank variable must be skipped. */ return; } if (rp->state_ptr) { CfDebug("Rewriting expanded type for %s from %s to %s\n", assoc->lval, CF_DATATYPES[assoc->dtype], (char *) rp->state_ptr->item); // must first free existing rval in scope, then allocate new (should always be string) RvalDestroy(assoc->rval); // avoids double free - borrowing value from lol (freed in DeleteScope()) assoc->rval.item = xstrdup(rp->state_ptr->item); } switch (assoc->dtype) { case DATA_TYPE_STRING_LIST: assoc->dtype = DATA_TYPE_STRING; assoc->rval.type = RVAL_TYPE_SCALAR; break; case DATA_TYPE_INT_LIST: assoc->dtype = DATA_TYPE_INT; assoc->rval.type = RVAL_TYPE_SCALAR; break; case DATA_TYPE_REAL_LIST: assoc->dtype = DATA_TYPE_REAL; assoc->rval.type = RVAL_TYPE_SCALAR; break; default: /* Only lists need to be converted */ break; } CfDebug(" to %s\n", CF_DATATYPES[assoc->dtype]); } } } }
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; }
void ScopeAugment(EvalContext *ctx, const Bundle *bp, const Rlist *arguments) { if (RlistLen(bp->args) != RlistLen(arguments)) { CfOut(OUTPUT_LEVEL_ERROR, "", "While constructing scope \"%s\"\n", bp->name); fprintf(stderr, "Formal = "); RlistShow(stderr, bp->args); fprintf(stderr, ", Actual = "); RlistShow(stderr, arguments); fprintf(stderr, "\n"); FatalError(ctx, "Augment scope, formal and actual parameter mismatch is fatal"); } for (const Rlist *rpl = bp->args, *rpr = arguments; rpl != NULL; rpl = rpl->next, rpr = rpr->next) { const char *lval = rpl->item; CfOut(OUTPUT_LEVEL_VERBOSE, "", " ? Augment scope %s with %s (%c)\n", bp->name, lval, rpr->type); // CheckBundleParameters() already checked that there is no namespace collision // By this stage all functions should have been expanded, so we only have scalars left if (IsNakedVar(rpr->item, '@')) { DataType vtype; char qnaked[CF_MAXVARSIZE]; char naked[CF_BUFSIZE]; GetNaked(naked, rpr->item); if (IsQualifiedVariable(naked) && strchr(naked, CF_NS) == NULL) { snprintf(qnaked, CF_MAXVARSIZE, "%s%c%s", bp->ns, CF_NS, naked); } Rval retval; EvalContextVariableGet(ctx, (VarRef) { NULL, bp->name, qnaked }, &retval, &vtype); switch (vtype) { case DATA_TYPE_STRING_LIST: case DATA_TYPE_INT_LIST: case DATA_TYPE_REAL_LIST: ScopeNewList(ctx, (VarRef) { NULL, bp->name, lval }, RvalCopy((Rval) { retval.item, RVAL_TYPE_LIST}).item, DATA_TYPE_STRING_LIST); break; default: CfOut(OUTPUT_LEVEL_ERROR, "", " !! List parameter \"%s\" not found while constructing scope \"%s\" - use @(scope.variable) in calling reference", qnaked, bp->name); ScopeNewScalar(ctx, (VarRef) { NULL, bp->name, lval }, rpr->item, DATA_TYPE_STRING); break; } } else { switch(rpr->type) { case RVAL_TYPE_SCALAR: ScopeNewScalar(ctx, (VarRef) { NULL, bp->name, lval }, rpr->item, DATA_TYPE_STRING); break; case RVAL_TYPE_FNCALL: { FnCall *subfp = rpr->item; Promise *pp = NULL; // This argument should really get passed down. Rval rval = FnCallEvaluate(ctx, subfp, pp).rval; if (rval.type == RVAL_TYPE_SCALAR) { ScopeNewScalar(ctx, (VarRef) { NULL, bp->name, lval }, rval.item, DATA_TYPE_STRING); } else { CfOut(OUTPUT_LEVEL_ERROR, "", "Only functions returning scalars can be used as arguments"); } } break; default: ProgrammingError("An argument neither a scalar nor a list seemed to appear. Impossible"); } } } /* Check that there are no danglers left to evaluate in the hash table itself */ { Scope *ptr = ScopeGet(bp->name); AssocHashTableIterator i = HashIteratorInit(ptr->hashtable); CfAssoc *assoc = NULL; while ((assoc = HashIteratorNext(&i))) { Rval retval = ExpandPrivateRval(ctx, bp->name, assoc->rval); // Retain the assoc, just replace rval RvalDestroy(assoc->rval); assoc->rval = retval; } } return; }
bool EvalContextVariablePut(EvalContext *ctx, VarRef lval, Rval rval, DataType type) { Scope *ptr; const Rlist *rp; CfAssoc *assoc; if (rval.type == RVAL_TYPE_SCALAR) { CfDebug("AddVariableHash(%s.%s=%s (%s) rtype=%c)\n", lval.scope, lval.lval, (const char *) rval.item, CF_DATATYPES[type], rval.type); } else { CfDebug("AddVariableHash(%s.%s=(list) (%s) rtype=%c)\n", lval.scope, lval.lval, CF_DATATYPES[type], rval.type); } if (lval.lval == NULL || lval.scope == NULL) { CfOut(OUTPUT_LEVEL_ERROR, "", "scope.value = %s.%s", lval.scope, lval.lval); ProgrammingError("Bad variable or scope in a variable assignment, should not happen - forgotten to register a function call in fncall.c?"); } if (rval.item == NULL) { CfDebug("No value to assignment - probably a parameter in an unused bundle/body\n"); return false; } if (strlen(lval.lval) > CF_MAXVARSIZE) { char *lval_str = VarRefToString(lval); CfOut(OUTPUT_LEVEL_ERROR, "", "Variable %s cannot be added because its length exceeds the maximum length allowed: %d", lval_str, CF_MAXVARSIZE); free(lval_str); return false; } /* If we are not expanding a body template, check for recursive singularities */ if (strcmp(lval.scope, "body") != 0) { switch (rval.type) { case RVAL_TYPE_SCALAR: if (StringContainsVar((char *) rval.item, lval.lval)) { CfOut(OUTPUT_LEVEL_ERROR, "", "Scalar variable %s.%s contains itself (non-convergent): %s", lval.scope, lval.lval, (char *) rval.item); return false; } break; case RVAL_TYPE_LIST: for (rp = rval.item; rp != NULL; rp = rp->next) { if (StringContainsVar((char *) rp->item, lval.lval)) { CfOut(OUTPUT_LEVEL_ERROR, "", "List variable %s contains itself (non-convergent)", lval.lval); return false; } } break; default: break; } } ptr = ScopeGet(lval.scope); if (!ptr) { ptr = ScopeNew(lval.scope); if (!ptr) { return false; } } // Look for outstanding lists in variable rvals if (THIS_AGENT_TYPE == AGENT_TYPE_COMMON) { Rlist *listvars = NULL; if (ScopeGetCurrent() && strcmp(ScopeGetCurrent()->scope, "this") != 0) { MapIteratorsFromRval(ScopeGetCurrent()->scope, &listvars, rval); if (listvars != NULL) { CfOut(OUTPUT_LEVEL_ERROR, "", " !! Redefinition of variable \"%s\" (embedded list in RHS) in context \"%s\"", lval.lval, ScopeGetCurrent()->scope); } RlistDestroy(listvars); } } assoc = HashLookupElement(ptr->hashtable, lval.lval); if (assoc) { if (CompareVariableValue(rval, assoc) == 0) { /* Identical value, keep as is */ } else { /* Different value, bark and replace */ if (!UnresolvedVariables(assoc, rval.type)) { CfOut(OUTPUT_LEVEL_INFORM, "", " !! Duplicate selection of value for variable \"%s\" in scope %s", lval.lval, ptr->scope); } RvalDestroy(assoc->rval); assoc->rval = RvalCopy(rval); assoc->dtype = type; CfDebug("Stored \"%s\" in context %s\n", lval.lval, lval.scope); } } else { if (!HashInsertElement(ptr->hashtable, lval.lval, rval, type)) { ProgrammingError("Hash table is full"); } } CfDebug("Added Variable %s in scope %s with value (omitted)\n", lval.lval, lval.scope); return true; }
void EvalContextStackFrameAddSoft(EvalContext *ctx, const char *context) { assert(SeqLength(ctx->stack) > 0); StackFrameBundle frame; { StackFrame *last_frame = LastStackFrameBundle(ctx); if (!last_frame) { ProgrammingError("Attempted to add a soft class on the stack, but stack had no bundle frame"); } frame = last_frame->data.bundle; } char copy[CF_BUFSIZE]; if (strcmp(frame.owner->ns, "default") != 0) { snprintf(copy, CF_MAXVARSIZE, "%s:%s", frame.owner->ns, context); } else { strncpy(copy, context, CF_MAXVARSIZE); } if (Chop(copy, CF_EXPANDSIZE) == -1) { CfOut(OUTPUT_LEVEL_ERROR, "", "Chop was called on a string that seemed to have no terminator"); } if (strlen(copy) == 0) { return; } CfDebug("NewBundleClass(%s)\n", copy); if (IsRegexItemIn(ctx, ctx->heap_abort_current_bundle, copy)) { CfOut(OUTPUT_LEVEL_ERROR, "", "Bundle %s aborted on defined class \"%s\"\n", frame.owner->name, copy); ABORTBUNDLE = true; } if (IsRegexItemIn(ctx, ctx->heap_abort, copy)) { CfOut(OUTPUT_LEVEL_ERROR, "", "cf-agent aborted on defined class \"%s\" defined in bundle %s\n", copy, frame.owner->name); exit(1); } if (EvalContextHeapContainsSoft(ctx, copy)) { CfOut(OUTPUT_LEVEL_ERROR, "", "WARNING - private class \"%s\" in bundle \"%s\" shadows a global class - you should choose a different name to avoid conflicts", copy, frame.owner->name); } if (EvalContextStackFrameContainsSoft(ctx, copy)) { return; } StringSetAdd(frame.contexts, xstrdup(copy)); for (const Item *ip = ctx->heap_abort; ip != NULL; ip = ip->next) { if (IsDefinedClass(ctx, ip->name, frame.owner->ns)) { CfOut(OUTPUT_LEVEL_ERROR, "", "cf-agent aborted on defined class \"%s\" defined in bundle %s\n", copy, frame.owner->name); exit(1); } } if (!ABORTBUNDLE) { for (const Item *ip = ctx->heap_abort_current_bundle; ip != NULL; ip = ip->next) { if (IsDefinedClass(ctx, ip->name, frame.owner->ns)) { CfOut(OUTPUT_LEVEL_ERROR, "", " -> Setting abort for \"%s\" when setting \"%s\"", ip->name, context); ABORTBUNDLE = true; break; } } } }