rpm 5.3.12
|
00001 00006 #include "system.h" 00007 00008 #include <rpmio.h> 00009 #include <rpmiotypes.h> 00010 #include <rpmlog.h> 00011 #include <rpmurl.h> 00012 #include <argv.h> 00013 #include <mire.h> 00014 00015 #define _RPMEVR_INTERNAL 00016 #define _RPMTAG_INTERNAL /* XXX rpmTags->aTags */ 00017 #include <rpmbuild.h> 00018 #include "debug.h" 00019 00020 /*@access FD_t @*/ /* compared with NULL */ 00021 /*@access headerTagIndices @*/ /* rpmTags->aTags */ 00022 00025 /*@observer@*/ /*@unchecked@*/ 00026 static rpmTag copyTagsDuringParse[] = { 00027 RPMTAG_EPOCH, 00028 RPMTAG_VERSION, 00029 RPMTAG_RELEASE, 00030 RPMTAG_DISTEPOCH, 00031 RPMTAG_LICENSE, 00032 RPMTAG_GROUP, /* XXX permissive. */ 00033 RPMTAG_SUMMARY, /* XXX permissive. */ 00034 RPMTAG_DESCRIPTION, /* XXX permissive. */ 00035 RPMTAG_PACKAGER, 00036 RPMTAG_DISTRIBUTION, 00037 RPMTAG_DISTURL, 00038 RPMTAG_VENDOR, 00039 RPMTAG_ICON, 00040 RPMTAG_GIF, 00041 RPMTAG_XPM, 00042 RPMTAG_URL, 00043 RPMTAG_CHANGELOGTIME, 00044 RPMTAG_CHANGELOGNAME, 00045 RPMTAG_CHANGELOGTEXT, 00046 RPMTAG_PREFIXES, 00047 RPMTAG_DISTTAG, 00048 RPMTAG_BUGURL, 00049 RPMTAG_CVSID, 00050 RPMTAG_VARIANTS, 00051 RPMTAG_XMAJOR, 00052 RPMTAG_XMINOR, 00053 RPMTAG_REPOTAG, 00054 RPMTAG_KEYWORDS, 00055 0 00056 }; 00057 00060 /*@observer@*/ /*@unchecked@*/ 00061 static rpmTag requiredTags[] = { 00062 RPMTAG_NAME, 00063 RPMTAG_VERSION, 00064 RPMTAG_RELEASE, 00065 RPMTAG_SUMMARY, 00066 RPMTAG_GROUP, 00067 RPMTAG_LICENSE, 00068 0 00069 }; 00070 00073 static void addOrAppendListEntry(Header h, rpmTag tag, char * line) 00074 /*@modifies h @*/ 00075 { 00076 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 00077 int xx; 00078 int argc; 00079 const char **argv; 00080 00081 xx = poptParseArgvString(line, &argc, &argv); 00082 if (argc) { 00083 he->tag = tag; 00084 he->t = RPM_STRING_ARRAY_TYPE; 00085 he->p.argv = argv; 00086 he->c = argc; 00087 he->append = 1; 00088 xx = headerPut(h, he, 0); 00089 he->append = 0; 00090 } 00091 argv = _free(argv); 00092 } 00093 00094 /* Parse a simple part line that only take -n <pkg> or <pkg> */ 00095 /* <pkg> is returned in name as a pointer into malloc'd storage. */ 00096 00099 static int parseSimplePart(Spec spec, /*@out@*/char ** Np, 00100 /*@out@*/rpmParseState *flag) 00101 /*@globals internalState@*/ 00102 /*@modifies *Np, *flag, internalState, spec->line @*/ 00103 { 00104 char * s, * se; 00105 int rc = 0; /* assume failure */ 00106 00107 if (Np) 00108 *Np = NULL; 00109 00110 se = strchr(spec->line, '#'); 00111 if (se) { 00112 *se = '\0'; 00113 while (--se >= spec->line && strchr(" \t\n\r", *se) != NULL) 00114 *se = '\0'; 00115 } 00116 00117 s = xstrdup(spec->line); 00118 /* Throw away the first token (the %xxxx) */ 00119 (void)strtok(s, " \t\n"); 00120 00121 if (!(se = strtok(NULL, " \t\n"))) 00122 goto exit; 00123 00124 if (!strcmp(se, "-n")) { 00125 if (!(se = strtok(NULL, " \t\n"))) { 00126 rc = 1; 00127 goto exit; 00128 } 00129 *flag = PART_NAME; 00130 } else 00131 *flag = PART_SUBNAME; 00132 00133 if (Np) 00134 *Np = xstrdup(se); 00135 00136 rc = (strtok(NULL, " \t\n") ? 1 : 0); 00137 00138 exit: 00139 s = _free(s); 00140 return rc; 00141 } 00142 00145 static inline int parseYesNo(const char * s) 00146 /*@*/ 00147 { 00148 return ((!s || (s[0] == 'n' || s[0] == 'N' || s[0] == '0') || 00149 !xstrcasecmp(s, "false") || !xstrcasecmp(s, "off")) 00150 ? 0 : 1); 00151 } 00152 00153 typedef struct tokenBits_s { 00154 /*@observer@*/ /*@null@*/ 00155 const char * name; 00156 rpmsenseFlags bits; 00157 } * tokenBits; 00158 00161 /*@observer@*/ /*@unchecked@*/ 00162 static struct tokenBits_s installScriptBits[] = { 00163 { "interp", RPMSENSE_INTERP }, 00164 { "preun", RPMSENSE_SCRIPT_PREUN }, 00165 { "pre", RPMSENSE_SCRIPT_PRE }, 00166 { "postun", RPMSENSE_SCRIPT_POSTUN }, 00167 { "post", RPMSENSE_SCRIPT_POST }, 00168 { "rpmlib", RPMSENSE_RPMLIB }, 00169 { "verify", RPMSENSE_SCRIPT_VERIFY }, 00170 { "hint", RPMSENSE_MISSINGOK }, 00171 { NULL, 0 } 00172 }; 00173 00176 /*@observer@*/ /*@unchecked@*/ 00177 static struct tokenBits_s buildScriptBits[] = { 00178 { "prep", RPMSENSE_SCRIPT_PREP }, 00179 { "build", RPMSENSE_SCRIPT_BUILD }, 00180 { "install", RPMSENSE_SCRIPT_INSTALL }, 00181 { "clean", RPMSENSE_SCRIPT_CLEAN }, 00182 { "hint", RPMSENSE_MISSINGOK }, 00183 { NULL, 0 } 00184 }; 00185 00188 static int parseBits(const char * s, const tokenBits tokbits, 00189 /*@out@*/ rpmsenseFlags * bp) 00190 /*@modifies *bp @*/ 00191 { 00192 tokenBits tb; 00193 const char * se; 00194 rpmsenseFlags bits = RPMSENSE_ANY; 00195 int c = 0; 00196 00197 if (s) { 00198 while (*s != '\0') { 00199 while ((c = *s) && xisspace(c)) s++; 00200 se = s; 00201 while ((c = *se) && xisalpha(c)) se++; 00202 if (s == se) 00203 break; 00204 for (tb = tokbits; tb->name; tb++) { 00205 if (tb->name != NULL && 00206 strlen(tb->name) == (size_t)(se-s) && !strncmp(tb->name, s, (se-s))) 00207 /*@innerbreak@*/ break; 00208 } 00209 if (tb->name == NULL) 00210 break; 00211 bits |= tb->bits; 00212 while ((c = *se) && xisspace(c)) se++; 00213 if (c != ',') 00214 break; 00215 s = ++se; 00216 } 00217 } 00218 if (c == 0 && bp) *bp = bits; 00219 return (c ? RPMRC_FAIL : RPMRC_OK); 00220 } 00221 00224 /*@null@*/ 00225 static inline char * findLastChar(char * s) 00226 /*@modifies *s @*/ 00227 { 00228 char *se = s + strlen(s); 00229 00230 /* Right trim white space. */ 00231 while (--se > s && strchr(" \t\n\r", *se) != NULL) 00232 *se = '\0'; 00233 /* Truncate comments. */ 00234 if ((se = strchr(s, '#')) != NULL) { 00235 *se = '\0'; 00236 while (--se > s && strchr(" \t\n\r", *se) != NULL) 00237 *se = '\0'; 00238 } 00239 /*@-temptrans -retalias @*/ 00240 return se; 00241 /*@=temptrans =retalias @*/ 00242 } 00243 00246 static int isMemberInEntry(Header h, const char *name, rpmTag tag) 00247 /*@globals internalState @*/ 00248 /*@modifies internalState @*/ 00249 { 00250 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 00251 int rc = -1; 00252 int xx; 00253 00254 he->tag = tag; 00255 xx = headerGet(h, he, 0); 00256 if (!xx) 00257 return rc; 00258 rc = 0; 00259 while (he->c) { 00260 he->c--; 00261 if (xstrcasecmp(he->p.argv[he->c], name)) 00262 continue; 00263 rc = 1; 00264 break; 00265 } 00266 he->p.ptr = _free(he->p.ptr); 00267 return rc; 00268 } 00269 00272 static int checkForValidArchitectures(Spec spec) 00273 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 00274 /*@modifies rpmGlobalMacroContext, internalState @*/ 00275 { 00276 const char *arch = rpmExpand("%{_target_cpu}", NULL); 00277 const char *os = rpmExpand("%{_target_os}", NULL); 00278 int rc = RPMRC_FAIL; /* assume failure. */ 00279 00280 if (isMemberInEntry(spec->sourceHeader, arch, RPMTAG_EXCLUDEARCH) == 1) { 00281 rpmlog(RPMLOG_ERR, _("Architecture is excluded: %s\n"), arch); 00282 goto exit; 00283 } 00284 if (isMemberInEntry(spec->sourceHeader, arch, RPMTAG_EXCLUSIVEARCH) == 0) { 00285 rpmlog(RPMLOG_ERR, _("Architecture is not included: %s\n"), arch); 00286 goto exit; 00287 } 00288 if (isMemberInEntry(spec->sourceHeader, os, RPMTAG_EXCLUDEOS) == 1) { 00289 rpmlog(RPMLOG_ERR, _("OS is excluded: %s\n"), os); 00290 goto exit; 00291 } 00292 if (isMemberInEntry(spec->sourceHeader, os, RPMTAG_EXCLUSIVEOS) == 0) { 00293 rpmlog(RPMLOG_ERR, _("OS is not included: %s\n"), os); 00294 goto exit; 00295 } 00296 rc = 0; 00297 exit: 00298 arch = _free(arch); 00299 os = _free(os); 00300 return rc; 00301 } 00302 00309 static rpmRC checkForRequired(Header h, const char * NVR) 00310 /*@*/ 00311 { 00312 rpmTag * p; 00313 rpmRC rc = RPMRC_OK; 00314 00315 for (p = requiredTags; *p != 0; p++) { 00316 if (!headerIsEntry(h, *p)) { 00317 rpmlog(RPMLOG_ERR, 00318 _("%s field must be present in package: %s\n"), 00319 tagName(*p), NVR); 00320 rc = RPMRC_FAIL; 00321 } 00322 } 00323 00324 return rc; 00325 } 00326 00333 static rpmRC checkForDuplicates(Header h, const char * NVR) 00334 /*@globals internalState @*/ 00335 /*@modifies h, internalState @*/ 00336 { 00337 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 00338 HeaderIterator hi; 00339 rpmTag lastTag = 0; 00340 rpmRC rc = RPMRC_OK; 00341 00342 for (hi = headerInit(h); 00343 headerNext(hi, he, 0); 00344 he->p.ptr = _free(he->p.ptr)) 00345 { 00346 if (he->tag != lastTag) { 00347 lastTag = he->tag; 00348 continue; 00349 } 00350 rpmlog(RPMLOG_ERR, _("Duplicate %s entries in package: %s\n"), 00351 tagName(he->tag), NVR); 00352 rc = RPMRC_FAIL; 00353 } 00354 hi = headerFini(hi); 00355 00356 return rc; 00357 } 00358 00361 /*@observer@*/ /*@unchecked@*/ 00362 static struct optionalTag { 00363 rpmTag ot_tag; 00364 /*@observer@*/ /*@null@*/ 00365 const char * ot_mac; 00366 } optionalTags[] = { 00367 { RPMTAG_VENDOR, "%{vendor}" }, 00368 { RPMTAG_PACKAGER, "%{packager}" }, 00369 { RPMTAG_DISTEPOCH, "%{distepoch}" }, 00370 { RPMTAG_DISTRIBUTION, "%{distribution}" }, 00371 { RPMTAG_DISTTAG, "%{disttag}" }, 00372 { RPMTAG_DISTURL, "%{disturl}" }, 00373 { RPMTAG_BUGURL, "%{bugurl}" }, 00374 { 0xffffffff, "%{class}" }, 00375 { -1, NULL } 00376 }; 00377 00380 static void fillOutMainPackage(Header h) 00381 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 00382 /*@modifies h, rpmGlobalMacroContext, internalState @*/ 00383 { 00384 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 00385 struct optionalTag *ot; 00386 int xx; 00387 00388 for (ot = optionalTags; ot->ot_mac != NULL; ot++) { 00389 const char * val; 00390 rpmTag tag; 00391 00392 tag = ot->ot_tag; 00393 00394 /* Generate arbitrary tag (if necessary). */ 00395 if (tag == 0xffffffff) { 00396 val = tagCanonicalize(ot->ot_mac + (sizeof("%{")-1)); 00397 tag = tagGenerate(val); 00398 val = _free(val); 00399 } 00400 00401 if (headerIsEntry(h, tag)) 00402 continue; 00403 val = rpmExpand(ot->ot_mac, NULL); 00404 if (val && *val != '%') { 00405 he->tag = tag; 00406 he->t = RPM_STRING_TYPE; 00407 he->p.str = val; 00408 he->c = 1; 00409 xx = headerPut(h, he, 0); 00410 } 00411 val = _free(val); 00412 } 00413 } 00414 00417 static int doIcon(Spec spec, Header h) 00418 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00419 /*@modifies h, rpmGlobalMacroContext, fileSystem, internalState @*/ 00420 { 00421 static size_t iconsize = 0; 00422 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 00423 const char *fn, *Lurlfn = NULL; 00424 struct Source *sp; 00425 size_t nb; 00426 rpmuint8_t * icon; 00427 FD_t fd = NULL; 00428 int rc = RPMRC_FAIL; /* assume error */ 00429 int urltype; 00430 int xx; 00431 00432 if (iconsize == 0) { 00433 iconsize = rpmExpandNumeric("%{?_build_iconsize}"); 00434 if (iconsize < 2048) 00435 iconsize = 2048; 00436 } 00437 icon = alloca(iconsize+1); 00438 00439 for (sp = spec->sources; sp != NULL; sp = sp->next) { 00440 if (sp->flags & RPMFILE_ICON) 00441 break; 00442 } 00443 if (sp == NULL) { 00444 rpmlog(RPMLOG_ERR, _("No icon file in sources\n")); 00445 goto exit; 00446 } 00447 00448 #if defined(RPM_VENDOR_OPENPKG) /* splitted-source-directory */ 00449 /* support splitted source directories, i.e., source files which 00450 are alternatively placed into the .spec directory and picked 00451 up from there, too. */ 00452 Lurlfn = rpmGenPath(NULL, "%{_specdir}/", sp->source); 00453 if (access(Lurlfn, F_OK) == -1) { 00454 Lurlfn = _free(Lurlfn); 00455 Lurlfn = rpmGenPath(NULL, "%{_icondir}/", sp->source); 00456 } 00457 #else 00458 Lurlfn = rpmGenPath(NULL, "%{_icondir}/", sp->source); 00459 #endif 00460 00461 fn = NULL; 00462 urltype = urlPath(Lurlfn, &fn); 00463 switch (urltype) { 00464 case URL_IS_HTTPS: 00465 case URL_IS_HTTP: 00466 case URL_IS_FTP: 00467 case URL_IS_PATH: 00468 case URL_IS_UNKNOWN: 00469 break; 00470 case URL_IS_DASH: 00471 case URL_IS_HKP: 00472 rpmlog(RPMLOG_ERR, _("Invalid icon URL: %s\n"), Lurlfn); 00473 goto exit; 00474 /*@notreached@*/ break; 00475 } 00476 00477 fd = Fopen(fn, "r%{?_rpmgio}"); 00478 if (fd == NULL || Ferror(fd)) { 00479 rpmlog(RPMLOG_ERR, _("Unable to open icon %s: %s\n"), 00480 fn, Fstrerror(fd)); 00481 rc = RPMRC_FAIL; 00482 goto exit; 00483 } 00484 00485 *icon = '\0'; 00486 nb = Fread(icon, sizeof(icon[0]), iconsize, fd); 00487 if (Ferror(fd) || nb == 0) { 00488 rpmlog(RPMLOG_ERR, _("Unable to read icon %s: %s\n"), 00489 fn, Fstrerror(fd)); 00490 goto exit; 00491 } 00492 if (nb >= iconsize) { 00493 rpmlog(RPMLOG_ERR, _("Icon %s is too big (max. %d bytes)\n"), 00494 fn, (int)iconsize); 00495 goto exit; 00496 } 00497 00498 if (icon[0] == 'G' && icon[1] == 'I' && icon[2] == 'F') 00499 he->tag = RPMTAG_GIF; 00500 else 00501 if (icon[0] == '/' && icon[1] == '*' && icon[2] == ' ' 00502 && icon[3] == 'X' && icon[4] == 'P' && icon[5] == 'M') 00503 he->tag = RPMTAG_XPM; 00504 else 00505 he->tag = tagValue("Icon"); 00506 he->t = RPM_BIN_TYPE; 00507 he->p.ui8p = icon; 00508 he->c = (rpmTagCount)nb; 00509 xx = headerPut(h, he, 0); 00510 rc = 0; 00511 00512 exit: 00513 if (fd) { 00514 (void) Fclose(fd); 00515 fd = NULL; 00516 } 00517 Lurlfn = _free(Lurlfn); 00518 return rc; 00519 } 00520 00521 spectag stashSt(Spec spec, Header h, rpmTag tag, const char * lang) 00522 { 00523 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 00524 spectag t = NULL; 00525 int xx; 00526 00527 if (spec->st) { 00528 spectags st = spec->st; 00529 if (st->st_ntags == st->st_nalloc) { 00530 st->st_nalloc += 10; 00531 st->st_t = xrealloc(st->st_t, st->st_nalloc * sizeof(*(st->st_t))); 00532 } 00533 t = st->st_t + st->st_ntags++; 00534 t->t_tag = tag; 00535 t->t_startx = spec->lineNum - 1; 00536 t->t_nlines = 1; 00537 t->t_lang = xstrdup(lang); 00538 t->t_msgid = NULL; 00539 if (!(t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG))) { 00540 he->tag = RPMTAG_NAME; 00541 xx = headerGet(h, he, 0); 00542 if (xx) { 00543 char buf[1024]; 00544 sprintf(buf, "%s(%s)", he->p.str, tagName(tag)); 00545 t->t_msgid = xstrdup(buf); 00546 } 00547 he->p.ptr = _free(he->p.ptr); 00548 } 00549 } 00550 /*@-usereleased -compdef@*/ 00551 return t; 00552 /*@=usereleased =compdef@*/ 00553 } 00554 00555 #define SINGLE_TOKEN_ONLY \ 00556 if (multiToken) { \ 00557 rpmlog(RPMLOG_ERR, _("line %d: Tag takes single token only: %s\n"), \ 00558 spec->lineNum, spec->line); \ 00559 return RPMRC_FAIL; \ 00560 } 00561 00562 /*@-redecl@*/ 00563 extern int noLang; 00564 /*@=redecl@*/ 00565 00566 static rpmRC tagValidate(Spec spec, rpmTag tag, const char * value) 00567 /*@*/ 00568 { 00569 const char * tagN = tagName(tag); 00570 const char * pattern = rpmExpand("%{?pattern_", tagN, "}", NULL); 00571 rpmRC ec = RPMRC_OK; 00572 00573 if (pattern && *pattern) { 00574 miRE mire; 00575 int xx; 00576 00577 mire = mireNew(RPMMIRE_REGEX, tag); 00578 xx = mireSetCOptions(mire, RPMMIRE_REGEX, 0, 0, NULL); 00579 if (!xx) 00580 xx = mireRegcomp(mire, pattern); 00581 if (!xx) 00582 xx = mireRegexec(mire, value, strlen(value)); 00583 if (!xx) 00584 ec = RPMRC_OK; 00585 else { 00586 rpmlog(RPMLOG_ERR, _("line %d: invalid tag value(\"%s\") %s: %s\n"), 00587 spec->lineNum, pattern, tagN, spec->line); 00588 ec = RPMRC_FAIL; 00589 } 00590 00591 mire = mireFree(mire); 00592 } 00593 00594 pattern = _free(pattern); 00595 00596 return ec; 00597 } 00598 00601 static rpmRC handlePreambleTag(Spec spec, Package pkg, rpmTag tag, 00602 const char *macro, const char *lang) 00603 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00604 /*@modifies spec->macros, spec->st, 00605 spec->sources, spec->numSources, spec->noSource, 00606 spec->sourceHeader, spec->BANames, spec->BACount, 00607 spec->line, 00608 pkg->header, pkg->autoProv, pkg->autoReq, pkg->noarch, 00609 rpmGlobalMacroContext, fileSystem, internalState @*/ 00610 { 00611 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 00612 char * field = spec->line; 00613 char * end; 00614 int multiToken = 0; 00615 rpmsenseFlags tagflags; 00616 int len; 00617 rpmuint32_t num; 00618 int rc; 00619 int xx; 00620 00621 if (field == NULL) return RPMRC_FAIL; /* XXX can't happen */ 00622 /* Find the start of the "field" and strip trailing space */ 00623 while ((*field) && (*field != ':')) 00624 field++; 00625 if (*field != ':') { 00626 rpmlog(RPMLOG_ERR, _("line %d: Malformed tag: %s\n"), 00627 spec->lineNum, spec->line); 00628 return RPMRC_FAIL; 00629 } 00630 field++; 00631 SKIPSPACE(field); 00632 if (!*field) { 00633 /* Empty field */ 00634 rpmlog(RPMLOG_ERR, _("line %d: Empty tag: %s\n"), 00635 spec->lineNum, spec->line); 00636 return RPMRC_FAIL; 00637 } 00638 end = findLastChar(field); 00639 00640 /* Validate tag data content. */ 00641 if (tagValidate(spec, tag, field) != RPMRC_OK) 00642 return RPMRC_FAIL; 00643 00644 /* See if this is multi-token */ 00645 end = field; 00646 SKIPNONSPACE(end); 00647 if (*end != '\0') 00648 multiToken = 1; 00649 00650 switch (tag) { 00651 case RPMTAG_NAME: 00652 case RPMTAG_VERSION: 00653 case RPMTAG_RELEASE: 00654 case RPMTAG_DISTEPOCH: 00655 case RPMTAG_URL: 00656 case RPMTAG_DISTTAG: 00657 case RPMTAG_REPOTAG: 00658 case RPMTAG_CVSID: 00659 case RPMTAG_BUGURL: 00660 SINGLE_TOKEN_ONLY; 00661 /* These macros are for backward compatibility */ 00662 if (tag == RPMTAG_VERSION) { 00663 if (strchr(field, '-') != NULL) { 00664 rpmlog(RPMLOG_ERR, _("line %d: Illegal char '-' in %s: %s\n"), 00665 spec->lineNum, "version", spec->line); 00666 return RPMRC_FAIL; 00667 } 00668 addMacro(spec->macros, "PACKAGE_VERSION", NULL, field, RMIL_OLDSPEC); 00669 } else if (tag == RPMTAG_RELEASE) { 00670 if (strchr(field, '-') != NULL) { 00671 rpmlog(RPMLOG_ERR, _("line %d: Illegal char '-' in %s: %s\n"), 00672 spec->lineNum, "release", spec->line); 00673 return RPMRC_FAIL; 00674 } 00675 addMacro(spec->macros, "PACKAGE_RELEASE", NULL, field, RMIL_OLDSPEC-1); 00676 } 00677 he->tag = tag; 00678 he->t = RPM_STRING_TYPE; 00679 he->p.str = field; 00680 he->c = 1; 00681 xx = headerPut(pkg->header, he, 0); 00682 break; 00683 case RPMTAG_GROUP: 00684 case RPMTAG_SUMMARY: 00685 #if defined(RPM_VENDOR_OPENPKG) /* make-class-available-as-macro */ 00686 case RPMTAG_CLASS: 00687 #endif 00688 (void) stashSt(spec, pkg->header, tag, lang); 00689 /*@fallthrough@*/ 00690 case RPMTAG_DISTRIBUTION: 00691 case RPMTAG_VENDOR: 00692 case RPMTAG_LICENSE: 00693 case RPMTAG_PACKAGER: 00694 if (!*lang) { 00695 he->tag = tag; 00696 he->t = RPM_STRING_TYPE; 00697 he->p.str = field; 00698 he->c = 1; 00699 xx = headerPut(pkg->header, he, 0); 00700 } else if (!(noLang && strcmp(lang, RPMBUILD_DEFAULT_LANG))) { 00701 (void) headerAddI18NString(pkg->header, tag, field, lang); 00702 } 00703 break; 00704 /* XXX silently ignore BuildRoot: */ 00705 case RPMTAG_BUILDROOT: 00706 SINGLE_TOKEN_ONLY; 00707 macro = NULL; 00708 #ifdef DYING 00709 buildRootURL = rpmGenPath(spec->rootURL, "%{?buildroot}", NULL); 00710 (void) urlPath(buildRootURL, &buildRoot); 00711 if (*buildRoot == '\0') buildRoot = "/"; 00712 if (!strcmp(buildRoot, "/")) { 00713 rpmlog(RPMLOG_ERR, 00714 _("BuildRoot can not be \"/\": %s\n"), spec->buildRootURL); 00715 buildRootURL = _free(buildRootURL); 00716 return RPMRC_FAIL; 00717 } 00718 buildRootURL = _free(buildRootURL); 00719 #endif 00720 break; 00721 case RPMTAG_KEYWORDS: 00722 case RPMTAG_VARIANTS: 00723 case RPMTAG_PREFIXES: 00724 addOrAppendListEntry(pkg->header, tag, field); 00725 he->tag = tag; 00726 xx = headerGet(pkg->header, he, 0); 00727 if (tag == RPMTAG_PREFIXES) 00728 while (he->c--) { 00729 if (he->p.argv[he->c][0] != '/') { 00730 rpmlog(RPMLOG_ERR, 00731 _("line %d: Prefixes must begin with \"/\": %s\n"), 00732 spec->lineNum, spec->line); 00733 he->p.ptr = _free(he->p.ptr); 00734 return RPMRC_FAIL; 00735 } 00736 len = (int)strlen(he->p.argv[he->c]); 00737 if (he->p.argv[he->c][len - 1] == '/' && len > 1) { 00738 rpmlog(RPMLOG_ERR, 00739 _("line %d: Prefixes must not end with \"/\": %s\n"), 00740 spec->lineNum, spec->line); 00741 he->p.ptr = _free(he->p.ptr); 00742 return RPMRC_FAIL; 00743 } 00744 } 00745 he->p.ptr = _free(he->p.ptr); 00746 break; 00747 case RPMTAG_DOCDIR: 00748 SINGLE_TOKEN_ONLY; 00749 if (field[0] != '/') { 00750 rpmlog(RPMLOG_ERR, 00751 _("line %d: Docdir must begin with '/': %s\n"), 00752 spec->lineNum, spec->line); 00753 return RPMRC_FAIL; 00754 } 00755 macro = NULL; 00756 delMacro(NULL, "_docdir"); 00757 addMacro(NULL, "_docdir", NULL, field, RMIL_SPEC); 00758 break; 00759 case RPMTAG_XMAJOR: 00760 case RPMTAG_XMINOR: 00761 case RPMTAG_EPOCH: 00762 SINGLE_TOKEN_ONLY; 00763 if (parseNum(field, &num)) { 00764 rpmlog(RPMLOG_ERR, 00765 _("line %d: %s takes an integer value: %s\n"), 00766 spec->lineNum, tagName(tag), spec->line); 00767 return RPMRC_FAIL; 00768 } 00769 he->tag = tag; 00770 he->t = RPM_UINT32_TYPE; 00771 he->p.ui32p = # 00772 he->c = 1; 00773 xx = headerPut(pkg->header, he, 0); 00774 break; 00775 case RPMTAG_AUTOREQPROV: 00776 pkg->autoReq = parseYesNo(field); 00777 pkg->autoProv = pkg->autoReq; 00778 break; 00779 case RPMTAG_AUTOREQ: 00780 pkg->autoReq = parseYesNo(field); 00781 break; 00782 case RPMTAG_AUTOPROV: 00783 pkg->autoProv = parseYesNo(field); 00784 break; 00785 case RPMTAG_SOURCE: 00786 case RPMTAG_PATCH: 00787 SINGLE_TOKEN_ONLY; 00788 macro = NULL; 00789 if ((rc = addSource(spec, pkg, field, tag))) 00790 return rc; 00791 break; 00792 case RPMTAG_ICON: 00793 SINGLE_TOKEN_ONLY; 00794 macro = NULL; 00795 if ((rc = addSource(spec, pkg, field, tag))) 00796 return rc; 00797 /* XXX the fetch/load of icon needs to be elsewhere. */ 00798 if ((rc = doIcon(spec, pkg->header))) 00799 return rc; 00800 break; 00801 case RPMTAG_NOSOURCE: 00802 case RPMTAG_NOPATCH: 00803 spec->noSource = 1; 00804 if ((rc = parseNoSource(spec, field, tag))) 00805 return rc; 00806 break; 00807 case RPMTAG_BUILDPREREQ: 00808 case RPMTAG_BUILDREQUIRES: 00809 if ((rc = parseBits(lang, buildScriptBits, &tagflags))) { 00810 rpmlog(RPMLOG_ERR, 00811 _("line %d: Bad %s: qualifiers: %s\n"), 00812 spec->lineNum, tagName(tag), spec->line); 00813 return rc; 00814 } 00815 if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags))) 00816 return rc; 00817 break; 00818 case RPMTAG_PREREQ: 00819 case RPMTAG_REQUIREFLAGS: 00820 if ((rc = parseBits(lang, installScriptBits, &tagflags))) { 00821 rpmlog(RPMLOG_ERR, 00822 _("line %d: Bad %s: qualifiers: %s\n"), 00823 spec->lineNum, tagName(tag), spec->line); 00824 return rc; 00825 } 00826 if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags))) 00827 return rc; 00828 break; 00829 /* Aliases for BuildRequires(hint): */ 00830 case RPMTAG_BUILDSUGGESTS: 00831 case RPMTAG_BUILDENHANCES: 00832 tagflags = RPMSENSE_MISSINGOK; 00833 if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags))) 00834 return rc; 00835 break; 00836 /* Aliases for Requires(hint): */ 00837 case RPMTAG_SUGGESTSFLAGS: 00838 case RPMTAG_ENHANCESFLAGS: 00839 tag = RPMTAG_REQUIREFLAGS; 00840 tagflags = RPMSENSE_MISSINGOK; 00841 if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags))) 00842 return rc; 00843 break; 00844 case RPMTAG_BUILDOBSOLETES: 00845 case RPMTAG_BUILDPROVIDES: 00846 case RPMTAG_BUILDCONFLICTS: 00847 case RPMTAG_CONFLICTFLAGS: 00848 case RPMTAG_OBSOLETEFLAGS: 00849 case RPMTAG_PROVIDEFLAGS: 00850 tagflags = RPMSENSE_ANY; 00851 if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags))) 00852 return rc; 00853 break; 00854 case RPMTAG_BUILDPLATFORMS: /* XXX needs pattern parsing */ 00855 case RPMTAG_EXCLUDEARCH: 00856 case RPMTAG_EXCLUSIVEARCH: 00857 case RPMTAG_EXCLUDEOS: 00858 case RPMTAG_EXCLUSIVEOS: 00859 addOrAppendListEntry(spec->sourceHeader, tag, field); 00860 break; 00861 00862 case RPMTAG_BUILDARCHS: 00863 { const char ** BANames = NULL; 00864 int BACount = 0; 00865 if ((rc = poptParseArgvString(field, &BACount, &BANames))) { 00866 rpmlog(RPMLOG_ERR, 00867 _("line %d: Bad BuildArchitecture format: %s\n"), 00868 spec->lineNum, spec->line); 00869 return RPMRC_FAIL; 00870 } 00871 if (spec->toplevel) { 00872 if (BACount > 0 && BANames != NULL) { 00873 spec->BACount = BACount; 00874 spec->BANames = BANames; 00875 BANames = NULL; /* XXX don't free. */ 00876 } 00877 } else { 00878 if (BACount != 1 || strcmp(BANames[0], "noarch")) { 00879 rpmlog(RPMLOG_ERR, 00880 _("line %d: Only \"noarch\" sub-packages are supported: %s\n"), 00881 spec->lineNum, spec->line); 00882 BANames = _free(BANames); 00883 return RPMRC_FAIL; 00884 } 00885 pkg->noarch = 1; 00886 } 00887 BANames = _free(BANames); 00888 } break; 00889 00890 default: 00891 macro = NULL; 00892 he->tag = tag; 00893 he->t = RPM_STRING_ARRAY_TYPE; 00894 he->p.argv= (const char **) &field; /* XXX NOCAST */ 00895 he->c = 1; 00896 he->append = 1; 00897 xx = headerPut(pkg->header, he, 0); 00898 he->append = 0; 00899 break; 00900 } 00901 00902 /*@-usereleased@*/ 00903 if (macro) 00904 addMacro(spec->macros, macro, NULL, field, RMIL_SPEC); 00905 /*@=usereleased@*/ 00906 00907 return RPMRC_OK; 00908 } 00909 00910 /* This table has to be in a peculiar order. If one tag is the */ 00911 /* same as another, plus a few letters, it must come first. */ 00912 00915 typedef struct PreambleRec_s { 00916 rpmTag tag; 00917 int multiLang; 00918 int obsolete; 00919 /*@observer@*/ /*@null@*/ 00920 const char * token; 00921 } * PreambleRec; 00922 00923 /*@unchecked@*/ 00924 static struct PreambleRec_s preambleList[] = { 00925 {RPMTAG_NAME, 0, 0, "name"}, 00926 {RPMTAG_VERSION, 0, 0, "version"}, 00927 {RPMTAG_RELEASE, 0, 0, "release"}, 00928 {RPMTAG_DISTEPOCH, 0, 0, "distepoch"}, 00929 {RPMTAG_EPOCH, 0, 0, "epoch"}, 00930 {RPMTAG_EPOCH, 0, 1, "serial"}, 00931 {RPMTAG_SUMMARY, 1, 0, "summary"}, 00932 {RPMTAG_LICENSE, 0, 0, "copyright"}, 00933 {RPMTAG_LICENSE, 0, 0, "license"}, 00934 {RPMTAG_DISTRIBUTION, 0, 0, "distribution"}, 00935 {RPMTAG_DISTURL, 0, 0, "disturl"}, 00936 {RPMTAG_VENDOR, 0, 0, "vendor"}, 00937 {RPMTAG_GROUP, 1, 0, "group"}, 00938 {RPMTAG_PACKAGER, 0, 0, "packager"}, 00939 {RPMTAG_URL, 0, 0, "url"}, 00940 {RPMTAG_SOURCE, 0, 0, "source"}, 00941 {RPMTAG_PATCH, 0, 0, "patch"}, 00942 {RPMTAG_NOSOURCE, 0, 0, "nosource"}, 00943 {RPMTAG_NOPATCH, 0, 0, "nopatch"}, 00944 {RPMTAG_EXCLUDEARCH, 0, 0, "excludearch"}, 00945 {RPMTAG_EXCLUSIVEARCH, 0, 0, "exclusivearch"}, 00946 {RPMTAG_EXCLUDEOS, 0, 0, "excludeos"}, 00947 {RPMTAG_EXCLUSIVEOS, 0, 0, "exclusiveos"}, 00948 {RPMTAG_ICON, 0, 0, "icon"}, 00949 {RPMTAG_PROVIDEFLAGS, 0, 0, "provides"}, 00950 {RPMTAG_REQUIREFLAGS, 1, 0, "requires"}, 00951 {RPMTAG_PREREQ, 1, 0, "prereq"}, 00952 {RPMTAG_CONFLICTFLAGS, 0, 0, "conflicts"}, 00953 {RPMTAG_OBSOLETEFLAGS, 0, 0, "obsoletes"}, 00954 {RPMTAG_PREFIXES, 0, 0, "prefixes"}, 00955 {RPMTAG_PREFIXES, 0, 0, "prefix"}, 00956 {RPMTAG_BUILDROOT, 0, 0, "buildroot"}, 00957 {RPMTAG_BUILDARCHS, 0, 0, "buildarchitectures"}, 00958 {RPMTAG_BUILDARCHS, 0, 0, "buildarch"}, 00959 {RPMTAG_BUILDCONFLICTS, 0, 0, "buildconflicts"}, 00960 {RPMTAG_BUILDOBSOLETES, 0, 0, "buildobsoletes"}, 00961 {RPMTAG_BUILDPREREQ, 1, 0, "buildprereq"}, 00962 {RPMTAG_BUILDPROVIDES, 0, 0, "buildprovides"}, 00963 {RPMTAG_BUILDREQUIRES, 1, 0, "buildrequires"}, 00964 {RPMTAG_AUTOREQPROV, 0, 0, "autoreqprov"}, 00965 {RPMTAG_AUTOREQ, 0, 0, "autoreq"}, 00966 {RPMTAG_AUTOPROV, 0, 0, "autoprov"}, 00967 {RPMTAG_DOCDIR, 0, 0, "docdir"}, 00968 {RPMTAG_DISTTAG, 0, 0, "disttag"}, 00969 {RPMTAG_BUGURL, 0, 0, "bugurl"}, 00970 {RPMTAG_CVSID, 0, 0, "cvsid"}, 00971 {RPMTAG_SVNID, 0, 0, "svnid"}, 00972 {RPMTAG_SUGGESTSFLAGS, 0, 0, "suggests"}, 00973 {RPMTAG_ENHANCESFLAGS, 0, 0, "enhances"}, 00974 {RPMTAG_BUILDSUGGESTS, 0, 0, "buildsuggests"}, 00975 {RPMTAG_BUILDENHANCES, 0, 0, "buildenhances"}, 00976 {RPMTAG_VARIANTS, 0, 0, "variants"}, 00977 {RPMTAG_VARIANTS, 0, 0, "variant"}, 00978 {RPMTAG_XMAJOR, 0, 0, "xmajor"}, 00979 {RPMTAG_XMINOR, 0, 0, "xminor"}, 00980 {RPMTAG_REPOTAG, 0, 0, "repotag"}, 00981 {RPMTAG_KEYWORDS, 0, 0, "keywords"}, 00982 {RPMTAG_KEYWORDS, 0, 0, "keyword"}, 00983 {RPMTAG_BUILDPLATFORMS, 0, 0, "buildplatforms"}, 00984 #if defined(RPM_VENDOR_OPENPKG) /* make-class-available-as-macro */ 00985 {RPMTAG_CLASS, 0, 0, "class"}, 00986 #endif 00987 /*@-nullassign@*/ /* LCL: can't add null annotation */ 00988 {0, 0, 0, 0} 00989 /*@=nullassign@*/ 00990 }; 00991 00994 static int findPreambleTag(Spec spec, /*@out@*/rpmTag * tagp, 00995 /*@null@*/ /*@out@*/ const char ** macro, /*@out@*/ char * lang) 00996 /*@modifies *tagp, *macro, *lang @*/ 00997 { 00998 PreambleRec p; 00999 char *s; 01000 size_t len = 0; 01001 01002 /* Search for defined tags. */ 01003 for (p = preambleList; p->token != NULL; p++) { 01004 len = strlen(p->token); 01005 if (!(p->token && !xstrncasecmp(spec->line, p->token, len))) 01006 continue; 01007 if (p->obsolete) { 01008 rpmlog(RPMLOG_ERR, _("Legacy syntax is unsupported: %s\n"), 01009 p->token); 01010 p = NULL; 01011 } 01012 break; 01013 } 01014 if (p == NULL) 01015 return 1; 01016 01017 /* Search for arbitrary tags. */ 01018 if (tagp && p->token == NULL) { 01019 ARGV_t aTags = NULL; 01020 int rc = 1; /* assume failure */ 01021 01022 /*@-noeffect@*/ 01023 (void) tagName(0); /* XXX force arbitrary tags to be initialized. */ 01024 /*@=noeffect@*/ 01025 aTags = rpmTags->aTags; 01026 if (aTags != NULL && aTags[0] != NULL) { 01027 ARGV_t av; 01028 s = tagCanonicalize(spec->line); 01029 #if defined(RPM_VENDOR_OPENPKG) /* wildcard-matching-arbitrary-tagnames */ 01030 av = argvSearchLinear(aTags, s, argvFnmatchCasefold); 01031 #else 01032 av = argvSearch(aTags, s, argvStrcasecmp); 01033 #endif 01034 if (av != NULL) { 01035 *tagp = tagGenerate(s); 01036 rc = 0; 01037 } 01038 s = _free(s); 01039 } 01040 return rc; 01041 } 01042 01043 s = spec->line + len; 01044 SKIPSPACE(s); 01045 01046 switch (p->multiLang) { 01047 default: 01048 case 0: 01049 /* Unless this is a source or a patch, a ':' better be next */ 01050 if (p->tag != RPMTAG_SOURCE && p->tag != RPMTAG_PATCH) { 01051 if (*s != ':') return 1; 01052 } 01053 *lang = '\0'; 01054 break; 01055 case 1: /* Parse optional ( <token> ). */ 01056 if (*s == ':') { 01057 strcpy(lang, RPMBUILD_DEFAULT_LANG); 01058 break; 01059 } 01060 if (*s != '(') return 1; 01061 s++; 01062 SKIPSPACE(s); 01063 while (!xisspace(*s) && *s != ')') 01064 *lang++ = *s++; 01065 *lang = '\0'; 01066 SKIPSPACE(s); 01067 if (*s != ')') return 1; 01068 s++; 01069 SKIPSPACE(s); 01070 if (*s != ':') return 1; 01071 break; 01072 } 01073 01074 if (tagp) 01075 *tagp = p->tag; 01076 if (macro) 01077 /*@-onlytrans -observertrans -dependenttrans@*/ /* FIX: double indirection. */ 01078 *macro = p->token; 01079 /*@=onlytrans =observertrans =dependenttrans@*/ 01080 return 0; 01081 } 01082 01083 /* XXX should return rpmParseState, but RPMRC_FAIL forces int return. */ 01084 int parsePreamble(Spec spec, int initialPackage) 01085 { 01086 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 01087 rpmParseState nextPart; 01088 int xx; 01089 char *linep; 01090 Package pkg; 01091 char NVR[BUFSIZ]; 01092 char lang[BUFSIZ]; 01093 rpmRC rc; 01094 01095 strcpy(NVR, "(main package)"); 01096 01097 pkg = newPackage(spec); 01098 if (spec->packages == NULL) { 01099 spec->packages = pkg; 01100 assert(initialPackage); 01101 } else if (! initialPackage) { 01102 char *name = NULL; 01103 rpmParseState flag; 01104 Package lastpkg; 01105 01106 /* There is one option to %package: <pkg> or -n <pkg> */ 01107 flag = PART_NONE; 01108 if (parseSimplePart(spec, &name, &flag)) { 01109 rpmlog(RPMLOG_ERR, _("Bad package specification: %s\n"), 01110 spec->line); 01111 pkg = freePackages(pkg); 01112 return RPMRC_FAIL; 01113 } 01114 01115 lastpkg = NULL; 01116 if (lookupPackage(spec, name, flag, &lastpkg) == RPMRC_OK) { 01117 pkg->next = lastpkg->next; 01118 } else { 01119 /* Add package to end of list */ 01120 for (lastpkg = spec->packages; lastpkg->next != NULL; lastpkg = lastpkg->next) 01121 {}; 01122 } 01123 assert(lastpkg != NULL); 01124 lastpkg->next = pkg; 01125 01126 /* Construct the package */ 01127 if (flag == PART_SUBNAME) { 01128 he->tag = RPMTAG_NAME; 01129 xx = headerGet(spec->packages->header, he, 0); 01130 sprintf(NVR, "%s-%s", he->p.str, name); 01131 he->p.ptr = _free(he->p.ptr); 01132 } else 01133 strcpy(NVR, name); 01134 name = _free(name); 01135 he->tag = RPMTAG_NAME; 01136 he->t = RPM_STRING_TYPE; 01137 he->p.str = NVR; 01138 he->c = 1; 01139 xx = headerPut(pkg->header, he, 0); 01140 } 01141 01142 if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) { 01143 nextPart = PART_NONE; 01144 } else { 01145 if (rc) 01146 return rc; 01147 while ((nextPart = isPart(spec)) == PART_NONE) { 01148 const char * macro = NULL; 01149 rpmTag tag = 0; 01150 01151 /* Skip blank lines */ 01152 linep = spec->line; 01153 SKIPSPACE(linep); 01154 if (*linep != '\0') { 01155 if (findPreambleTag(spec, &tag, ¯o, lang)) { 01156 rpmlog(RPMLOG_ERR, _("line %d: Unknown tag: %s\n"), 01157 spec->lineNum, spec->line); 01158 return RPMRC_FAIL; 01159 } 01160 if (handlePreambleTag(spec, pkg, tag, macro, lang)) 01161 return RPMRC_FAIL; 01162 if (spec->BANames && !spec->recursing && spec->toplevel) 01163 return PART_BUILDARCHITECTURES; 01164 } 01165 if ((rc = 01166 readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) { 01167 nextPart = PART_NONE; 01168 break; 01169 } 01170 if (rc) 01171 return rc; 01172 } 01173 } 01174 01175 /* Do some final processing on the header */ 01176 01177 /* 01178 * Expand buildroot one more time to get %{version} and the like 01179 * from the main package. 01180 */ 01181 if (initialPackage) { 01182 const char *s = rpmExpand("%{?buildroot}", NULL); 01183 if (s && *s) 01184 (void) addMacro(NULL, "buildroot", NULL, s, -1); 01185 s = _free(s); 01186 } 01187 01188 /* XXX Skip valid arch check if not building binary package */ 01189 if (!spec->anyarch && checkForValidArchitectures(spec)) 01190 return RPMRC_FAIL; 01191 01192 if (pkg == spec->packages) 01193 fillOutMainPackage(pkg->header); 01194 01195 if (checkForDuplicates(pkg->header, NVR) != RPMRC_OK) 01196 return RPMRC_FAIL; 01197 01198 if (pkg != spec->packages) 01199 headerCopyTags(spec->packages->header, pkg->header, 01200 (void *)copyTagsDuringParse); 01201 01202 #ifdef RPM_VENDOR_PLD /* rpm-epoch0 */ 01203 /* Add Epoch: 0 to package header if it was not set by spec */ 01204 he->tag = RPMTAG_NAME; 01205 if (headerGet(spec->packages->header, he, 0) == 0) { 01206 rpmuint32_t num = 0; 01207 01208 he->tag = RPMTAG_EPOCH; 01209 he->t = RPM_UINT32_TYPE; 01210 he->p.ui32p = # 01211 he->c = 1; 01212 xx = headerPut(pkg->header, he, 0); 01213 01214 /* also declare %{epoch} to be same */ 01215 addMacro(spec->macros, "epoch", NULL, "0", RMIL_SPEC); 01216 } 01217 #endif /* RPM_VENDOR_PLD rpm-epoch0 */ 01218 01219 if (checkForRequired(pkg->header, NVR) != RPMRC_OK) 01220 return RPMRC_FAIL; 01221 01222 return nextPart; 01223 }