summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Schroeder <mls@suse.de>2017-09-06 14:46:55 +0200
committerPanu Matilainen <pmatilai@redhat.com>2018-03-28 13:26:35 +0300
commitb1f76f67414e2504a08bec77003ee502319772a9 (patch)
treea9682342ac02f3322ea0cc63c414f72e605438ae
parent2349e0efa3c0e7308d73aa940b5fc1451e484f42 (diff)
downloadrpm-b1f76f67414e2504a08bec77003ee502319772a9.tar.gz
Forbid 'if' richops in 'or' context and 'unless' richops in 'and' context
Guide users to the correct operator instead. (cherry picked from commit 99e6de810904c2b9d32341832f541108c196cc97)
-rw-r--r--build/parseReqs.c2
-rw-r--r--lib/rpmds.c93
-rw-r--r--lib/rpmds.h11
3 files changed, 90 insertions, 16 deletions
diff --git a/build/parseReqs.c b/build/parseReqs.c
index a443505e4..bbf04af1e 100644
--- a/build/parseReqs.c
+++ b/build/parseReqs.c
@@ -232,7 +232,7 @@ rpmRC parseRCPOT(rpmSpec spec, Package pkg, const char *field, rpmTagVal tagN,
}
data.spec = spec;
data.sb = newStringBuf();
- if (rpmrichParse(&r, &emsg, parseRCPOTRichCB, &data) != RPMRC_OK) {
+ if (rpmrichParseForTag(&r, &emsg, parseRCPOTRichCB, &data, nametag) != RPMRC_OK) {
freeStringBuf(data.sb);
goto exit;
}
diff --git a/lib/rpmds.c b/lib/rpmds.c
index c57ac1f7f..d7c08be60 100644
--- a/lib/rpmds.c
+++ b/lib/rpmds.c
@@ -1453,11 +1453,38 @@ static rpmRC parseSimpleDep(const char **dstrp, char **emsg, rpmrichParseFunctio
return RPMRC_OK;
}
-static rpmRC rpmrichParseInternal(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata, int *nowithp)
+#define RICHPARSE_CHECK (1 << 0)
+#define RICHPARSE_NO_WITH (1 << 1)
+#define RICHPARSE_NO_AND (1 << 2)
+#define RICHPARSE_NO_OR (1 << 3)
+
+static rpmRC rpmrichParseCheck(rpmrichOp op, int check, char **emsg)
+{
+ if ((op == RPMRICHOP_WITH || op == RPMRICHOP_WITHOUT) && (check & RICHPARSE_NO_WITH) != 0) {
+ if (emsg)
+ rasprintf(emsg, _("Illegal ops in with/without"));
+ return RPMRC_FAIL;
+ }
+ if ((check & RICHPARSE_CHECK) == 0)
+ return RPMRC_OK;
+ if ((op == RPMRICHOP_AND || op == RPMRICHOP_IF) && (check & RICHPARSE_NO_AND) != 0) {
+ if (emsg)
+ rasprintf(emsg, _("Illegal context for 'unless', please use 'or' instead"));
+ return RPMRC_FAIL;
+ }
+ if ((op == RPMRICHOP_OR || op == RPMRICHOP_UNLESS) && (check & RICHPARSE_NO_OR) != 0) {
+ if (emsg)
+ rasprintf(emsg, _("Illegal context for 'if', please use 'and' instead"));
+ return RPMRC_FAIL;
+ }
+ return RPMRC_OK;
+}
+
+static rpmRC rpmrichParseInternal(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata, int *checkp)
{
const char *p = *dstrp, *pe;
- rpmrichOp op = RPMRICHOP_SINGLE, chainop = 0;
- int nowith = 0;
+ rpmrichOp op = RPMRICHOP_SINGLE, firstop = RPMRICHOP_SINGLE, chainop = 0;
+ int check = checkp ? *checkp : 0;
if (cb(cbdata, RPMRICH_PARSE_ENTER, p, 0, 0, 0, 0, op, emsg) != RPMRC_OK)
return RPMRC_FAIL;
@@ -1477,10 +1504,14 @@ static rpmRC rpmrichParseInternal(const char **dstrp, char **emsg, rpmrichParseF
}
return RPMRC_FAIL;
}
- if (*p == '(') {
- if (rpmrichParseInternal(&p, emsg, cb, cbdata, &nowith) != RPMRC_OK)
- return RPMRC_FAIL;
- } else {
+ if (*p == '(') {
+ int subcheck = check & RICHPARSE_CHECK;
+ if (rpmrichParseInternal(&p, emsg, cb, cbdata, &subcheck) != RPMRC_OK)
+ return RPMRC_FAIL;
+ if (op == RPMRICHOP_IF || op == RPMRICHOP_UNLESS)
+ subcheck &= ~(RICHPARSE_NO_AND | RICHPARSE_NO_OR);
+ check |= subcheck;
+ } else {
if (parseSimpleDep(&p, emsg, cb, cbdata) != RPMRC_OK)
return RPMRC_FAIL;
}
@@ -1495,6 +1526,9 @@ static rpmRC rpmrichParseInternal(const char **dstrp, char **emsg, rpmrichParseF
pe = p;
if (parseRichDepOp(&pe, &op, emsg) != RPMRC_OK)
return RPMRC_FAIL;
+ if (firstop == RPMRICHOP_SINGLE)
+ firstop = op;
+
if (op == RPMRICHOP_ELSE && (chainop == RPMRICHOP_IF || chainop == RPMRICHOP_UNLESS))
chainop = 0;
if (chainop && op != chainop) {
@@ -1502,8 +1536,7 @@ static rpmRC rpmrichParseInternal(const char **dstrp, char **emsg, rpmrichParseF
rasprintf(emsg, _("Cannot chain different ops"));
return RPMRC_FAIL;
}
- if (chainop && op != RPMRICHOP_AND && op != RPMRICHOP_OR &&
- op != RPMRICHOP_WITH) {
+ if (chainop && op != RPMRICHOP_AND && op != RPMRICHOP_OR && op != RPMRICHOP_WITH) {
if (emsg)
rasprintf(emsg, _("Can only chain and/or/with ops"));
return RPMRC_FAIL;
@@ -1512,18 +1545,28 @@ static rpmRC rpmrichParseInternal(const char **dstrp, char **emsg, rpmrichParseF
return RPMRC_FAIL;
chainop = op;
p = pe;
- if (nowithp && op != RPMRICHOP_WITH && op != RPMRICHOP_WITHOUT && op != RPMRICHOP_OR)
- *nowithp = 1;
}
- if ((op == RPMRICHOP_WITH || op == RPMRICHOP_WITHOUT) && nowith) {
- if (emsg)
- rasprintf(emsg, _("Illegal ops in with/without"));
+
+ /* check for illegal combinations */
+ if (rpmrichParseCheck(firstop, check, emsg) != RPMRC_OK)
return RPMRC_FAIL;
- }
+
+ /* update check data */
+ if (firstop == RPMRICHOP_IF)
+ check |= RICHPARSE_NO_OR;
+ if (firstop == RPMRICHOP_UNLESS)
+ check |= RICHPARSE_NO_AND;
+ if (op == RPMRICHOP_AND || op == RPMRICHOP_OR)
+ check &= ~(RICHPARSE_NO_AND | RICHPARSE_NO_OR);
+ if (op != RPMRICHOP_SINGLE && op != RPMRICHOP_WITH && op != RPMRICHOP_WITHOUT && op != RPMRICHOP_OR)
+ check |= RICHPARSE_NO_WITH;
+
p++;
if (cb(cbdata, RPMRICH_PARSE_LEAVE, *dstrp, p - *dstrp , 0, 0, 0, op, emsg) != RPMRC_OK)
return RPMRC_FAIL;
*dstrp = p;
+ if (checkp)
+ *checkp |= check;
return RPMRC_OK;
}
@@ -1532,6 +1575,26 @@ rpmRC rpmrichParse(const char **dstrp, char **emsg, rpmrichParseFunction cb, voi
return rpmrichParseInternal(dstrp, emsg, cb, cbdata, NULL);
}
+rpmRC rpmrichParseForTag(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata, rpmTagVal tagN)
+{
+ int check = RICHPARSE_CHECK;
+ if (rpmrichParseInternal(dstrp, emsg, cb, cbdata, &check) != RPMRC_OK)
+ return RPMRC_FAIL;
+ switch (tagN) {
+ case RPMTAG_CONFLICTNAME:
+ case RPMTAG_SUPPLEMENTNAME:
+ case RPMTAG_ENHANCENAME:
+ if (rpmrichParseCheck(RPMRICHOP_OR, check, emsg) != RPMRC_OK)
+ return RPMRC_FAIL;
+ break;
+ default:
+ if (rpmrichParseCheck(RPMRICHOP_AND, check, emsg) != RPMRC_OK)
+ return RPMRC_FAIL;
+ break;
+ }
+ return RPMRC_OK;
+}
+
struct rpmdsParseRichDepData {
rpmds dep;
rpmsenseFlags depflags;
diff --git a/lib/rpmds.h b/lib/rpmds.h
index b1a587dfa..a13dfbef3 100644
--- a/lib/rpmds.h
+++ b/lib/rpmds.h
@@ -495,6 +495,17 @@ typedef rpmRC (*rpmrichParseFunction) (void *cbdata, rpmrichParseType type,
*/
rpmRC rpmrichParse(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata);
+/**
+ * Parse a rich dependency string for a specific tag
+ * @param dstrp pointer to sting, will be updated
+ * @param emsg returns the error string, can be NULL
+ * @param cb callback function
+ * @param cbdata callback function data
+ * @param tagN type of dependency
+ * @return RPMRC_OK on success
+ */
+rpmRC rpmrichParseForTag(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata, rpmTagVal tagN);
+
/**
* Return if current depenency is rich