static ExpressionValue EvalTokenAsClass(const char *classname, void *param) { const EvalContext *ctx = ((EvalTokenAsClassContext *)param)->ctx; const char *ns = ((EvalTokenAsClassContext *)param)->ns; char qualified_class[CF_MAXVARSIZE]; if (strcmp(classname, "any") == 0) { return true; } if (strchr(classname, ':')) { if (strncmp(classname, "default:", strlen("default:")) == 0) { snprintf(qualified_class, CF_MAXVARSIZE, "%s", classname + strlen("default:")); } else { snprintf(qualified_class, CF_MAXVARSIZE, "%s", classname); } } else if (ns != NULL && strcmp(ns, "default") != 0) { snprintf(qualified_class, CF_MAXVARSIZE, "%s:%s", ns, (char *)classname); } else { snprintf(qualified_class, CF_MAXVARSIZE, "%s", classname); } if (EvalContextHeapContainsNegated(ctx, qualified_class)) { return false; } if (EvalContextStackFrameContainsNegated(ctx, qualified_class)) { return false; } if (EvalContextHeapContainsHard(ctx, classname)) // Hard classes are always unqualified { return true; } if (EvalContextHeapContainsSoft(ctx, qualified_class)) { return true; } if (EvalContextStackFrameContainsSoft(ctx, qualified_class)) { return true; } return false; }
static void VerifyProcessOp(EvalContext *ctx, Item *procdata, Attributes a, Promise *pp) { int matches = 0, do_signals = true, out_of_range, killed = 0, need_to_restart = true; Item *killlist = NULL; matches = FindPidMatches(ctx, procdata, &killlist, a, pp->promiser); /* promise based on number of matches */ if (a.process_count.min_range != CF_NOINT) /* if a range is specified */ { if ((matches < a.process_count.min_range) || (matches > a.process_count.max_range)) { cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_CHANGE, pp, a, "Process count for '%s' was out of promised range (%d found)", pp->promiser, matches); for (const Rlist *rp = a.process_count.out_of_range_define; rp != NULL; rp = rp->next) { if (!EvalContextHeapContainsSoft(ctx, rp->item)) { EvalContextHeapAddSoft(ctx, rp->item, PromiseGetNamespace(pp)); } } out_of_range = true; } else { for (const Rlist *rp = a.process_count.in_range_define; rp != NULL; rp = rp->next) { if (!EvalContextHeapContainsSoft(ctx, rp->item)) { EvalContextHeapAddSoft(ctx, rp->item, PromiseGetNamespace(pp)); } } cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, a, "Process promise for '%s' is kept", pp->promiser); out_of_range = false; } } else { out_of_range = true; } if (!out_of_range) { return; } if (a.transaction.action == cfa_warn) { do_signals = false; } else { do_signals = true; } /* signal/kill promises for existing matches */ if (do_signals && (matches > 0)) { if (a.process_stop != NULL) { if (DONTDO) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_WARN, pp, a, "Need to keep process-stop promise for '%s', but only a warning is promised", pp->promiser); } else { if (IsExecutable(CommandArg0(a.process_stop))) { ShellCommandReturnsZero(a.process_stop, SHELL_TYPE_NONE); } else { cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_FAIL, pp, a, "Process promise to stop '%s' could not be kept because '%s' the stop operator failed", pp->promiser, a.process_stop); DeleteItemList(killlist); return; } } } killed = DoAllSignals(ctx, killlist, a, pp); } /* delegated promise to restart killed or non-existent entries */ need_to_restart = (a.restart_class != NULL) && (killed || (matches == 0)); DeleteItemList(killlist); if (!need_to_restart) { cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, a, "No restart promised for %s", pp->promiser); return; } else { if (a.transaction.action == cfa_warn) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_WARN, pp, a, "Need to keep restart promise for '%s', but only a warning is promised", pp->promiser); } else { cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_CHANGE, pp, a, "Making a one-time restart promise for '%s'", pp->promiser); EvalContextHeapAddSoft(ctx, a.restart_class, PromiseGetNamespace(pp)); } } }
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; } } } }
void EvalContextHeapAddSoft(EvalContext *ctx, const char *context, const char *ns) { char context_copy[CF_MAXVARSIZE]; char canonified_context[CF_MAXVARSIZE]; strcpy(canonified_context, context); if (Chop(canonified_context, CF_EXPANDSIZE) == -1) { CfOut(OUTPUT_LEVEL_ERROR, "", "Chop was called on a string that seemed to have no terminator"); } CanonifyNameInPlace(canonified_context); if (ns && strcmp(ns, "default") != 0) { snprintf(context_copy, CF_MAXVARSIZE, "%s:%s", ns, canonified_context); } else { strncpy(context_copy, canonified_context, CF_MAXVARSIZE); } CfDebug("EvalContextHeapAddSoft(%s)\n", context_copy); if (strlen(context_copy) == 0) { return; } if (IsRegexItemIn(ctx, ctx->heap_abort_current_bundle, context_copy)) { CfOut(OUTPUT_LEVEL_ERROR, "", "Bundle aborted on defined class \"%s\"\n", context_copy); ABORTBUNDLE = true; } if (IsRegexItemIn(ctx, ctx->heap_abort, context_copy)) { CfOut(OUTPUT_LEVEL_ERROR, "", "cf-agent aborted on defined class \"%s\"\n", context_copy); exit(1); } if (EvalContextHeapContainsSoft(ctx, context_copy)) { return; } StringSetAdd(ctx->heap_soft, xstrdup(context_copy)); for (const Item *ip = ctx->heap_abort; ip != NULL; ip = ip->next) { if (IsDefinedClass(ctx, ip->name, ns)) { CfOut(OUTPUT_LEVEL_ERROR, "", "cf-agent aborted on defined class \"%s\" defined in bundle %s\n", ip->name, StackFrameOwnerName(LastStackFrame(ctx, 0))); exit(1); } } if (!ABORTBUNDLE) { for (const Item *ip = ctx->heap_abort_current_bundle; ip != NULL; ip = ip->next) { if (IsDefinedClass(ctx, ip->name, ns)) { CfOut(OUTPUT_LEVEL_ERROR, "", " -> Setting abort for \"%s\" when setting \"%s\"", ip->name, context_copy); ABORTBUNDLE = true; break; } } } }
void NewBundleClass(EvalContext *ctx, const char *context, const char *bundle, const char *ns) { char copy[CF_BUFSIZE]; if (ns && strcmp(ns, "default") != 0) { snprintf(copy, CF_MAXVARSIZE, "%s:%s", 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", bundle, 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, bundle); 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, bundle); } if (EvalContextStackFrameContainsSoft(ctx, copy)) { return; } EvalContextStackFrameAddSoft(ctx, copy); for (const Item *ip = ctx->heap_abort; ip != NULL; ip = ip->next) { if (IsDefinedClass(ctx, ip->name, ns)) { CfOut(OUTPUT_LEVEL_ERROR, "", "cf-agent aborted on defined class \"%s\" defined in bundle %s\n", copy, bundle); exit(1); } } if (!ABORTBUNDLE) { for (const Item *ip = ctx->heap_abort_current_bundle; ip != NULL; ip = ip->next) { if (IsDefinedClass(ctx, ip->name, ns)) { CfOut(OUTPUT_LEVEL_ERROR, "", " -> Setting abort for \"%s\" when setting \"%s\"", ip->name, context); ABORTBUNDLE = true; break; } } } }