Add macro %isu_package to generate ISU Package
[platform/upstream/rpm.git] / build / parseReqs.c
1 /** \ingroup rpmbuild
2  * \file build/parseReqs.c
3  *  Parse dependency tag from spec file or from auto-dependency generator.
4  */
5
6 #include "system.h"
7
8 #include <ctype.h>
9 #include <rpm/rpmtypes.h>
10 #include <rpm/rpmlog.h>
11 #include "build/rpmbuild_internal.h"
12 #include "build/rpmbuild_misc.h"
13 #include "debug.h"
14
15
16 #define SKIPWHITE(_x)   {while (*(_x) && (risspace(*_x) || *(_x) == ',')) (_x)++;}
17 #define SKIPNONWHITE(_x){while (*(_x) &&!(risspace(*_x) || *(_x) == ',')) (_x)++;}
18
19 static rpmRC checkSep(const char *s, char c, char **emsg)
20 {
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);
24         return RPMRC_FAIL;
25     }
26     return RPMRC_OK;
27 }
28
29 static rpmRC checkEpoch(const char *s, char **emsg)
30 {
31     const char *si, *sep = strchr(s, ':');
32
33     if (!sep)
34         return RPMRC_OK;
35
36     for (si = s; si != sep; si++) {
37         if (!risdigit(*si)) {
38             rasprintf(emsg, "Invalid version (epoch must be unsigned integer): %s", s);
39             return RPMRC_FAIL;
40         }
41     }
42     return RPMRC_OK;
43 }
44
45 static rpmRC checkDep(rpmSpec spec, char *N, char *EVR, char **emsg)
46 {
47     /* 
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.
50      */
51     if (isascii(N[0]) && !(risalnum(N[0]) || N[0] == '_' || N[0] == '/')) {
52         rasprintf(emsg, _("Dependency tokens must begin with alpha-numeric, '_' or '/'"));
53         return RPMRC_FAIL;
54     }
55     if (EVR) {
56         if (N[0] == '/') {
57             rasprintf(emsg, _("Versioned file name not permitted"));
58             return RPMRC_FAIL;
59         }
60       //  if (rpmCharCheck(spec, EVR, ".-_+:%{}~"))
61        //     return RPMRC_FAIL;
62         if (checkSep(EVR, '-', emsg) != RPMRC_OK ||
63             checkSep(EVR, ':', emsg) != RPMRC_OK ||
64             checkEpoch(EVR, emsg) != RPMRC_OK) {
65
66             if (rpmExpandNumeric("%{?_wrong_version_format_terminate_build}"))
67                 return RPMRC_FAIL;
68         }
69     }
70     return RPMRC_OK;
71 }
72
73 struct parseRCPOTRichData {
74     rpmSpec spec;
75     StringBuf sb;
76 };
77
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;
85     rpmRC rc = RPMRC_OK;
86
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);
93         char *EVR = NULL;
94         rstrlcpy(N, n, nl + 1);
95         appendStringBuf(sb, N);
96         if (el) {
97             char rel[6], *rp = rel;
98             EVR = xmalloc(el + 1);
99             rstrlcpy(EVR, e, el + 1);
100             *rp++ = ' ';
101             if (sense & RPMSENSE_LESS)
102                 *rp++ = '<';
103             if (sense & RPMSENSE_GREATER)
104                 *rp++ = '>';
105             if (sense & RPMSENSE_EQUAL)
106                 *rp++ = '=';
107             *rp++ = ' ';
108             *rp = 0;
109             appendStringBuf(sb, rel);
110             appendStringBuf(sb, EVR);
111         }
112         rc = checkDep(data->spec, N, EVR, emsg);
113         _free(N);
114         _free(EVR);
115     } else if (type == RPMRICH_PARSE_OP) {
116         appendStringBuf(sb, " ");
117         appendStringBuf(sb, rpmrichOpStr(op));
118         appendStringBuf(sb, " ");
119     }
120     return rc;
121 }
122
123 rpmRC parseRCPOT(rpmSpec spec, Package pkg, const char *field, rpmTagVal tagN,
124                int index, rpmsenseFlags tagflags, addReqProvFunction cb, void *cbdata)
125 {
126         const char *r, *re, *v, *ve;
127         char *emsg = NULL;
128         char * N = NULL, * EVR = NULL;
129         rpmTagVal nametag = RPMTAG_NOT_FOUND;
130         rpmsenseFlags Flags;
131         rpmRC rc = RPMRC_FAIL; /* assume failure */
132         int allow_richdeps = 0;
133
134         if (!cbdata)
135         cbdata = pkg;
136
137         switch (tagN) {
138         default:
139         case RPMTAG_REQUIRENAME:
140         tagflags |= RPMSENSE_ANY;
141         /* fall through */
142         case RPMTAG_RECOMMENDNAME:
143         case RPMTAG_SUGGESTNAME:
144         case RPMTAG_SUPPLEMENTNAME:
145         case RPMTAG_ENHANCENAME:
146         case RPMTAG_CONFLICTNAME:
147         allow_richdeps = 1;
148         /* fall through */
149         case RPMTAG_PROVIDENAME:
150         case RPMTAG_OBSOLETENAME:
151         case RPMTAG_ORDERNAME:
152         nametag = tagN;
153         break;
154         case RPMTAG_PREREQ:
155         /* XXX map legacy PreReq into Requires(pre,preun) */
156         nametag = RPMTAG_REQUIRENAME;
157         tagflags |= (RPMSENSE_SCRIPT_PRE|RPMSENSE_SCRIPT_PREUN);
158         allow_richdeps = 1;
159         break;
160         case RPMTAG_TRIGGERPREIN:
161         nametag = RPMTAG_TRIGGERNAME;
162         tagflags |= RPMSENSE_TRIGGERPREIN;
163         break;
164         case RPMTAG_TRIGGERIN:
165         nametag = RPMTAG_TRIGGERNAME;
166         tagflags |= RPMSENSE_TRIGGERIN;
167         break;
168         case RPMTAG_TRIGGERPOSTUN:
169         nametag = RPMTAG_TRIGGERNAME;
170         tagflags |= RPMSENSE_TRIGGERPOSTUN;
171         break;
172         case RPMTAG_TRIGGERUN:
173         nametag = RPMTAG_TRIGGERNAME;
174         tagflags |= RPMSENSE_TRIGGERUN;
175         break;
176         case RPMTAG_BUILDPREREQ:
177         case RPMTAG_BUILDREQUIRES:
178         nametag = RPMTAG_REQUIRENAME;
179         tagflags |= RPMSENSE_ANY;
180         allow_richdeps = 1;
181         break;
182         case RPMTAG_BUILDCONFLICTS:
183         nametag = RPMTAG_CONFLICTNAME;
184         allow_richdeps = 1;
185         break;
186         case RPMTAG_FILETRIGGERIN:
187         nametag = RPMTAG_FILETRIGGERNAME;
188         tagflags |= RPMSENSE_TRIGGERIN;
189         break;
190         case RPMTAG_FILETRIGGERUN:
191         nametag = RPMTAG_FILETRIGGERNAME;
192         tagflags |= RPMSENSE_TRIGGERUN;
193         break;
194         case RPMTAG_FILETRIGGERPOSTUN:
195         nametag = RPMTAG_FILETRIGGERNAME;
196         tagflags |= RPMSENSE_TRIGGERPOSTUN;
197         break;
198         case RPMTAG_TRANSFILETRIGGERIN:
199         nametag = RPMTAG_TRANSFILETRIGGERNAME;
200         tagflags |= RPMSENSE_TRIGGERIN;
201         break;
202         case RPMTAG_TRANSFILETRIGGERUN:
203         nametag = RPMTAG_TRANSFILETRIGGERNAME;
204         tagflags |= RPMSENSE_TRIGGERUN;
205         break;
206         case RPMTAG_TRANSFILETRIGGERPOSTUN:
207         nametag = RPMTAG_TRANSFILETRIGGERNAME;
208         tagflags |= RPMSENSE_TRIGGERPOSTUN;
209         break;
210         }
211
212         for (r = field; *r != '\0'; r = re) {
213         SKIPWHITE(r);
214         if (*r == '\0')
215                 break;
216
217         Flags = (tagflags & ~RPMSENSE_SENSEMASK);
218
219         if (r[0] == '(') {
220                 struct parseRCPOTRichData data;
221                 if (!allow_richdeps) {
222                 rasprintf(&emsg, _("No rich dependencies allowed for this type"));
223                 goto exit;
224                 }
225                 data.spec = spec;
226                 data.sb = newStringBuf();
227                 if (rpmrichParseForTag(&r, &emsg, parseRCPOTRichCB, &data, nametag) != RPMRC_OK) {
228                 freeStringBuf(data.sb);
229                 goto exit;
230                 }
231                 if (cb && cb(cbdata, nametag, getStringBuf(data.sb), NULL, Flags, index) != RPMRC_OK) {
232                 rasprintf(&emsg, _("invalid dependency"));
233                 freeStringBuf(data.sb);
234                 goto exit;
235                 }
236                 freeStringBuf(data.sb);
237                 re = r;
238                 continue;
239         }
240
241         re = r;
242         SKIPNONWHITE(re);
243         N = xmalloc((re-r) + 1);
244         rstrlcpy(N, r, (re-r) + 1);
245
246         /* Parse EVR */
247         EVR = NULL;
248         v = re;
249         SKIPWHITE(v);
250         ve = v;
251         SKIPNONWHITE(ve);
252
253         re = v; /* ==> next token (if no EVR found) starts here */
254
255         /* Check for possible logical operator */
256         if (ve > v) {
257                 rpmsenseFlags sense = rpmParseDSFlags(v, ve - v);
258                 if (sense) {
259                 Flags |= sense;
260
261                 /* now parse EVR */
262                 v = ve;
263                 SKIPWHITE(v);
264                 ve = v;
265                 SKIPNONWHITE(ve);
266                 if (*v == '\0' || ve == v) {
267                         rasprintf(&emsg, _("Version required"));
268                         goto exit;
269                 }
270                 EVR = xmalloc((ve-v) + 1);
271                 rstrlcpy(EVR, v, (ve-v) + 1);
272                 re = ve;        /* ==> next token after EVR string starts here */
273                 }
274         }
275
276         /* check that dependency is well-formed */
277         if (checkDep(spec, N, EVR, &emsg))
278                 goto exit;
279
280         if (nametag == RPMTAG_OBSOLETENAME) {
281                 if (rpmCharCheck(spec, N, WHITELIST_NAME)) {
282                 rasprintf(&emsg, _("Only package names are allowed in "
283                                    "Obsoletes"));
284                 goto exit;
285                 }
286                 if (!EVR) {
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"));
292                 }
293         }
294
295         if (nametag == RPMTAG_FILETRIGGERNAME ||
296                 nametag == RPMTAG_TRANSFILETRIGGERNAME) {
297                 if (N[0] != '/') {
298                 rasprintf(&emsg, _("Only absolute paths are allowed in "
299                                         "file triggers"));
300                 }
301         }
302
303
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);
308                 rpmdsInit(*pdsp);
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"));
313                         break;
314                 }
315                 }
316                 rpmdsFree(newds);
317                 if (emsg)
318                 goto exit;
319         }
320
321         if (cb && cb(cbdata, nametag, N, EVR, Flags, index) != RPMRC_OK) {
322                 rasprintf(&emsg, _("invalid dependency"));
323                 goto exit;
324         }
325
326         N = _free(N);
327         EVR = _free(EVR);
328
329         }
330         rc = RPMRC_OK;
331
332 exit:
333         if (emsg) {
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);
338         } else {
339                 rpmlog(lvl, _("line %d: %s: %s\n"),
340                    spec->lineNum, emsg, spec->line);
341         }
342         free(emsg);
343         }
344         _free(N);
345         _free(EVR);
346
347         return rc;
348 }
349