| 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 | } |