diff --git i/libpromises/evalfunction.c w/libpromises/evalfunction.c index 2444f273c..dc002c364 100644 --- i/libpromises/evalfunction.c +++ w/libpromises/evalfunction.c @@ -1558,7 +1558,7 @@ static bool AddPackagesMatchingJsonLine(pcre *matcher, JsonElement *json, char * return true; } -static bool GetLegacyPackagesMatching(pcre *matcher, JsonElement *json, const bool installed_mode) +static bool GetLegacyPackagesMatching(pcre *matcher, JsonElement *json, const bool installed_mode, const bool check_mode) { char filename[CF_MAXVARSIZE]; if (installed_mode) @@ -1606,7 +1606,7 @@ static bool GetLegacyPackagesMatching(pcre *matcher, JsonElement *json, const bo return ret; } -static bool GetPackagesMatching(pcre *matcher, JsonElement *json, const bool installed_mode, Rlist *default_inventory) +static bool GetPackagesMatching(pcre *matcher, JsonElement *json, const bool installed_mode, const bool check_mode, Rlist *default_inventory) { dbid database = (installed_mode == true ? dbid_packages_installed : dbid_packages_updates); @@ -1672,6 +1672,11 @@ static bool GetPackagesMatching(pcre *matcher, JsonElement *json, const bool ins { break; } + + if (check_mode && JsonLength(json) > 0) + { + break; + } } SeqDestroy(packages_from_module); } @@ -1689,6 +1694,7 @@ static bool GetPackagesMatching(pcre *matcher, JsonElement *json, const bool ins static FnCallResult FnCallPackagesMatching(ARG_UNUSED EvalContext *ctx, ARG_UNUSED const Policy *policy, const FnCall *fp, const Rlist *finalargs) { + const bool check_mode = (strncmp(fp->name, "is", 2) == 0); const bool installed_mode = (strcmp(fp->name, "packagesmatching") == 0); pcre *matcher; { @@ -1715,12 +1721,12 @@ static FnCallResult FnCallPackagesMatching(ARG_UNUSED EvalContext *ctx, ARG_UNUS if (!default_inventory) { // Legacy package promise - ret = GetLegacyPackagesMatching(matcher, json, installed_mode); + ret = GetLegacyPackagesMatching(matcher, json, installed_mode, check_mode); } else { // We are using package modules. - ret = GetPackagesMatching(matcher, json, installed_mode, default_inventory); + ret = GetPackagesMatching(matcher, json, installed_mode, check_mode, default_inventory); } pcre_free(matcher); @@ -1733,6 +1739,13 @@ static FnCallResult FnCallPackagesMatching(ARG_UNUSED EvalContext *ctx, ARG_UNUS return FnFailure(); } + if (check_mode) + { + const bool empty = (JsonLength(json) == 0); + JsonDestroy(json); + return FnReturnContext(!empty); + } + return (FnCallResult) { FNCALL_SUCCESS, (Rval) { json, RVAL_TYPE_CONTAINER } }; } @@ -8983,6 +8996,10 @@ const FnCallType CF_FNCALL_TYPES[] = FNCALL_OPTION_NONE, FNCALL_CATEGORY_FILES, SYNTAX_STATUS_NORMAL), FnCallTypeNew("isnewerthan", CF_DATA_TYPE_CONTEXT, ISNEWERTHAN_ARGS, &FnCallIsNewerThan, "True if arg1 is newer (modified later) than arg2 (mtime)", FNCALL_OPTION_NONE, FNCALL_CATEGORY_FILES, SYNTAX_STATUS_NORMAL), + FnCallTypeNew("ispackagematching", CF_DATA_TYPE_CONTEXT, PACKAGESMATCHING_ARGS, &FnCallPackagesMatching, "Check if at least one installed package (\"name,version,arch,manager\") matches regex arg1=name,arg2=version,arg3=arch,arg4=method", + FNCALL_OPTION_NONE, FNCALL_CATEGORY_SYSTEM, SYNTAX_STATUS_NORMAL), + FnCallTypeNew("ispackageupdatematching", CF_DATA_TYPE_CONTEXT, PACKAGESMATCHING_ARGS, &FnCallPackagesMatching, "Check if at least one patch (\"name,version,arch,manager\") is available matching regex arg1=name,arg2=version,arg3=arch,arg4=method. Enterprise only.", + FNCALL_OPTION_NONE, FNCALL_CATEGORY_SYSTEM, SYNTAX_STATUS_NORMAL), FnCallTypeNew("isplain", CF_DATA_TYPE_CONTEXT, FILESTAT_ARGS, &FnCallFileStat, "True if the named object is a plain/regular file", FNCALL_OPTION_NONE, FNCALL_CATEGORY_FILES, SYNTAX_STATUS_NORMAL), FnCallTypeNew("isvariable", CF_DATA_TYPE_CONTEXT, ISVARIABLE_ARGS, &FnCallIsVariable, "True if the named variable is defined",