Bug Summary

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')

Annotated Source Code

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
30typedef 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
40static 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
80int 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 */
98static 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
119int 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 */
130static 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 */
148static 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
163static 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
174static 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. */
224static 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
283static 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
310static int readLineFromOFI(rpmSpec spec, OFI_t *ofi)
311{
312retry:
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)
\
345do { \
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
360int 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
492void closeSpec(rpmSpec spec)
493{
494 while (popOFI(spec)) {};
495}
496
497static 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
522static void initSourceHeader(rpmSpec spec)
523{
524 Package sourcePkg = spec->sourcePackage;
525 struct Source *srcPtr;
526
527 if (headerIsEntry(sourcePkg->header, RPMTAG_NAME))
20
Assuming the condition is false
21
Taking false branch
528 return;
529
530 /* Only specific tags are added to the source package header */
531 headerCopyTags(spec->packages->header, sourcePkg->header, sourceTags);
22
Access to field 'header' results in a dereference of a null pointer (loaded from field 'packages')
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. */
575void 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
600static 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
630rpmRC 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
690exit:
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
700static 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
748exit:
749 return res;
750}
751
752static 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) {
1
Assuming 'buildRoot' is null
2
Taking false branch
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) {
3
Loop condition is true. Entering loop body
11
Assuming 'parsePart' is equal to PART_NONE
12
Loop condition is false. Execution continues on line 902
782 int goterror = 0;
783 storedParsePart = parsePart;
784 switch (parsePart) {
4
Control jumps to 'case PART_PREAMBLE:' at line 792
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);
5
Value assigned to field 'packages'
794 initialPackage = 0;
795 break;
6
Execution continues on line 845
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) {
7
Assuming 'parsePart' is < PART_LAST
8
Taking false branch
848 goto errxit;
849 }
850
851 if (parsePart == PART_BUILDARCHITECTURES) {
9
Assuming 'parsePart' is not equal to PART_BUILDARCHITECTURES
10
Taking false branch
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)) {
13
Assuming the condition is false
14
Taking false branch
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) {
15
Assuming 'pkg' is equal to NULL
16
Loop condition is false. Execution continues on line 919
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)) {
17
Assuming the condition is false
18
Taking false branch
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);
934exit:
935 /* Assemble source header from parsed components */
936 initSourceHeader(spec);
19
Calling 'initSourceHeader'
937
938 return spec;
939
940errxit:
941 rpmSpecFree(spec);
942 return NULL((void*)0);
943}
944
945rpmSpec rpmSpecParse(const char *specFile, rpmSpecFlags flags,
946 const char *buildRoot)
947{
948 return parseSpec(specFile, flags, buildRoot, 0);
949}