2 * \file build/parseReqs.c
3 * Parse dependency tag from spec file or from auto-dependency generator.
9 #include <rpm/rpmtypes.h>
10 #include <rpm/rpmlog.h>
11 #include "build/rpmbuild_internal.h"
12 #include "build/rpmbuild_misc.h"
16 #define SKIPWHITE(_x) {while (*(_x) && (risspace(*_x) || *(_x) == ',')) (_x)++;}
17 #define SKIPNONWHITE(_x){while (*(_x) &&!(risspace(*_x) || *(_x) == ',')) (_x)++;}
19 static rpmRC checkSep(const char *s, char c, char **emsg)
21 const char *sep = strchr(s, c);
22 if (sep && strchr(sep + 1, c)) {
23 rasprintf(emsg, "Invalid version (double separator '%c'): %s", c, s);
29 static rpmRC checkEpoch(const char *s, char **emsg)
31 const char *si, *sep = strchr(s, ':');
36 for (si = s; si != sep; si++) {
38 rasprintf(emsg, "Invalid version (epoch must be unsigned integer): %s", s);
45 static rpmRC checkDep(rpmSpec spec, char *N, char *EVR, char **emsg)
48 * Tokens must begin with alphanumeric, _, or /, but we don't know
49 * the spec's encoding so we only check what we can: plain ascii.
51 if (isascii(N[0]) && !(risalnum(N[0]) || N[0] == '_' || N[0] == '/')) {
52 rasprintf(emsg, _("Dependency tokens must begin with alpha-numeric, '_' or '/'"));
57 rasprintf(emsg, _("Versioned file name not permitted"));
60 // if (rpmCharCheck(spec, EVR, ".-_+:%{}~"))
62 if (checkSep(EVR, '-', emsg) != RPMRC_OK ||
63 checkSep(EVR, ':', emsg) != RPMRC_OK ||
64 checkEpoch(EVR, emsg) != RPMRC_OK) {
66 if (rpmExpandNumeric("%{?_wrong_version_format_terminate_build}"))
73 struct parseRCPOTRichData {
78 /* Callback for the rich dependency parser. We use this to do check for invalid
79 * characters and to build a normailzed version of the dependency */
80 static rpmRC parseRCPOTRichCB(void *cbdata, rpmrichParseType type,
81 const char *n, int nl, const char *e, int el, rpmsenseFlags sense,
82 rpmrichOp op, char **emsg) {
83 struct parseRCPOTRichData *data = cbdata;
84 StringBuf sb = data->sb;
87 if (type == RPMRICH_PARSE_ENTER) {
88 appendStringBuf(sb, "(");
89 } else if (type == RPMRICH_PARSE_LEAVE) {
90 appendStringBuf(sb, ")");
91 } else if (type == RPMRICH_PARSE_SIMPLE) {
92 char *N = xmalloc(nl + 1);
94 rstrlcpy(N, n, nl + 1);
95 appendStringBuf(sb, N);
97 char rel[6], *rp = rel;
98 EVR = xmalloc(el + 1);
99 rstrlcpy(EVR, e, el + 1);
101 if (sense & RPMSENSE_LESS)
103 if (sense & RPMSENSE_GREATER)
105 if (sense & RPMSENSE_EQUAL)
109 appendStringBuf(sb, rel);
110 appendStringBuf(sb, EVR);
112 rc = checkDep(data->spec, N, EVR, emsg);
115 } else if (type == RPMRICH_PARSE_OP) {
116 appendStringBuf(sb, " ");
117 appendStringBuf(sb, rpmrichOpStr(op));
118 appendStringBuf(sb, " ");
123 rpmRC parseRCPOT(rpmSpec spec, Package pkg, const char *field, rpmTagVal tagN,
124 int index, rpmsenseFlags tagflags, addReqProvFunction cb, void *cbdata)
126 const char *r, *re, *v, *ve;
128 char * N = NULL, * EVR = NULL;
129 rpmTagVal nametag = RPMTAG_NOT_FOUND;
131 rpmRC rc = RPMRC_FAIL; /* assume failure */
132 int allow_richdeps = 0;
139 case RPMTAG_REQUIRENAME:
140 tagflags |= RPMSENSE_ANY;
142 case RPMTAG_RECOMMENDNAME:
143 case RPMTAG_SUGGESTNAME:
144 case RPMTAG_SUPPLEMENTNAME:
145 case RPMTAG_ENHANCENAME:
146 case RPMTAG_CONFLICTNAME:
149 case RPMTAG_PROVIDENAME:
150 case RPMTAG_OBSOLETENAME:
151 case RPMTAG_ORDERNAME:
155 /* XXX map legacy PreReq into Requires(pre,preun) */
156 nametag = RPMTAG_REQUIRENAME;
157 tagflags |= (RPMSENSE_SCRIPT_PRE|RPMSENSE_SCRIPT_PREUN);
160 case RPMTAG_TRIGGERPREIN:
161 nametag = RPMTAG_TRIGGERNAME;
162 tagflags |= RPMSENSE_TRIGGERPREIN;
164 case RPMTAG_TRIGGERIN:
165 nametag = RPMTAG_TRIGGERNAME;
166 tagflags |= RPMSENSE_TRIGGERIN;
168 case RPMTAG_TRIGGERPOSTUN:
169 nametag = RPMTAG_TRIGGERNAME;
170 tagflags |= RPMSENSE_TRIGGERPOSTUN;
172 case RPMTAG_TRIGGERUN:
173 nametag = RPMTAG_TRIGGERNAME;
174 tagflags |= RPMSENSE_TRIGGERUN;
176 case RPMTAG_BUILDPREREQ:
177 case RPMTAG_BUILDREQUIRES:
178 nametag = RPMTAG_REQUIRENAME;
179 tagflags |= RPMSENSE_ANY;
182 case RPMTAG_BUILDCONFLICTS:
183 nametag = RPMTAG_CONFLICTNAME;
186 case RPMTAG_FILETRIGGERIN:
187 nametag = RPMTAG_FILETRIGGERNAME;
188 tagflags |= RPMSENSE_TRIGGERIN;
190 case RPMTAG_FILETRIGGERUN:
191 nametag = RPMTAG_FILETRIGGERNAME;
192 tagflags |= RPMSENSE_TRIGGERUN;
194 case RPMTAG_FILETRIGGERPOSTUN:
195 nametag = RPMTAG_FILETRIGGERNAME;
196 tagflags |= RPMSENSE_TRIGGERPOSTUN;
198 case RPMTAG_TRANSFILETRIGGERIN:
199 nametag = RPMTAG_TRANSFILETRIGGERNAME;
200 tagflags |= RPMSENSE_TRIGGERIN;
202 case RPMTAG_TRANSFILETRIGGERUN:
203 nametag = RPMTAG_TRANSFILETRIGGERNAME;
204 tagflags |= RPMSENSE_TRIGGERUN;
206 case RPMTAG_TRANSFILETRIGGERPOSTUN:
207 nametag = RPMTAG_TRANSFILETRIGGERNAME;
208 tagflags |= RPMSENSE_TRIGGERPOSTUN;
212 for (r = field; *r != '\0'; r = re) {
217 Flags = (tagflags & ~RPMSENSE_SENSEMASK);
220 struct parseRCPOTRichData data;
221 if (!allow_richdeps) {
222 rasprintf(&emsg, _("No rich dependencies allowed for this type"));
226 data.sb = newStringBuf();
227 if (rpmrichParseForTag(&r, &emsg, parseRCPOTRichCB, &data, nametag) != RPMRC_OK) {
228 freeStringBuf(data.sb);
231 if (cb && cb(cbdata, nametag, getStringBuf(data.sb), NULL, Flags, index) != RPMRC_OK) {
232 rasprintf(&emsg, _("invalid dependency"));
233 freeStringBuf(data.sb);
236 freeStringBuf(data.sb);
243 N = xmalloc((re-r) + 1);
244 rstrlcpy(N, r, (re-r) + 1);
253 re = v; /* ==> next token (if no EVR found) starts here */
255 /* Check for possible logical operator */
257 rpmsenseFlags sense = rpmParseDSFlags(v, ve - v);
266 if (*v == '\0' || ve == v) {
267 rasprintf(&emsg, _("Version required"));
270 EVR = xmalloc((ve-v) + 1);
271 rstrlcpy(EVR, v, (ve-v) + 1);
272 re = ve; /* ==> next token after EVR string starts here */
276 /* check that dependency is well-formed */
277 if (checkDep(spec, N, EVR, &emsg))
280 if (nametag == RPMTAG_OBSOLETENAME) {
281 if (rpmCharCheck(spec, N, WHITELIST_NAME)) {
282 rasprintf(&emsg, _("Only package names are allowed in "
287 rasprintf(&emsg, _("It's not recommended to have "
288 "unversioned Obsoletes"));
289 } else if (Flags & RPMSENSE_GREATER) {
290 rasprintf(&emsg, _("It's not recommended to use "
291 "'>' in Obsoletes"));
295 if (nametag == RPMTAG_FILETRIGGERNAME ||
296 nametag == RPMTAG_TRANSFILETRIGGERNAME) {
298 rasprintf(&emsg, _("Only absolute paths are allowed in "
304 /* Deny more "normal" triggers fired by the same pakage. File triggers are ok */
305 if (nametag == RPMTAG_TRIGGERNAME) {
306 rpmds *pdsp = packageDependencies(pkg, nametag);
307 rpmds newds = rpmdsSingle(nametag, N, EVR, Flags);
309 while (rpmdsNext(*pdsp) >= 0) {
310 if (rpmdsCompare(*pdsp, newds) && (rpmdsFlags(*pdsp) & tagflags )) {
311 rasprintf(&emsg, _("Trigger fired by the same package "
312 "is already defined in spec file"));
321 if (cb && cb(cbdata, nametag, N, EVR, Flags, index) != RPMRC_OK) {
322 rasprintf(&emsg, _("invalid dependency"));
334 int lvl = (rc == RPMRC_OK) ? RPMLOG_WARNING : RPMLOG_ERR;
335 /* Automatic dependencies don't relate to spec lines */
336 if (tagflags & (RPMSENSE_FIND_REQUIRES|RPMSENSE_FIND_PROVIDES)) {
337 rpmlog(lvl, "%s: %s\n", emsg, r);
339 rpmlog(lvl, _("line %d: %s: %s\n"),
340 spec->lineNum, emsg, spec->line);