int ParseFlagString(Rlist *bitlist, u_long *plusmask, u_long *minusmask) { if (bitlist == NULL) { return true; } *plusmask = 0; *minusmask = 0; for (const Rlist *rp = bitlist; rp != NULL; rp = rp->next) { const char *flag = RlistScalarValue(rp); char op = *RlistScalarValue(rp); switch (op) { case '-': *minusmask |= ConvertBSDBits(flag + 1); break; case '+': *plusmask |= ConvertBSDBits(flag + 1); break; default: *plusmask |= ConvertBSDBits(flag); break; } } Log(LOG_LEVEL_DEBUG, "ParseFlagString: [PLUS = %lo] [MINUS = %lo]", *plusmask, *minusmask); return true; }
static bool RlistItemMACLess(void *lhs, void *rhs, ARG_UNUSED void *ctx) { int bytes = 6; unsigned char left[bytes], right[bytes]; int matched_left = 6 == ParseEtherAddress(RlistScalarValue((Rlist*)lhs), left); int matched_right = 6 == ParseEtherAddress(RlistScalarValue((Rlist*)rhs), right); if (matched_left && matched_right) { int difference = memcmp(left, right, bytes); if (difference != 0) return difference < 0; } if (matched_left) { return false; } if (matched_right) { return true; } // neither item matched return RlistItemLess(lhs, rhs, ctx); }
void PromiseIteratorUpdateVariable(EvalContext *ctx, const PromiseIterator *iter) { for (size_t i = 0; i < SeqLength(iter->vars); i++) { CfAssoc *iter_var = SeqAt(iter->vars, i); const Rlist *state = SeqAt(iter->var_states, i); if (!state || state->val.type == RVAL_TYPE_FNCALL) { continue; } assert(state->val.type == RVAL_TYPE_SCALAR); switch (iter_var->dtype) { case CF_DATA_TYPE_STRING_LIST: EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, iter_var->lval, RlistScalarValue(state), CF_DATA_TYPE_STRING, "source=promise"); break; case CF_DATA_TYPE_INT_LIST: EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, iter_var->lval, RlistScalarValue(state), CF_DATA_TYPE_INT, "source=promise"); break; case CF_DATA_TYPE_REAL_LIST: EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, iter_var->lval, RlistScalarValue(state), CF_DATA_TYPE_REAL, "source=promise"); break; default: assert(false); break; } } }
int DoAllSignals(EvalContext *ctx, Item *siglist, Attributes a, const Promise *pp, PromiseResult *result) { Item *ip; Rlist *rp; pid_t pid; int killed = false; if (siglist == NULL) { return 0; } if (a.signals == NULL) { Log(LOG_LEVEL_VERBOSE, "No signals to send for '%s'", pp->promiser); return 0; } for (ip = siglist; ip != NULL; ip = ip->next) { pid = ip->counter; for (rp = a.signals; rp != NULL; rp = rp->next) { int signal = SignalFromString(RlistScalarValue(rp)); if (!DONTDO) { if ((signal == SIGKILL) || (signal == SIGTERM)) { killed = true; } if (kill((pid_t) pid, signal) < 0) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Couldn't send promised signal '%s' (%d) to pid %jd (might be dead). (kill: %s)", RlistScalarValue(rp), signal, (intmax_t)pid, GetErrorStr()); *result = PromiseResultUpdate(*result, PROMISE_RESULT_FAIL); } else { cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_CHANGE, pp, a, "Signalled '%s' (%d) to process %jd (%s)", RlistScalarValue(rp), signal, (intmax_t)pid, ip->name); *result = PromiseResultUpdate(*result, PROMISE_RESULT_CHANGE); } } else { Log(LOG_LEVEL_ERR, "Need to keep signal promise '%s' in process entry '%s'", RlistScalarValue(rp), ip->name); } } } return killed; }
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); }
static int DoAllSignals(Item *siglist, Attributes a, Promise *pp) { Item *ip; Rlist *rp; pid_t pid; int killed = false; CfDebug("DoSignals(%s)\n", pp->promiser); if (siglist == NULL) { return 0; } if (a.signals == NULL) { CfOut(OUTPUT_LEVEL_VERBOSE, "", " -> No signals to send for %s\n", pp->promiser); return 0; } for (ip = siglist; ip != NULL; ip = ip->next) { pid = ip->counter; for (rp = a.signals; rp != NULL; rp = rp->next) { int signal = SignalFromString(rp->item); if (!DONTDO) { if ((signal == SIGKILL) || (signal == SIGTERM)) { killed = true; } if (kill((pid_t) pid, signal) < 0) { cfPS(OUTPUT_LEVEL_VERBOSE, CF_FAIL, "kill", pp, a, " !! Couldn't send promised signal \'%s\' (%d) to pid %jd (might be dead)\n", RlistScalarValue(rp), signal, (intmax_t)pid); } else { cfPS(OUTPUT_LEVEL_INFORM, CF_CHG, "", pp, a, " -> Signalled '%s' (%d) to process %jd (%s)\n", RlistScalarValue(rp), signal, (intmax_t)pid, ip->name); } } else { CfOut(OUTPUT_LEVEL_ERROR, "", " -> Need to keep signal promise \'%s\' in process entry %s", RlistScalarValue(rp), ip->name); } } } return killed; }
static int CheckRegistrySanity(const Attributes *a, const Promise *pp) { assert(a != NULL); bool retval = true; ValidateRegistryPromiser(pp->promiser, pp); if ((a->database.operation) && (strcmp(a->database.operation, "create") == 0)) { if (a->database.rows == NULL) { Log(LOG_LEVEL_INFO, "No row values promised for the MS registry database"); } if (a->database.columns != NULL) { Log(LOG_LEVEL_ERR, "Columns are only used to delete promised values for the MS registry database"); retval = false; } } if ((a->database.operation) && ((strcmp(a->database.operation, "delete") == 0) || (strcmp(a->database.operation, "drop") == 0))) { if (a->database.columns == NULL) { Log(LOG_LEVEL_INFO, "No columns were promised deleted in the MS registry database"); } if (a->database.rows != NULL) { Log(LOG_LEVEL_ERR, "Rows cannot be deleted in the MS registry database, only entire columns"); retval = false; } } for (Rlist *rp = a->database.rows; rp != NULL; rp = rp->next) { if (CountChar(RlistScalarValue(rp), ',') != 2) { Log(LOG_LEVEL_ERR, "Registry row format should be NAME,REG_SZ,VALUE, not '%s'", RlistScalarValue(rp)); retval = false; } } for (Rlist *rp = a->database.columns; rp != NULL; rp = rp->next) { if (CountChar(RlistScalarValue(rp), ',') > 0) { Log(LOG_LEVEL_ERR, "MS registry column format should be NAME only in deletion"); retval = false; } } return retval; }
static void test_last(void) { Rlist *l = NULL; assert_true(RlistLast(l) == NULL); RlistAppendScalar(&l, "a"); assert_string_equal("a", RlistScalarValue(RlistLast(l))); RlistAppendScalar(&l, "b"); assert_string_equal("b", RlistScalarValue(RlistLast(l))); RlistDestroy(l); }
static bool DistributeClass(EvalContext *ctx, const Rlist *dist, const Promise *pp) { int total = 0; const Rlist *rp; for (rp = dist; rp != NULL; rp = rp->next) { int result = IntFromString(RlistScalarValue(rp)); if (result < 0) { Log(LOG_LEVEL_ERR, "Negative 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() * total; assert(0 <= fluct && fluct < total); for (rp = dist; rp != NULL; rp = rp->next) { fluct -= IntFromString(RlistScalarValue(rp)); if (fluct < 0) { break; } } assert(rp); char buffer[CF_MAXVARSIZE]; snprintf(buffer, CF_MAXVARSIZE, "%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; }
bool RlistIsUnresolved(const Rlist *list) { for (const Rlist *rp = list; rp != NULL; rp = rp->next) { if (rp->val.type != RVAL_TYPE_SCALAR) { return true; } if (IsCf3Scalar(RlistScalarValue(rp))) { if (strstr(RlistScalarValue(rp), "$(this)") || strstr(RlistScalarValue(rp), "${this}") || strstr(RlistScalarValue(rp), "$(this.k)") || strstr(RlistScalarValue(rp), "${this.k}") || strstr(RlistScalarValue(rp), "$(this.k[1])") || strstr(RlistScalarValue(rp), "${this.k[1]}") || strstr(RlistScalarValue(rp), "$(this.v)") || strstr(RlistScalarValue(rp), "${this.v}")) { // We should allow this in function args for substitution in maplist() etc // We should allow this.k and this.k[1] and this.v in function args for substitution in maparray() etc } else { return true; } } } return false; }
static int SelectOwnerMatch(EvalContext *ctx, char *path, struct stat *lstatptr, Rlist *crit) { Rlist *rp; char ownerName[CF_BUFSIZE]; int gotOwner; StringSet *leafattrib = StringSetNew(); #ifndef __MINGW32__ // no uids on Windows char buffer[CF_SMALLBUF]; snprintf(buffer, CF_SMALLBUF, "%jd", (uintmax_t) lstatptr->st_uid); StringSetAdd(leafattrib, xstrdup(buffer)); #endif /* __MINGW32__ */ gotOwner = GetOwnerName(path, lstatptr, ownerName, sizeof(ownerName)); if (gotOwner) { StringSetAdd(leafattrib, xstrdup(ownerName)); } else { StringSetAdd(leafattrib, xstrdup("none")); } for (rp = crit; rp != NULL; rp = rp->next) { if (EvalFileResult((char *) rp->item, leafattrib)) { Log(LOG_LEVEL_DEBUG, "Select owner match"); StringSetDestroy(leafattrib); return true; } if (gotOwner && (FullTextMatch(ctx, RlistScalarValue(rp), ownerName))) { Log(LOG_LEVEL_DEBUG, "Select owner match"); StringSetDestroy(leafattrib); return true; } #ifndef __MINGW32__ if (FullTextMatch(ctx, RlistScalarValue(rp), buffer)) { Log(LOG_LEVEL_DEBUG, "Select owner match"); StringSetDestroy(leafattrib); return true; } #endif /* !__MINGW32__ */ } StringSetDestroy(leafattrib); return false; }
static void test_reverse(void) { Rlist *list = RlistFromSplitString("a,b,c", ','); RlistReverse(&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_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_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); }
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 CopyLocalizedReferencesToBundleScope(EvalContext *ctx, const Bundle *bundle, const Rlist *ref_names) { for (const Rlist *rp = ref_names; rp != NULL; rp = rp->next) { const char *mangled = RlistScalarValue(rp); char *demangled = xstrdup(mangled); DeMangleVarRefString(demangled, strlen(demangled)); if (strchr(RlistScalarValue(rp), CF_MAPPEDLIST)) { VarRef *demangled_ref = VarRefParseFromBundle(demangled, bundle); DataType value_type; const void *value = EvalContextVariableGet(ctx, demangled_ref, &value_type); if (!value) { ProgrammingError("Couldn't find extracted variable '%s'", mangled); } VarRef *mangled_ref = VarRefParseFromBundle(mangled, bundle); switch (DataTypeToRvalType(value_type)) { case RVAL_TYPE_LIST: { Rlist *list = RlistCopy(value); RlistFlatten(ctx, &list); EvalContextVariablePut(ctx, mangled_ref, list, value_type, "source=agent"); RlistDestroy(list); } break; case RVAL_TYPE_CONTAINER: case RVAL_TYPE_SCALAR: EvalContextVariablePut(ctx, mangled_ref, value, value_type, "source=agent"); break; case RVAL_TYPE_FNCALL: case RVAL_TYPE_NOPROMISEE: ProgrammingError("Illegal rval type in switch %d", DataTypeToRvalType(value_type)); } VarRefDestroy(mangled_ref); VarRefDestroy(demangled_ref); } free(demangled); } }
static void test_regex_split_empty_chunks() { Rlist *list = RlistFromRegexSplitNoOverflow(":one:two:three:", ":", 5); assert_int_equal(5, RlistLen(list)); assert_string_equal(RlistScalarValue(list), ""); assert_string_equal(RlistScalarValue(list->next), "one"); assert_string_equal(RlistScalarValue(list->next->next), "two"); assert_string_equal(RlistScalarValue(list->next->next->next), "three"); assert_string_equal(RlistScalarValue(list->next->next->next->next), ""); RlistDestroy(list); }
Rlist *ExpandList(EvalContext *ctx, const char *ns, const char *scope, const Rlist *list, int expandnaked) { Rlist *start = NULL; Rval returnval; for (const Rlist *rp = list; rp != NULL; rp = rp->next) { if (!expandnaked && (rp->val.type == RVAL_TYPE_SCALAR) && IsNakedVar(RlistScalarValue(rp), '@')) { returnval = RvalNew(RlistScalarValue(rp), RVAL_TYPE_SCALAR); } else if ((rp->val.type == RVAL_TYPE_SCALAR) && IsNakedVar(RlistScalarValue(rp), '@')) { char naked[CF_MAXVARSIZE]; GetNaked(naked, RlistScalarValue(rp)); if (!IsExpandable(naked)) { VarRef *ref = VarRefParseFromScope(naked, scope); DataType value_type = DATA_TYPE_NONE; const void *value = EvalContextVariableGet(ctx, ref, &value_type); if (value) { returnval = ExpandPrivateRval(ctx, ns, scope, value, DataTypeToRvalType(value_type)); } else { returnval = ExpandPrivateRval(ctx, ns, scope, rp->val.item, rp->val.type); } VarRefDestroy(ref); } else { returnval = ExpandPrivateRval(ctx, ns, scope, rp->val.item, rp->val.type); } } else { returnval = ExpandPrivateRval(ctx, ns, scope, rp->val.item, rp->val.type); } RlistAppend(&start, returnval.item, returnval.type); RvalDestroy(returnval); } return start; }
void RlistFlatten(EvalContext *ctx, Rlist **list) { for (Rlist *rp = *list; rp != NULL;) { if (rp->val.type != RVAL_TYPE_SCALAR) { rp = rp->next; continue; } char naked[CF_BUFSIZE] = ""; if (IsNakedVar(RlistScalarValue(rp), '@')) { GetNaked(naked, RlistScalarValue(rp)); if (!IsExpandable(naked)) { Rval rv; VarRef *ref = VarRefParse(naked); bool var_found = EvalContextVariableGet(ctx, ref, &rv, NULL); VarRefDestroy(ref); if (var_found) { switch (rv.type) { case RVAL_TYPE_LIST: for (const Rlist *srp = rv.item; srp != NULL; srp = srp->next) { RlistAppendRval(list, RvalCopy(srp->val)); } Rlist *next = rp->next; RlistDestroyEntry(list, rp); rp = next; continue; default: ProgrammingError("List variable does not resolve to a list"); RlistAppendRval(list, RvalCopy(rp->val)); break; } } } } rp = rp->next; } }
static void test_split_long(void) { char buf[CF_MAXVARSIZE * 2], *tail = buf + CF_MAXVARSIZE; memset(buf, '$', sizeof(buf) - 1); buf[sizeof(buf) - 1] = '\0'; buf[CF_MAXVARSIZE - 1] = ','; Rlist *list = RlistFromSplitString(buf, ','); assert_int_equal(2, RlistLen(list)); assert_string_equal(tail, RlistScalarValue(list)); assert_string_equal(tail, RlistScalarValue(list->next)); RlistDestroy(list); }
static void test_copy(void) { Rlist *list = NULL, *copy = NULL; RlistPrepend(&list, "stuff", RVAL_TYPE_SCALAR); RlistPrepend(&list, "more-stuff", RVAL_TYPE_SCALAR); copy = RlistCopy(list); assert_string_equal(RlistScalarValue(list), RlistScalarValue(copy)); assert_string_equal(RlistScalarValue(list->next), RlistScalarValue(copy->next)); RlistDestroy(list); RlistDestroy(copy); }
static JsonElement *FnCallToJson(const FnCall *fp) { assert(fp); JsonElement *object = JsonObjectCreate(3); JsonObjectAppendString(object, "name", fp->name); JsonObjectAppendString(object, "type", "function-call"); JsonElement *argsArray = JsonArrayCreate(5); for (Rlist *rp = fp->args; rp != NULL; rp = rp->next) { switch (rp->val.type) { case RVAL_TYPE_SCALAR: JsonArrayAppendString(argsArray, RlistScalarValue(rp)); break; case RVAL_TYPE_FNCALL: JsonArrayAppendObject(argsArray, FnCallToJson(RlistFnCallValue(rp))); break; default: assert(false && "Unknown argument type"); break; } } JsonObjectAppendArray(object, "arguments", argsArray); return object; }
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); }
void FnCallWrite(Writer *writer, const FnCall *call) { WriterWrite(writer, call->name); WriterWriteChar(writer, '('); for (const Rlist *rp = call->args; rp != NULL; rp = rp->next) { switch (rp->val.type) { case RVAL_TYPE_SCALAR: ScalarWrite(writer, RlistScalarValue(rp), true); break; case RVAL_TYPE_FNCALL: FnCallWrite(writer, RlistFnCallValue(rp)); break; default: WriterWrite(writer, "(** Unknown argument **)\n"); break; } if (rp->next != NULL) { WriterWriteChar(writer, ','); } } WriterWriteChar(writer, ')'); }
static int ServicesSanityChecks(Attributes a, const Promise *pp) { Rlist *dep; switch (a.service.service_policy) { case SERVICE_POLICY_START: break; case SERVICE_POLICY_STOP: case SERVICE_POLICY_DISABLE: case SERVICE_POLICY_RESTART: case SERVICE_POLICY_RELOAD: if (strcmp(a.service.service_autostart_policy, "none") != 0) { Log(LOG_LEVEL_ERR, "!! Autostart policy of service promiser '%s' needs to be 'none' when service policy is not 'start', but is '%s'", pp->promiser, a.service.service_autostart_policy); PromiseRef(LOG_LEVEL_ERR, pp); return false; } break; default: Log(LOG_LEVEL_ERR, "Invalid service policy for service '%s'", pp->promiser); PromiseRef(LOG_LEVEL_ERR, pp); return false; } for (dep = a.service.service_depend; dep != NULL; dep = dep->next) { if (strcmp(pp->promiser, RlistScalarValue(dep)) == 0) { Log(LOG_LEVEL_ERR, "Service promiser '%s' has itself as dependency", pp->promiser); PromiseRef(LOG_LEVEL_ERR, pp); return false; } } if (a.service.service_type == NULL) { Log(LOG_LEVEL_ERR, "Service type for service '%s' is not known", pp->promiser); PromiseRef(LOG_LEVEL_ERR, pp); return false; } #ifdef __MINGW32__ if (strcmp(a.service.service_type, "windows") != 0) { Log(LOG_LEVEL_ERR, "Service type for promiser '%s' must be 'windows' on this system, but is '%s'", pp->promiser, a.service.service_type); PromiseRef(LOG_LEVEL_ERR, pp); return false; } #endif /* __MINGW32__ */ return true; }
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; }
int CompareFileHashes(const char *file1, const char *file2, struct stat *sstat, struct stat *dstat, FileCopy fc, AgentConnection *conn) { unsigned char digest1[EVP_MAX_MD_SIZE + 1] = { 0 }, digest2[EVP_MAX_MD_SIZE + 1] = { 0 }; int i; if (sstat->st_size != dstat->st_size) { Log(LOG_LEVEL_DEBUG, "File sizes differ, no need to compute checksum"); return true; } if (conn == NULL) { HashFile(file1, digest1, CF_DEFAULT_DIGEST); HashFile(file2, digest2, CF_DEFAULT_DIGEST); for (i = 0; i < EVP_MAX_MD_SIZE; i++) { if (digest1[i] != digest2[i]) { return true; } } Log(LOG_LEVEL_DEBUG, "Files were identical"); return false; /* only if files are identical */ } else { assert(fc.servers && strcmp(RlistScalarValue(fc.servers), "localhost")); return CompareHashNet(file1, file2, fc.encrypt, conn); /* client.c */ } }
static void DeleteAllClasses(EvalContext *ctx, const Rlist *list) { for (const Rlist *rp = list; rp != NULL; rp = rp->next) { if (CheckParseContext((char *) rp->item, CF_IDRANGE) != SYNTAX_TYPE_MATCH_OK) { return; // TODO: interesting course of action, but why is the check there in the first place? } if (EvalContextHeapContainsHard(ctx, (char *) rp->item)) { Log(LOG_LEVEL_ERR, "You cannot cancel a reserved hard class '%s' in post-condition classes", RlistScalarValue(rp)); } const char *string = (char *) (rp->item); Log(LOG_LEVEL_VERBOSE, "Cancelling class '%s'", string); EvalContextHeapPersistentRemove(string); EvalContextHeapRemoveSoft(ctx, CanonifyName(string)); EvalContextStackFrameAddNegated(ctx, CanonifyName(string)); } }
bool RlistMatchesRegex(const Rlist *list, const char *regex) /* Returns true if any of the "list" of strings matches "regex". Non-scalars in "list" are skipped. */ { if (regex == NULL || list == NULL) { return false; } pcre *rx = CompileRegex(regex); if (!rx) { return false; } for (const Rlist *rp = list; rp != NULL; rp = rp->next) { if (rp->val.type == RVAL_TYPE_SCALAR && StringMatchFullWithPrecompiledRegex(rx, RlistScalarValue(rp))) { pcre_free(rx); return true; } } pcre_free(rx); return false; }
static int ServicesSanityChecks(Attributes a, const Promise *pp) { Rlist *dep; for (dep = a.service.service_depend; dep != NULL; dep = dep->next) { if (strcmp(pp->promiser, RlistScalarValue(dep)) == 0) { Log(LOG_LEVEL_ERR, "Service promiser '%s' has itself as dependency", pp->promiser); PromiseRef(LOG_LEVEL_ERR, pp); return false; } } if (a.service.service_type == NULL) { Log(LOG_LEVEL_ERR, "Service type for service '%s' is not known", pp->promiser); PromiseRef(LOG_LEVEL_ERR, pp); return false; } #ifdef __MINGW32__ if (strcmp(a.service.service_type, "windows") != 0) { Log(LOG_LEVEL_ERR, "Service type for promiser '%s' must be 'windows' on this system, but is '%s'", pp->promiser, a.service.service_type); PromiseRef(LOG_LEVEL_ERR, pp); return false; } #endif /* __MINGW32__ */ return true; }