Check for valid chars in Requires/Provides as well
[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 <rpm/rpmtypes.h>
9 #include <rpm/rpmbuild.h>
10 #include <rpm/rpmlog.h>
11 #include "debug.h"
12
13 /**
14  */
15 static struct ReqComp {
16 const char * token;
17     rpmsenseFlags sense;
18 } const ReqComparisons[] = {
19     { "<=", RPMSENSE_LESS | RPMSENSE_EQUAL},
20     { "=<", RPMSENSE_LESS | RPMSENSE_EQUAL},
21     { "<", RPMSENSE_LESS},
22
23     { "==", RPMSENSE_EQUAL},
24     { "=", RPMSENSE_EQUAL},
25     
26     { ">=", RPMSENSE_GREATER | RPMSENSE_EQUAL},
27     { "=>", RPMSENSE_GREATER | RPMSENSE_EQUAL},
28     { ">", RPMSENSE_GREATER},
29
30     { NULL, 0 },
31 };
32
33 #define SKIPWHITE(_x)   {while(*(_x) && (risspace(*_x) || *(_x) == ',')) (_x)++;}
34 #define SKIPNONWHITE(_x){while(*(_x) &&!(risspace(*_x) || *(_x) == ',')) (_x)++;}
35
36 rpmRC parseRCPOT(rpmSpec spec, Package pkg, const char *field, rpmTag tagN,
37                int index, rpmsenseFlags tagflags)
38 {
39     const char *r, *re, *v, *ve;
40     char * N, * EVR;
41     rpmsenseFlags Flags;
42     Header h;
43
44     switch (tagN) {
45     case RPMTAG_PROVIDEFLAGS:
46         tagflags |= RPMSENSE_PROVIDES;
47         h = pkg->header;
48         break;
49     case RPMTAG_OBSOLETEFLAGS:
50         tagflags |= RPMSENSE_OBSOLETES;
51         h = pkg->header;
52         break;
53     case RPMTAG_CONFLICTFLAGS:
54         tagflags |= RPMSENSE_CONFLICTS;
55         h = pkg->header;
56         break;
57     case RPMTAG_BUILDCONFLICTS:
58         tagflags |= RPMSENSE_CONFLICTS;
59         h = spec->buildRestrictions;
60         break;
61     case RPMTAG_PREREQ:
62         /* XXX map legacy PreReq into Requires(pre,preun) */
63         tagflags |= (RPMSENSE_SCRIPT_PRE|RPMSENSE_SCRIPT_PREUN);
64         h = pkg->header;
65         break;
66     case RPMTAG_TRIGGERPREIN:
67         tagflags |= RPMSENSE_TRIGGERPREIN;
68         h = pkg->header;
69         break;
70     case RPMTAG_TRIGGERIN:
71         tagflags |= RPMSENSE_TRIGGERIN;
72         h = pkg->header;
73         break;
74     case RPMTAG_TRIGGERPOSTUN:
75         tagflags |= RPMSENSE_TRIGGERPOSTUN;
76         h = pkg->header;
77         break;
78     case RPMTAG_TRIGGERUN:
79         tagflags |= RPMSENSE_TRIGGERUN;
80         h = pkg->header;
81         break;
82     case RPMTAG_BUILDPREREQ:
83     case RPMTAG_BUILDREQUIRES:
84         tagflags |= RPMSENSE_ANY;
85         h = spec->buildRestrictions;
86         break;
87     default:
88     case RPMTAG_REQUIREFLAGS:
89         tagflags |= RPMSENSE_ANY;
90         h = pkg->header;
91         break;
92     }
93
94     for (r = field; *r != '\0'; r = re) {
95         SKIPWHITE(r);
96         if (*r == '\0')
97             break;
98
99         Flags = (tagflags & ~RPMSENSE_SENSEMASK);
100
101         /* 
102          * Tokens must begin with alphanumeric, _, or /, but we don't know
103          * the spec's encoding so we only check what we can: plain ascii.
104          */
105         if (isascii(r[0]) && !(risalnum(r[0]) || r[0] == '_' || r[0] == '/')) {
106             rpmlog(RPMLOG_ERR,
107                      _("line %d: Dependency tokens must begin with alpha-numeric, '_' or '/': %s\n"),
108                      spec->lineNum, spec->line);
109             return RPMRC_FAIL;
110         }
111
112         re = r;
113         SKIPNONWHITE(re);
114         N = xmalloc((re-r) + 1);
115         rstrlcpy(N, r, (re-r) + 1);
116
117         /* Check for weird characters in Requires/Provides, etc.*/
118         if (r[0] != '/') {
119             if (charCheck(spec, N, re-r, ".-_+()")) return RPMRC_FAIL;
120         }
121
122         /* Parse EVR */
123         v = re;
124         SKIPWHITE(v);
125         ve = v;
126         SKIPNONWHITE(ve);
127
128         re = v; /* ==> next token (if no EVR found) starts here */
129
130         /* Check for possible logical operator */
131         if (ve > v) {
132           const struct ReqComp *rc;
133           for (rc = ReqComparisons; rc->token != NULL; rc++) {
134             if ((ve-v) != strlen(rc->token) || strncmp(v, rc->token, (ve-v)))
135                 continue;
136
137             if (r[0] == '/') {
138                 rpmlog(RPMLOG_ERR,
139                          _("line %d: Versioned file name not permitted: %s\n"),
140                          spec->lineNum, spec->line);
141                 return RPMRC_FAIL;
142             }
143
144             switch(tagN) {
145             case RPMTAG_BUILDPREREQ:
146             case RPMTAG_PREREQ:
147             case RPMTAG_PROVIDEFLAGS:
148             case RPMTAG_OBSOLETEFLAGS:
149                 /* Add prereq on rpmlib that has versioned dependencies. */
150                 if (!rpmExpandNumeric("%{?_noVersionedDependencies}"))
151                     (void) rpmlibNeedsFeature(h, "VersionedDependencies", "3.0.3-1");
152                 break;
153             default:
154                 break;
155             }
156             Flags |= rc->sense;
157
158             /* now parse EVR */
159             v = ve;
160             SKIPWHITE(v);
161             ve = v;
162             SKIPNONWHITE(ve);
163             break;
164           }
165         }
166
167         if (Flags & RPMSENSE_SENSEMASK) {
168             if (*v == '\0' || ve == v) {
169                 rpmlog(RPMLOG_ERR, _("line %d: Version required: %s\n"),
170                         spec->lineNum, spec->line);
171                 return RPMRC_FAIL;
172             }
173             EVR = xmalloc((ve-v) + 1);
174             rstrlcpy(EVR, v, (ve-v) + 1);
175             if (charCheck(spec, N, ve-v, ".-_+")) return RPMRC_FAIL;
176             re = ve;    /* ==> next token after EVR string starts here */
177         } else
178             EVR = NULL;
179
180         (void) addReqProv(spec, h, tagN, N, EVR, Flags, index);
181
182         N = _free(N);
183         EVR = _free(EVR);
184
185     }
186
187     return RPMRC_OK;
188 }