File: | build/parseSpec.c |
Warning: | line 531, column 20 Access to field 'header' results in a dereference of a null pointer (loaded from field 'packages') |
1 | /** \ingroup rpmbuild | |||
2 | * \file build/parseSpec.c | |||
3 | * Top level dispatcher for spec file parsing. | |||
4 | */ | |||
5 | ||||
6 | #include "system.h" | |||
7 | ||||
8 | #include <errno(*__errno_location ()).h> | |||
9 | #ifdef HAVE_ICONV1 | |||
10 | #include <iconv.h> | |||
11 | #endif | |||
12 | ||||
13 | #include <rpm/rpmtypes.h> | |||
14 | #include <rpm/rpmlib.h> /* RPM_MACHTABLE & related */ | |||
15 | #include <rpm/rpmds.h> | |||
16 | #include <rpm/rpmts.h> | |||
17 | #include <rpm/rpmlog.h> | |||
18 | #include <rpm/rpmfileutil.h> | |||
19 | #include "build/rpmbuild_internal.h" | |||
20 | #include "build/rpmbuild_misc.h" | |||
21 | #include "debug.h" | |||
22 | ||||
23 | #define SKIPSPACE(s){ while (*(s) && risspace(*(s))) (s)++; } { while (*(s) && risspace(*(s))) (s)++; } | |||
24 | #define SKIPNONSPACE(s){ while (*(s) && !risspace(*(s))) (s)++; } { while (*(s) && !risspace(*(s))) (s)++; } | |||
25 | #define ISMACRO(s,m)(rstreqn((s), (m), sizeof((m))-1) && !risalpha((s)[sizeof ((m))-1])) (rstreqn((s), (m), sizeof((m))-1) && !risalpha((s)[sizeof((m))-1])) | |||
26 | #define ISMACROWITHARG(s,m)(rstreqn((s), (m), sizeof((m))-1) && (risblank((s)[sizeof ((m))-1]) || !(s)[sizeof((m))-1])) (rstreqn((s), (m), sizeof((m))-1) && (risblank((s)[sizeof((m))-1]) || !(s)[sizeof((m))-1])) | |||
27 | ||||
28 | #define LEN_AND_STR(_tag)(sizeof(_tag)-1), (_tag) (sizeof(_tag)-1), (_tag) | |||
29 | ||||
30 | typedef struct OpenFileInfo { | |||
31 | char * fileName; | |||
32 | FILE *fp; | |||
33 | int lineNum; | |||
34 | char *readBuf; | |||
35 | size_t readBufLen; | |||
36 | const char * readPtr; | |||
37 | struct OpenFileInfo * next; | |||
38 | } OFI_t; | |||
39 | ||||
40 | static const struct PartRec { | |||
41 | int part; | |||
42 | size_t len; | |||
43 | const char * token; | |||
44 | } partList[] = { | |||
45 | { PART_PREAMBLE, LEN_AND_STR("%package")(sizeof("%package")-1), ("%package")}, | |||
46 | { PART_PREP, LEN_AND_STR("%prep")(sizeof("%prep")-1), ("%prep")}, | |||
47 | { PART_BUILD, LEN_AND_STR("%build")(sizeof("%build")-1), ("%build")}, | |||
48 | { PART_INSTALL, LEN_AND_STR("%install")(sizeof("%install")-1), ("%install")}, | |||
49 | { PART_CHECK, LEN_AND_STR("%check")(sizeof("%check")-1), ("%check")}, | |||
50 | { PART_CLEAN, LEN_AND_STR("%clean")(sizeof("%clean")-1), ("%clean")}, | |||
51 | { PART_PREUN, LEN_AND_STR("%preun")(sizeof("%preun")-1), ("%preun")}, | |||
52 | { PART_POSTUN, LEN_AND_STR("%postun")(sizeof("%postun")-1), ("%postun")}, | |||
53 | { PART_PRETRANS, LEN_AND_STR("%pretrans")(sizeof("%pretrans")-1), ("%pretrans")}, | |||
54 | { PART_POSTTRANS, LEN_AND_STR("%posttrans")(sizeof("%posttrans")-1), ("%posttrans")}, | |||
55 | { PART_PRE, LEN_AND_STR("%pre")(sizeof("%pre")-1), ("%pre")}, | |||
56 | { PART_POST, LEN_AND_STR("%post")(sizeof("%post")-1), ("%post")}, | |||
57 | { PART_FILES, LEN_AND_STR("%files")(sizeof("%files")-1), ("%files")}, | |||
58 | { PART_CHANGELOG, LEN_AND_STR("%changelog")(sizeof("%changelog")-1), ("%changelog")}, | |||
59 | { PART_DESCRIPTION, LEN_AND_STR("%description")(sizeof("%description")-1), ("%description")}, | |||
60 | { PART_TRIGGERPOSTUN, LEN_AND_STR("%triggerpostun")(sizeof("%triggerpostun")-1), ("%triggerpostun")}, | |||
61 | { PART_TRIGGERPREIN, LEN_AND_STR("%triggerprein")(sizeof("%triggerprein")-1), ("%triggerprein")}, | |||
62 | { PART_TRIGGERUN, LEN_AND_STR("%triggerun")(sizeof("%triggerun")-1), ("%triggerun")}, | |||
63 | { PART_TRIGGERIN, LEN_AND_STR("%triggerin")(sizeof("%triggerin")-1), ("%triggerin")}, | |||
64 | { PART_TRIGGERIN, LEN_AND_STR("%trigger")(sizeof("%trigger")-1), ("%trigger")}, | |||
65 | { PART_VERIFYSCRIPT, LEN_AND_STR("%verifyscript")(sizeof("%verifyscript")-1), ("%verifyscript")}, | |||
66 | { PART_POLICIES, LEN_AND_STR("%sepolicy")(sizeof("%sepolicy")-1), ("%sepolicy")}, | |||
67 | { PART_FILETRIGGERIN, LEN_AND_STR("%filetriggerin")(sizeof("%filetriggerin")-1), ("%filetriggerin")}, | |||
68 | { PART_FILETRIGGERIN, LEN_AND_STR("%filetrigger")(sizeof("%filetrigger")-1), ("%filetrigger")}, | |||
69 | { PART_FILETRIGGERUN, LEN_AND_STR("%filetriggerun")(sizeof("%filetriggerun")-1), ("%filetriggerun")}, | |||
70 | { PART_FILETRIGGERPOSTUN, LEN_AND_STR("%filetriggerpostun")(sizeof("%filetriggerpostun")-1), ("%filetriggerpostun")}, | |||
71 | { PART_TRANSFILETRIGGERIN, LEN_AND_STR("%transfiletriggerin")(sizeof("%transfiletriggerin")-1), ("%transfiletriggerin")}, | |||
72 | { PART_TRANSFILETRIGGERIN, LEN_AND_STR("%transfiletrigger")(sizeof("%transfiletrigger")-1), ("%transfiletrigger")}, | |||
73 | { PART_TRANSFILETRIGGERUN, LEN_AND_STR("%transfiletriggerun")(sizeof("%transfiletriggerun")-1), ("%transfiletriggerun")}, | |||
74 | { PART_TRANSFILETRIGGERUN, LEN_AND_STR("%transfiletriggerun")(sizeof("%transfiletriggerun")-1), ("%transfiletriggerun")}, | |||
75 | { PART_TRANSFILETRIGGERPOSTUN, LEN_AND_STR("%transfiletriggerpostun")(sizeof("%transfiletriggerpostun")-1), ("%transfiletriggerpostun" )}, | |||
76 | { PART_EMPTY, LEN_AND_STR("%end")(sizeof("%end")-1), ("%end")}, | |||
77 | {0, 0, 0} | |||
78 | }; | |||
79 | ||||
80 | int isPart(const char *line) | |||
81 | { | |||
82 | const struct PartRec *p; | |||
83 | ||||
84 | for (p = partList; p->token != NULL((void*)0); p++) { | |||
85 | char c; | |||
86 | if (rstrncasecmp(line, p->token, p->len)) | |||
87 | continue; | |||
88 | c = *(line + p->len); | |||
89 | if (c == '\0' || risspace(c)) | |||
90 | break; | |||
91 | } | |||
92 | ||||
93 | return (p->token ? p->part : PART_NONE); | |||
94 | } | |||
95 | ||||
96 | /** | |||
97 | */ | |||
98 | static int matchTok(const char *token, const char *line) | |||
99 | { | |||
100 | const char *b, *be = line; | |||
101 | size_t toklen = strlen(token); | |||
102 | int rc = 0; | |||
103 | ||||
104 | while ( *(b = be) != '\0' ) { | |||
105 | SKIPSPACE(b){ while (*(b) && risspace(*(b))) (b)++; }; | |||
106 | be = b; | |||
107 | SKIPNONSPACE(be){ while (*(be) && !risspace(*(be))) (be)++; }; | |||
108 | if (be == b) | |||
109 | break; | |||
110 | if (toklen != (be-b) || rstrncasecmp(token, b, (be-b))) | |||
111 | continue; | |||
112 | rc = 1; | |||
113 | break; | |||
114 | } | |||
115 | ||||
116 | return rc; | |||
117 | } | |||
118 | ||||
119 | int handleComments(char *s) | |||
120 | { | |||
121 | SKIPSPACE(s){ while (*(s) && risspace(*(s))) (s)++; }; | |||
122 | if (*s == '#') { | |||
123 | *s = '\0'; | |||
124 | return 1; | |||
125 | } | |||
126 | return 0; | |||
127 | } | |||
128 | ||||
129 | /* Push a file to spec's file stack, return the newly pushed entry */ | |||
130 | static OFI_t * pushOFI(rpmSpec spec, const char *fn) | |||
131 | { | |||
132 | OFI_t *ofi = xcalloc(1, sizeof(*ofi))rcalloc((1), (sizeof(*ofi))); | |||
133 | ||||
134 | ofi->fp = NULL((void*)0); | |||
135 | ofi->fileName = xstrdup(fn)rstrdup((fn)); | |||
136 | ofi->lineNum = 0; | |||
137 | ofi->readBufLen = BUFSIZ8192; | |||
138 | ofi->readBuf = xmalloc(ofi->readBufLen)rmalloc((ofi->readBufLen)); | |||
139 | ofi->readBuf[0] = '\0'; | |||
140 | ofi->readPtr = NULL((void*)0); | |||
141 | ofi->next = spec->fileStack; | |||
142 | ||||
143 | spec->fileStack = ofi; | |||
144 | return spec->fileStack; | |||
145 | } | |||
146 | ||||
147 | /* Pop from spec's file stack */ | |||
148 | static OFI_t * popOFI(rpmSpec spec) | |||
149 | { | |||
150 | if (spec->fileStack) { | |||
151 | OFI_t * ofi = spec->fileStack; | |||
152 | ||||
153 | spec->fileStack = ofi->next; | |||
154 | if (ofi->fp) | |||
155 | fclose(ofi->fp); | |||
156 | free(ofi->fileName); | |||
157 | free(ofi->readBuf); | |||
158 | free(ofi); | |||
159 | } | |||
160 | return spec->fileStack; | |||
161 | } | |||
162 | ||||
163 | static int restoreFirstChar(rpmSpec spec) | |||
164 | { | |||
165 | /* Restore 1st char in (possible) next line */ | |||
166 | if (spec->nextline != NULL((void*)0) && spec->nextpeekc != '\0') { | |||
167 | *spec->nextline = spec->nextpeekc; | |||
168 | spec->nextpeekc = '\0'; | |||
169 | return 1; | |||
170 | } | |||
171 | return 0; | |||
172 | } | |||
173 | ||||
174 | static int expandMacrosInSpecBuf(rpmSpec spec, int strip) | |||
175 | { | |||
176 | char *lbuf = NULL((void*)0); | |||
177 | int isComment = 0; | |||
178 | ||||
179 | /* Don't expand macros (eg. %define) in false branch of %if clause */ | |||
180 | if (!spec->readStack->reading) | |||
181 | return 0; | |||
182 | ||||
183 | lbuf = spec->lbuf; | |||
184 | SKIPSPACE(lbuf){ while (*(lbuf) && risspace(*(lbuf))) (lbuf)++; }; | |||
185 | if (lbuf[0] == '#') | |||
186 | isComment = 1; | |||
187 | ||||
188 | ||||
189 | if (rpmExpandMacros(spec->macros, spec->lbuf, &lbuf, 0) < 0) { | |||
190 | rpmlog(RPMLOG_ERR, _("line %d: %s\n")dcgettext ("rpm", "line %d: %s\n", 5), | |||
191 | spec->lineNum, spec->lbuf); | |||
192 | return 1; | |||
193 | } | |||
194 | ||||
195 | if (strip & STRIP_COMMENTS(1 << 1) && isComment) { | |||
196 | char *bufA = spec->lbuf; | |||
197 | char *bufB = lbuf; | |||
198 | ||||
199 | while (*bufA != '\0' && *bufB != '\0') { | |||
200 | if (*bufA == '%' && *(bufA + 1) == '%') | |||
201 | bufA++; | |||
202 | ||||
203 | if (*bufA != *bufB) | |||
204 | break; | |||
205 | ||||
206 | bufA++; | |||
207 | bufB++; | |||
208 | } | |||
209 | ||||
210 | if (*bufA != '\0' || *bufB != '\0') | |||
211 | rpmlog(RPMLOG_WARNING, | |||
212 | _("Macro expanded in comment on line %d: %s\n")dcgettext ("rpm", "Macro expanded in comment on line %d: %s\n" , 5), | |||
213 | spec->lineNum, bufA); | |||
214 | } | |||
215 | ||||
216 | free(spec->lbuf); | |||
217 | spec->lbuf = lbuf; | |||
218 | spec->lbufSize = strlen(spec->lbuf) + 1; | |||
219 | ||||
220 | return 0; | |||
221 | } | |||
222 | ||||
223 | /* Return zero on success, 1 if we need to read more and -1 on errors. */ | |||
224 | static int copyNextLineFromOFI(rpmSpec spec, OFI_t *ofi, int strip) | |||
225 | { | |||
226 | /* Expand next line from file into line buffer */ | |||
227 | if (!(spec->nextline && *spec->nextline)) { | |||
228 | int pc = 0, bc = 0, nc = 0; | |||
229 | const char *from = ofi->readPtr; | |||
230 | char ch = ' '; | |||
231 | while (from && *from && ch != '\n') { | |||
232 | ch = spec->lbuf[spec->lbufOff] = *from; | |||
233 | spec->lbufOff++; from++; | |||
234 | ||||
235 | if (spec->lbufOff >= spec->lbufSize) { | |||
236 | spec->lbufSize += BUFSIZ8192; | |||
237 | spec->lbuf = realloc(spec->lbuf, spec->lbufSize); | |||
238 | } | |||
239 | } | |||
240 | spec->lbuf[spec->lbufOff] = '\0'; | |||
241 | ofi->readPtr = from; | |||
242 | ||||
243 | /* Check if we need another line before expanding the buffer. */ | |||
244 | for (const char *p = spec->lbuf; *p; p++) { | |||
245 | switch (*p) { | |||
246 | case '\\': | |||
247 | switch (*(p+1)) { | |||
248 | case '\n': p++, nc = 1; break; | |||
249 | case '\0': break; | |||
250 | default: p++; break; | |||
251 | } | |||
252 | break; | |||
253 | case '\n': nc = 0; break; | |||
254 | case '%': | |||
255 | switch (*(p+1)) { | |||
256 | case '{': p++, bc++; break; | |||
257 | case '(': p++, pc++; break; | |||
258 | case '%': p++; break; | |||
259 | } | |||
260 | break; | |||
261 | case '{': if (bc > 0) bc++; break; | |||
262 | case '}': if (bc > 0) bc--; break; | |||
263 | case '(': if (pc > 0) pc++; break; | |||
264 | case ')': if (pc > 0) pc--; break; | |||
265 | } | |||
266 | } | |||
267 | ||||
268 | /* If it doesn't, ask for one more line. */ | |||
269 | if (pc || bc || nc ) { | |||
270 | spec->nextline = ""; | |||
271 | return 1; | |||
272 | } | |||
273 | spec->lbufOff = 0; | |||
274 | ||||
275 | if (expandMacrosInSpecBuf(spec, strip)) | |||
276 | return -1; | |||
277 | ||||
278 | spec->nextline = spec->lbuf; | |||
279 | } | |||
280 | return 0; | |||
281 | } | |||
282 | ||||
283 | static void copyNextLineFinish(rpmSpec spec, int strip) | |||
284 | { | |||
285 | char *last; | |||
286 | char ch; | |||
287 | ||||
288 | /* Find next line in expanded line buffer */ | |||
289 | spec->line = last = spec->nextline; | |||
290 | ch = ' '; | |||
291 | while (*spec->nextline && ch != '\n') { | |||
292 | ch = *spec->nextline++; | |||
293 | if (!risspace(ch)) | |||
294 | last = spec->nextline; | |||
295 | } | |||
296 | ||||
297 | /* Save 1st char of next line in order to terminate current line. */ | |||
298 | if (*spec->nextline != '\0') { | |||
299 | spec->nextpeekc = *spec->nextline; | |||
300 | *spec->nextline = '\0'; | |||
301 | } | |||
302 | ||||
303 | if (strip & STRIP_COMMENTS(1 << 1)) | |||
304 | handleComments(spec->line); | |||
305 | ||||
306 | if (strip & STRIP_TRAILINGSPACE(1 << 0)) | |||
307 | *last = '\0'; | |||
308 | } | |||
309 | ||||
310 | static int readLineFromOFI(rpmSpec spec, OFI_t *ofi) | |||
311 | { | |||
312 | retry: | |||
313 | /* Make sure the current file is open */ | |||
314 | if (ofi->fp == NULL((void*)0)) { | |||
315 | ofi->fp = fopen(ofi->fileName, "r"); | |||
316 | if (ofi->fp == NULL((void*)0)) { | |||
317 | rpmlog(RPMLOG_ERR, _("Unable to open %s: %s\n")dcgettext ("rpm", "Unable to open %s: %s\n", 5), | |||
318 | ofi->fileName, strerror(errno(*__errno_location ()))); | |||
319 | return PART_ERROR; | |||
320 | } | |||
321 | spec->lineNum = ofi->lineNum = 0; | |||
322 | } | |||
323 | ||||
324 | /* Make sure we have something in the read buffer */ | |||
325 | if (!(ofi->readPtr && *(ofi->readPtr))) { | |||
326 | if (getline(&ofi->readBuf, &ofi->readBufLen, ofi->fp) <= 0) { | |||
327 | /* EOF, remove this file from the stack */ | |||
328 | ofi = popOFI(spec); | |||
329 | ||||
330 | /* only on last file do we signal EOF to caller */ | |||
331 | if (ofi == NULL((void*)0)) | |||
332 | return 1; | |||
333 | ||||
334 | /* otherwise, go back and try the read again. */ | |||
335 | goto retry; | |||
336 | } | |||
337 | ofi->readPtr = ofi->readBuf; | |||
338 | ofi->lineNum++; | |||
339 | spec->lineNum = ofi->lineNum; | |||
340 | } | |||
341 | return 0; | |||
342 | } | |||
343 | ||||
344 | #define ARGMATCH(s,token,match)do { char *os = s; char *exp = rpmExpand(token, ((void*)0)); while (*s && !risblank(*s)) s++; while (*s && risblank (*s)) s++; if (!*s) { rpmlog(RPMLOG_ERR, dcgettext ("rpm", "%s:%d: Argument expected for %s\n" , 5), ofi->fileName, ofi->lineNum, os); free(exp); return PART_ERROR; } match = matchTok(exp, s); free(exp); } while ( 0) \ | |||
345 | do { \ | |||
346 | char *os = s; \ | |||
347 | char *exp = rpmExpand(token, NULL((void*)0)); \ | |||
348 | while (*s && !risblank(*s)) s++; \ | |||
349 | while (*s && risblank(*s)) s++; \ | |||
350 | if (!*s) { \ | |||
351 | rpmlog(RPMLOG_ERR, _("%s:%d: Argument expected for %s\n")dcgettext ("rpm", "%s:%d: Argument expected for %s\n", 5), ofi->fileName, ofi->lineNum, os); \ | |||
352 | free(exp); \ | |||
353 | return PART_ERROR; \ | |||
354 | } \ | |||
355 | match = matchTok(exp, s); \ | |||
356 | free(exp); \ | |||
357 | } while (0) | |||
358 | ||||
359 | ||||
360 | int readLine(rpmSpec spec, int strip) | |||
361 | { | |||
362 | char *s; | |||
363 | int match; | |||
364 | struct ReadLevelEntry *rl; | |||
365 | OFI_t *ofi = spec->fileStack; | |||
366 | int rc; | |||
367 | int startLine = 0; | |||
368 | ||||
369 | if (!restoreFirstChar(spec)) { | |||
370 | retry: | |||
371 | if ((rc = readLineFromOFI(spec, ofi)) != 0) { | |||
372 | if (spec->readStack->next) { | |||
373 | rpmlog(RPMLOG_ERR, _("line %d: Unclosed %%if\n")dcgettext ("rpm", "line %d: Unclosed %%if\n", 5), | |||
374 | spec->readStack->lineNum); | |||
375 | rc = PART_ERROR; | |||
376 | } else if (startLine > 0) { | |||
377 | rpmlog(RPMLOG_ERR, | |||
378 | _("line %d: unclosed macro or bad line continuation\n")dcgettext ("rpm", "line %d: unclosed macro or bad line continuation\n" , 5), | |||
379 | startLine); | |||
380 | rc = PART_ERROR; | |||
381 | } | |||
382 | return rc; | |||
383 | } | |||
384 | ofi = spec->fileStack; | |||
385 | ||||
386 | /* Copy next file line into the spec line buffer */ | |||
387 | rc = copyNextLineFromOFI(spec, ofi, strip); | |||
388 | if (rc > 0) { | |||
389 | if (startLine == 0) | |||
390 | startLine = spec->lineNum; | |||
391 | goto retry; | |||
392 | } else if (rc < 0) { | |||
393 | return PART_ERROR; | |||
394 | } | |||
395 | } | |||
396 | ||||
397 | copyNextLineFinish(spec, strip); | |||
398 | ||||
399 | s = spec->line; | |||
400 | SKIPSPACE(s){ while (*(s) && risspace(*(s))) (s)++; }; | |||
401 | ||||
402 | match = -1; | |||
403 | if (!spec->readStack->reading && ISMACROWITHARG(s, "%if")(rstreqn((s), ("%if"), sizeof(("%if"))-1) && (risblank ((s)[sizeof(("%if"))-1]) || !(s)[sizeof(("%if"))-1]))) { | |||
404 | match = 0; | |||
405 | } else if (ISMACROWITHARG(s, "%ifarch")(rstreqn((s), ("%ifarch"), sizeof(("%ifarch"))-1) && ( risblank((s)[sizeof(("%ifarch"))-1]) || !(s)[sizeof(("%ifarch" ))-1]))) { | |||
406 | ARGMATCH(s, "%{_target_cpu}", match)do { char *os = s; char *exp = rpmExpand("%{_target_cpu}", (( void*)0)); while (*s && !risblank(*s)) s++; while (*s && risblank(*s)) s++; if (!*s) { rpmlog(RPMLOG_ERR, dcgettext ("rpm", "%s:%d: Argument expected for %s\n", 5), ofi->fileName , ofi->lineNum, os); free(exp); return PART_ERROR; } match = matchTok(exp, s); free(exp); } while (0); | |||
407 | } else if (ISMACROWITHARG(s, "%ifnarch")(rstreqn((s), ("%ifnarch"), sizeof(("%ifnarch"))-1) && (risblank((s)[sizeof(("%ifnarch"))-1]) || !(s)[sizeof(("%ifnarch" ))-1]))) { | |||
408 | ARGMATCH(s, "%{_target_cpu}", match)do { char *os = s; char *exp = rpmExpand("%{_target_cpu}", (( void*)0)); while (*s && !risblank(*s)) s++; while (*s && risblank(*s)) s++; if (!*s) { rpmlog(RPMLOG_ERR, dcgettext ("rpm", "%s:%d: Argument expected for %s\n", 5), ofi->fileName , ofi->lineNum, os); free(exp); return PART_ERROR; } match = matchTok(exp, s); free(exp); } while (0); | |||
409 | match = !match; | |||
410 | } else if (ISMACROWITHARG(s, "%ifos")(rstreqn((s), ("%ifos"), sizeof(("%ifos"))-1) && (risblank ((s)[sizeof(("%ifos"))-1]) || !(s)[sizeof(("%ifos"))-1]))) { | |||
411 | ARGMATCH(s, "%{_target_os}", match)do { char *os = s; char *exp = rpmExpand("%{_target_os}", ((void *)0)); while (*s && !risblank(*s)) s++; while (*s && risblank(*s)) s++; if (!*s) { rpmlog(RPMLOG_ERR, dcgettext ( "rpm", "%s:%d: Argument expected for %s\n", 5), ofi->fileName , ofi->lineNum, os); free(exp); return PART_ERROR; } match = matchTok(exp, s); free(exp); } while (0); | |||
412 | } else if (ISMACROWITHARG(s, "%ifnos")(rstreqn((s), ("%ifnos"), sizeof(("%ifnos"))-1) && (risblank ((s)[sizeof(("%ifnos"))-1]) || !(s)[sizeof(("%ifnos"))-1]))) { | |||
413 | ARGMATCH(s, "%{_target_os}", match)do { char *os = s; char *exp = rpmExpand("%{_target_os}", ((void *)0)); while (*s && !risblank(*s)) s++; while (*s && risblank(*s)) s++; if (!*s) { rpmlog(RPMLOG_ERR, dcgettext ( "rpm", "%s:%d: Argument expected for %s\n", 5), ofi->fileName , ofi->lineNum, os); free(exp); return PART_ERROR; } match = matchTok(exp, s); free(exp); } while (0); | |||
414 | match = !match; | |||
415 | } else if (ISMACROWITHARG(s, "%if")(rstreqn((s), ("%if"), sizeof(("%if"))-1) && (risblank ((s)[sizeof(("%if"))-1]) || !(s)[sizeof(("%if"))-1]))) { | |||
416 | s += 3; | |||
417 | match = parseExpressionBoolean(s); | |||
418 | if (match < 0) { | |||
419 | rpmlog(RPMLOG_ERR, | |||
420 | _("%s:%d: bad %%if condition\n")dcgettext ("rpm", "%s:%d: bad %%if condition\n", 5), | |||
421 | ofi->fileName, ofi->lineNum); | |||
422 | return PART_ERROR; | |||
423 | } | |||
424 | } else if (ISMACRO(s, "%else")(rstreqn((s), ("%else"), sizeof(("%else"))-1) && !risalpha ((s)[sizeof(("%else"))-1]))) { | |||
425 | if (! spec->readStack->next) { | |||
426 | /* Got an else with no %if ! */ | |||
427 | rpmlog(RPMLOG_ERR, | |||
428 | _("%s:%d: Got a %%else with no %%if\n")dcgettext ("rpm", "%s:%d: Got a %%else with no %%if\n", 5), | |||
429 | ofi->fileName, ofi->lineNum); | |||
430 | return PART_ERROR; | |||
431 | } | |||
432 | spec->readStack->reading = | |||
433 | spec->readStack->next->reading && ! spec->readStack->reading; | |||
434 | spec->line[0] = '\0'; | |||
435 | } else if (ISMACRO(s, "%endif")(rstreqn((s), ("%endif"), sizeof(("%endif"))-1) && !risalpha ((s)[sizeof(("%endif"))-1]))) { | |||
436 | if (! spec->readStack->next) { | |||
437 | /* Got an end with no %if ! */ | |||
438 | rpmlog(RPMLOG_ERR, | |||
439 | _("%s:%d: Got a %%endif with no %%if\n")dcgettext ("rpm", "%s:%d: Got a %%endif with no %%if\n", 5), | |||
440 | ofi->fileName, ofi->lineNum); | |||
441 | return PART_ERROR; | |||
442 | } | |||
443 | rl = spec->readStack; | |||
444 | spec->readStack = spec->readStack->next; | |||
445 | free(rl); | |||
446 | spec->line[0] = '\0'; | |||
447 | } else if (spec->readStack->reading && ISMACROWITHARG(s, "%include")(rstreqn((s), ("%include"), sizeof(("%include"))-1) && (risblank((s)[sizeof(("%include"))-1]) || !(s)[sizeof(("%include" ))-1]))) { | |||
448 | char *fileName, *endFileName, *p; | |||
449 | ||||
450 | fileName = s+8; | |||
451 | SKIPSPACE(fileName){ while (*(fileName) && risspace(*(fileName))) (fileName )++; }; | |||
452 | endFileName = fileName; | |||
453 | do { | |||
454 | SKIPNONSPACE(endFileName){ while (*(endFileName) && !risspace(*(endFileName))) (endFileName)++; }; | |||
455 | p = endFileName; | |||
456 | SKIPSPACE(p){ while (*(p) && risspace(*(p))) (p)++; }; | |||
457 | if (*p != '\0') endFileName = p; | |||
458 | } while (*p != '\0'); | |||
459 | if (*fileName == '\0') { | |||
460 | rpmlog(RPMLOG_ERR, _("%s:%d: malformed %%include statement\n")dcgettext ("rpm", "%s:%d: malformed %%include statement\n", 5 ), | |||
461 | ofi->fileName, ofi->lineNum); | |||
462 | return PART_ERROR; | |||
463 | } | |||
464 | *endFileName = '\0'; | |||
465 | ||||
466 | ofi = pushOFI(spec, fileName); | |||
467 | goto retry; | |||
468 | } | |||
469 | ||||
470 | if (match != -1) { | |||
471 | rl = xmalloc(sizeof(*rl))rmalloc((sizeof(*rl))); | |||
472 | rl->reading = spec->readStack->reading && match; | |||
473 | rl->next = spec->readStack; | |||
474 | rl->lineNum = ofi->lineNum; | |||
475 | spec->readStack = rl; | |||
476 | spec->line[0] = '\0'; | |||
477 | } | |||
478 | ||||
479 | if (! spec->readStack->reading) { | |||
480 | spec->line[0] = '\0'; | |||
481 | } | |||
482 | ||||
483 | /* Collect parsed line */ | |||
484 | if (spec->parsed == NULL((void*)0)) | |||
485 | spec->parsed = newStringBuf(); | |||
486 | appendStringBufAux(spec->parsed, spec->line,(strip & STRIP_TRAILINGSPACE(1 << 0))); | |||
487 | ||||
488 | /* FIX: spec->readStack->next should be dependent */ | |||
489 | return 0; | |||
490 | } | |||
491 | ||||
492 | void closeSpec(rpmSpec spec) | |||
493 | { | |||
494 | while (popOFI(spec)) {}; | |||
495 | } | |||
496 | ||||
497 | static const rpmTagVal sourceTags[] = { | |||
498 | RPMTAG_NAME, | |||
499 | RPMTAG_VERSION, | |||
500 | RPMTAG_RELEASE, | |||
501 | RPMTAG_EPOCH, | |||
502 | RPMTAG_SUMMARY, | |||
503 | RPMTAG_DESCRIPTION, | |||
504 | RPMTAG_PACKAGER, | |||
505 | RPMTAG_DISTRIBUTION, | |||
506 | RPMTAG_DISTURL, | |||
507 | RPMTAG_VENDOR, | |||
508 | RPMTAG_LICENSE, | |||
509 | RPMTAG_GROUP, | |||
510 | RPMTAG_OS, | |||
511 | RPMTAG_ARCH, | |||
512 | RPMTAG_CHANGELOGTIME, | |||
513 | RPMTAG_CHANGELOGNAME, | |||
514 | RPMTAG_CHANGELOGTEXT, | |||
515 | RPMTAG_URL, | |||
516 | RPMTAG_BUGURL, | |||
517 | RPMTAG_HEADERI18NTABLE, | |||
518 | RPMTAG_VCS, | |||
519 | 0 | |||
520 | }; | |||
521 | ||||
522 | static void initSourceHeader(rpmSpec spec) | |||
523 | { | |||
524 | Package sourcePkg = spec->sourcePackage; | |||
525 | struct Source *srcPtr; | |||
526 | ||||
527 | if (headerIsEntry(sourcePkg->header, RPMTAG_NAME)) | |||
528 | return; | |||
529 | ||||
530 | /* Only specific tags are added to the source package header */ | |||
531 | headerCopyTags(spec->packages->header, sourcePkg->header, sourceTags); | |||
| ||||
532 | ||||
533 | /* Add the build restrictions */ | |||
534 | for (int i=0; i<PACKAGE_NUM_DEPS12; i++) { | |||
535 | rpmdsPutToHeader(sourcePkg->dependencies[i], sourcePkg->header); | |||
536 | } | |||
537 | ||||
538 | { | |||
539 | HeaderIterator hi = headerInitIterator(spec->buildRestrictions); | |||
540 | struct rpmtd_s td; | |||
541 | while (headerNext(hi, &td)) { | |||
542 | if (rpmtdCount(&td) > 0) { | |||
543 | (void) headerPut(sourcePkg->header, &td, HEADERPUT_DEFAULT); | |||
544 | } | |||
545 | rpmtdFreeData(&td); | |||
546 | } | |||
547 | headerFreeIterator(hi); | |||
548 | } | |||
549 | ||||
550 | if (spec->BANames && spec->BACount > 0) { | |||
551 | headerPutStringArray(sourcePkg->header, RPMTAG_BUILDARCHS, | |||
552 | spec->BANames, spec->BACount); | |||
553 | } | |||
554 | ||||
555 | /* Add tags for sources and patches */ | |||
556 | for (srcPtr = spec->sources; srcPtr != NULL((void*)0); srcPtr = srcPtr->next) { | |||
557 | if (srcPtr->flags & RPMBUILD_ISSOURCE) { | |||
558 | headerPutString(sourcePkg->header, RPMTAG_SOURCE, srcPtr->source); | |||
559 | if (srcPtr->flags & RPMBUILD_ISNO) { | |||
560 | headerPutUint32(sourcePkg->header, RPMTAG_NOSOURCE, | |||
561 | &srcPtr->num, 1); | |||
562 | } | |||
563 | } | |||
564 | if (srcPtr->flags & RPMBUILD_ISPATCH) { | |||
565 | headerPutString(sourcePkg->header, RPMTAG_PATCH, srcPtr->source); | |||
566 | if (srcPtr->flags & RPMBUILD_ISNO) { | |||
567 | headerPutUint32(sourcePkg->header, RPMTAG_NOPATCH, | |||
568 | &srcPtr->num, 1); | |||
569 | } | |||
570 | } | |||
571 | } | |||
572 | } | |||
573 | ||||
574 | /* Add extra provides to package. */ | |||
575 | void addPackageProvides(Package pkg) | |||
576 | { | |||
577 | const char *arch, *name; | |||
578 | char *evr, *isaprov; | |||
579 | rpmsenseFlags pflags = RPMSENSE_EQUAL; | |||
580 | ||||
581 | /* <name> = <evr> provide */ | |||
582 | name = headerGetString(pkg->header, RPMTAG_NAME); | |||
583 | arch = headerGetString(pkg->header, RPMTAG_ARCH); | |||
584 | evr = headerGetAsString(pkg->header, RPMTAG_EVR); | |||
585 | addReqProv(pkg, RPMTAG_PROVIDENAME, name, evr, pflags, 0); | |||
586 | ||||
587 | /* | |||
588 | * <name>(<isa>) = <evr> provide | |||
589 | * FIXME: noarch needs special casing for now as BuildArch: noarch doesn't | |||
590 | * cause reading in the noarch macros :-/ | |||
591 | */ | |||
592 | isaprov = rpmExpand(name, "%{?_isa}", NULL((void*)0)); | |||
593 | if (!rstreq(arch, "noarch") && !rstreq(name, isaprov)) { | |||
594 | addReqProv(pkg, RPMTAG_PROVIDENAME, isaprov, evr, pflags, 0); | |||
595 | } | |||
596 | free(isaprov); | |||
597 | free(evr); | |||
598 | } | |||
599 | ||||
600 | static void addTargets(Package Pkgs) | |||
601 | { | |||
602 | char *platform = rpmExpand("%{_target_platform}", NULL((void*)0)); | |||
603 | char *arch = rpmExpand("%{_target_cpu}", NULL((void*)0)); | |||
604 | char *os = rpmExpand("%{_target_os}", NULL((void*)0)); | |||
605 | char *optflags = rpmExpand("%{optflags}", NULL((void*)0)); | |||
606 | ||||
607 | for (Package pkg = Pkgs; pkg != NULL((void*)0); pkg = pkg->next) { | |||
608 | headerPutString(pkg->header, RPMTAG_OS, os); | |||
609 | /* noarch subpackages already have arch set here, leave it alone */ | |||
610 | if (!headerIsEntry(pkg->header, RPMTAG_ARCH)) { | |||
611 | headerPutString(pkg->header, RPMTAG_ARCH, arch); | |||
612 | } | |||
613 | headerPutString(pkg->header, RPMTAG_PLATFORM, platform); | |||
614 | headerPutString(pkg->header, RPMTAG_OPTFLAGS, optflags); | |||
615 | ||||
616 | /* Add manual dependencies early for rpmspec etc to look at */ | |||
617 | addPackageProvides(pkg); | |||
618 | for (int i=0; i<PACKAGE_NUM_DEPS12; i++) { | |||
619 | rpmdsPutToHeader(pkg->dependencies[i], pkg->header); | |||
620 | } | |||
621 | ||||
622 | pkg->ds = rpmdsThis(pkg->header, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL); | |||
623 | } | |||
624 | free(platform); | |||
625 | free(arch); | |||
626 | free(os); | |||
627 | free(optflags); | |||
628 | } | |||
629 | ||||
630 | rpmRC checkForEncoding(Header h, int addtag) | |||
631 | { | |||
632 | rpmRC rc = RPMRC_OK; | |||
633 | #if HAVE_ICONV1 | |||
634 | const char *encoding = "utf-8"; | |||
635 | rpmTagVal tag; | |||
636 | iconv_t ic; | |||
637 | char *dest = NULL((void*)0); | |||
638 | size_t destlen = 0; | |||
639 | int strict = rpmExpandNumeric("%{_invalid_encoding_terminates_build}"); | |||
640 | HeaderIterator hi = headerInitIterator(h); | |||
641 | ||||
642 | ic = iconv_open(encoding, encoding); | |||
643 | if (ic == (iconv_t) -1) { | |||
644 | rpmlog(RPMLOG_WARNING, | |||
645 | _("encoding %s not supported by system\n")dcgettext ("rpm", "encoding %s not supported by system\n", 5), encoding); | |||
646 | goto exit; | |||
647 | } | |||
648 | ||||
649 | while ((tag = headerNextTag(hi)) != RPMTAG_NOT_FOUND) { | |||
650 | struct rpmtd_s td; | |||
651 | const char *src = NULL((void*)0); | |||
652 | ||||
653 | if (rpmTagGetClass(tag) != RPM_STRING_CLASS) | |||
654 | continue; | |||
655 | ||||
656 | headerGet(h, tag, &td, (HEADERGET_RAW|HEADERGET_MINMEM)); | |||
657 | while ((src = rpmtdNextString(&td)) != NULL((void*)0)) { | |||
658 | size_t srclen = strlen(src); | |||
659 | size_t outlen, inlen = srclen; | |||
660 | char *out, *in = (char *) src; | |||
661 | ||||
662 | if (destlen < srclen) { | |||
663 | destlen = srclen * 2; | |||
664 | dest = xrealloc(dest, destlen)rrealloc((dest), (destlen)); | |||
665 | } | |||
666 | out = dest; | |||
667 | outlen = destlen; | |||
668 | ||||
669 | /* reset conversion state */ | |||
670 | iconv(ic, NULL((void*)0), &inlen, &out, &outlen); | |||
671 | ||||
672 | if (iconv(ic, &in, &inlen, &out, &outlen) == (size_t) -1) { | |||
673 | rpmlog(strict ? RPMLOG_ERR : RPMLOG_WARNING, | |||
674 | _("Package %s: invalid %s encoding in %s: %s - %s\n")dcgettext ("rpm", "Package %s: invalid %s encoding in %s: %s - %s\n" , 5), | |||
675 | headerGetString(h, RPMTAG_NAME), | |||
676 | encoding, rpmTagGetName(tag), src, strerror(errno(*__errno_location ()))); | |||
677 | rc = RPMRC_FAIL; | |||
678 | } | |||
679 | ||||
680 | } | |||
681 | rpmtdFreeData(&td); | |||
682 | } | |||
683 | ||||
684 | /* Stomp "known good utf" mark in header if requested */ | |||
685 | if (rc == RPMRC_OK && addtag) | |||
686 | headerPutString(h, RPMTAG_ENCODING, encoding); | |||
687 | if (!strict) | |||
688 | rc = RPMRC_OK; | |||
689 | ||||
690 | exit: | |||
691 | if (ic != (iconv_t) -1) | |||
692 | iconv_close(ic); | |||
693 | headerFreeIterator(hi); | |||
694 | free(dest); | |||
695 | #endif /* HAVE_ICONV */ | |||
696 | ||||
697 | return rc; | |||
698 | } | |||
699 | ||||
700 | static int parseEmpty(rpmSpec spec, int prevParsePart) | |||
701 | { | |||
702 | int res = PART_ERROR; | |||
703 | int nextPart, rc; | |||
704 | char *line; | |||
705 | ||||
706 | line = spec->line + sizeof("%end") - 1; | |||
707 | SKIPSPACE(line){ while (*(line) && risspace(*(line))) (line)++; }; | |||
708 | if (line[0] != '\0') { | |||
709 | rpmlog(RPMLOG_ERR, | |||
710 | _("line %d: %%end doesn't take any arguments: %s\n")dcgettext ("rpm", "line %d: %%end doesn't take any arguments: %s\n" , 5), | |||
711 | spec->lineNum, spec->line); | |||
712 | goto exit; | |||
713 | } | |||
714 | ||||
715 | if (prevParsePart == PART_EMPTY) { | |||
716 | rpmlog(RPMLOG_ERR, | |||
717 | _("line %d: %%end not expected here, no section to close: %s\n")dcgettext ("rpm", "line %d: %%end not expected here, no section to close: %s\n" , 5), | |||
718 | spec->lineNum, spec->line); | |||
719 | goto exit; | |||
720 | } | |||
721 | ||||
722 | if ((rc = readLine(spec, STRIP_TRAILINGSPACE(1 << 0)|STRIP_COMMENTS(1 << 1))) > 0) { | |||
723 | nextPart = PART_NONE; | |||
724 | } else if (rc < 0) { | |||
725 | goto exit; | |||
726 | } else { | |||
727 | while (! (nextPart = isPart(spec->line))) { | |||
728 | line = spec->line; | |||
729 | SKIPSPACE(line){ while (*(line) && risspace(*(line))) (line)++; }; | |||
730 | ||||
731 | if (line[0] != '\0') { | |||
732 | rpmlog(RPMLOG_ERR, | |||
733 | _("line %d doesn't belong to any section: %s\n")dcgettext ("rpm", "line %d doesn't belong to any section: %s\n" , 5), | |||
734 | spec->lineNum, spec->line); | |||
735 | goto exit; | |||
736 | } | |||
737 | if ((rc = readLine(spec, STRIP_TRAILINGSPACE(1 << 0)|STRIP_COMMENTS(1 << 1))) > 0) { | |||
738 | nextPart = PART_NONE; | |||
739 | break; | |||
740 | } else if (rc < 0) { | |||
741 | goto exit; | |||
742 | } | |||
743 | } | |||
744 | } | |||
745 | ||||
746 | res = nextPart; | |||
747 | ||||
748 | exit: | |||
749 | return res; | |||
750 | } | |||
751 | ||||
752 | static rpmSpec parseSpec(const char *specFile, rpmSpecFlags flags, | |||
753 | const char *buildRoot, int recursing) | |||
754 | { | |||
755 | int parsePart = PART_PREAMBLE; | |||
756 | int prevParsePart = PART_EMPTY; | |||
757 | int storedParsePart; | |||
758 | int initialPackage = 1; | |||
759 | rpmSpec spec; | |||
760 | ||||
761 | /* Set up a new Spec structure with no packages. */ | |||
762 | spec = newSpec(); | |||
763 | ||||
764 | spec->specFile = rpmGetPath(specFile, NULL((void*)0)); | |||
765 | pushOFI(spec, spec->specFile); | |||
766 | /* If buildRoot not specified, use default %{buildroot} */ | |||
767 | if (buildRoot) { | |||
| ||||
768 | spec->buildRoot = xstrdup(buildRoot)rstrdup((buildRoot)); | |||
769 | } else { | |||
770 | spec->buildRoot = rpmGetPath("%{?buildroot:%{buildroot}}", NULL((void*)0)); | |||
771 | } | |||
772 | rpmPushMacro(NULL((void*)0), "_docdir", NULL((void*)0), "%{_defaultdocdir}", RMIL_SPEC-3); | |||
773 | rpmPushMacro(NULL((void*)0), "_licensedir", NULL((void*)0), "%{_defaultlicensedir}", RMIL_SPEC-3); | |||
774 | spec->recursing = recursing; | |||
775 | spec->flags = flags; | |||
776 | ||||
777 | /* All the parse*() functions expect to have a line pre-read */ | |||
778 | /* in the spec's line buffer. Except for parsePreamble(), */ | |||
779 | /* which handles the initial entry into a spec file. */ | |||
780 | ||||
781 | while (parsePart != PART_NONE) { | |||
782 | int goterror = 0; | |||
783 | storedParsePart = parsePart; | |||
784 | switch (parsePart) { | |||
785 | case PART_ERROR: /* fallthrough */ | |||
786 | default: | |||
787 | goterror = 1; | |||
788 | break; | |||
789 | case PART_EMPTY: | |||
790 | parsePart = parseEmpty(spec, prevParsePart); | |||
791 | break; | |||
792 | case PART_PREAMBLE: | |||
793 | parsePart = parsePreamble(spec, initialPackage); | |||
794 | initialPackage = 0; | |||
795 | break; | |||
796 | case PART_PREP: | |||
797 | parsePart = parsePrep(spec); | |||
798 | break; | |||
799 | case PART_BUILD: | |||
800 | case PART_INSTALL: | |||
801 | case PART_CHECK: | |||
802 | case PART_CLEAN: | |||
803 | parsePart = parseBuildInstallClean(spec, parsePart); | |||
804 | break; | |||
805 | case PART_CHANGELOG: | |||
806 | parsePart = parseChangelog(spec); | |||
807 | break; | |||
808 | case PART_DESCRIPTION: | |||
809 | parsePart = parseDescription(spec); | |||
810 | break; | |||
811 | ||||
812 | case PART_PRE: | |||
813 | case PART_POST: | |||
814 | case PART_PREUN: | |||
815 | case PART_POSTUN: | |||
816 | case PART_PRETRANS: | |||
817 | case PART_POSTTRANS: | |||
818 | case PART_VERIFYSCRIPT: | |||
819 | case PART_TRIGGERPREIN: | |||
820 | case PART_TRIGGERIN: | |||
821 | case PART_TRIGGERUN: | |||
822 | case PART_TRIGGERPOSTUN: | |||
823 | case PART_FILETRIGGERIN: | |||
824 | case PART_FILETRIGGERUN: | |||
825 | case PART_FILETRIGGERPOSTUN: | |||
826 | case PART_TRANSFILETRIGGERIN: | |||
827 | case PART_TRANSFILETRIGGERUN: | |||
828 | case PART_TRANSFILETRIGGERPOSTUN: | |||
829 | parsePart = parseScript(spec, parsePart); | |||
830 | break; | |||
831 | ||||
832 | case PART_FILES: | |||
833 | parsePart = parseFiles(spec); | |||
834 | break; | |||
835 | ||||
836 | case PART_POLICIES: | |||
837 | parsePart = parsePolicies(spec); | |||
838 | break; | |||
839 | ||||
840 | case PART_NONE: /* XXX avoid gcc whining */ | |||
841 | case PART_LAST: | |||
842 | case PART_BUILDARCHITECTURES: | |||
843 | break; | |||
844 | } | |||
845 | prevParsePart = storedParsePart; | |||
846 | ||||
847 | if (goterror || parsePart >= PART_LAST) { | |||
848 | goto errxit; | |||
849 | } | |||
850 | ||||
851 | if (parsePart == PART_BUILDARCHITECTURES) { | |||
852 | int index; | |||
853 | int x; | |||
854 | ||||
855 | closeSpec(spec); | |||
856 | ||||
857 | spec->BASpecs = xcalloc(spec->BACount, sizeof(*spec->BASpecs))rcalloc((spec->BACount), (sizeof(*spec->BASpecs))); | |||
858 | index = 0; | |||
859 | if (spec->BANames != NULL((void*)0)) | |||
860 | for (x = 0; x < spec->BACount; x++) { | |||
861 | ||||
862 | /* Skip if not arch is not compatible. */ | |||
863 | if (!rpmMachineScore(RPM_MACHTABLE_BUILDARCH, spec->BANames[x])) | |||
864 | continue; | |||
865 | rpmPushMacro(NULL((void*)0), "_target_cpu", NULL((void*)0), spec->BANames[x], RMIL_RPMRC-11); | |||
866 | spec->BASpecs[index] = parseSpec(specFile, flags, buildRoot, 1); | |||
867 | if (spec->BASpecs[index] == NULL((void*)0)) { | |||
868 | spec->BACount = index; | |||
869 | goto errxit; | |||
870 | } | |||
871 | rpmPopMacro(NULL((void*)0), "_target_cpu"); | |||
872 | index++; | |||
873 | } | |||
874 | ||||
875 | spec->BACount = index; | |||
876 | if (! index) { | |||
877 | rpmlog(RPMLOG_ERR, | |||
878 | _("No compatible architectures found for build\n")dcgettext ("rpm", "No compatible architectures found for build\n" , 5)); | |||
879 | goto errxit; | |||
880 | } | |||
881 | ||||
882 | /* | |||
883 | * Return the 1st child's fully parsed Spec structure. | |||
884 | * The restart of the parse when encountering BuildArch | |||
885 | * causes problems for "rpm -q --specfile". This is | |||
886 | * still a hack because there may be more than 1 arch | |||
887 | * specified (unlikely but possible.) There's also the | |||
888 | * further problem that the macro context, particularly | |||
889 | * %{_target_cpu}, disagrees with the info in the header. | |||
890 | */ | |||
891 | if (spec->BACount >= 1) { | |||
892 | rpmSpec nspec = spec->BASpecs[0]; | |||
893 | spec->BASpecs = _free(spec->BASpecs)rfree((spec->BASpecs)); | |||
894 | rpmSpecFree(spec); | |||
895 | spec = nspec; | |||
896 | } | |||
897 | ||||
898 | goto exit; | |||
899 | } | |||
900 | } | |||
901 | ||||
902 | if (spec->clean == NULL((void*)0)) { | |||
903 | char *body = rpmExpand("%{?buildroot: %{__rm} -rf %{buildroot}}", NULL((void*)0)); | |||
904 | spec->clean = newStringBuf(); | |||
905 | appendLineStringBuf(spec->clean, body)appendStringBufAux(spec->clean, body, 1); | |||
906 | free(body); | |||
907 | } | |||
908 | ||||
909 | /* Check for description in each package */ | |||
910 | for (Package pkg = spec->packages; pkg != NULL((void*)0); pkg = pkg->next) { | |||
911 | if (!headerIsEntry(pkg->header, RPMTAG_DESCRIPTION)) { | |||
912 | rpmlog(RPMLOG_ERR, _("Package has no %%description: %s\n")dcgettext ("rpm", "Package has no %%description: %s\n", 5), | |||
913 | headerGetString(pkg->header, RPMTAG_NAME)); | |||
914 | goto errxit; | |||
915 | } | |||
916 | } | |||
917 | ||||
918 | /* Add arch, os and platform, self-provides etc for each package */ | |||
919 | addTargets(spec->packages); | |||
920 | ||||
921 | /* Check for encoding in each package unless disabled */ | |||
922 | if (!(spec->flags & RPMSPEC_NOUTF8)) { | |||
923 | int badenc = 0; | |||
924 | for (Package pkg = spec->packages; pkg != NULL((void*)0); pkg = pkg->next) { | |||
925 | if (checkForEncoding(pkg->header, 0) != RPMRC_OK) { | |||
926 | badenc = 1; | |||
927 | } | |||
928 | } | |||
929 | if (badenc) | |||
930 | goto errxit; | |||
931 | } | |||
932 | ||||
933 | closeSpec(spec); | |||
934 | exit: | |||
935 | /* Assemble source header from parsed components */ | |||
936 | initSourceHeader(spec); | |||
937 | ||||
938 | return spec; | |||
939 | ||||
940 | errxit: | |||
941 | rpmSpecFree(spec); | |||
942 | return NULL((void*)0); | |||
943 | } | |||
944 | ||||
945 | rpmSpec rpmSpecParse(const char *specFile, rpmSpecFlags flags, | |||
946 | const char *buildRoot) | |||
947 | { | |||
948 | return parseSpec(specFile, flags, buildRoot, 0); | |||
949 | } |