|
rpm
5.4.4
|
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 case URL_IS_MONGO: /* XXX FIXME */ 00473 rpmlog(RPMLOG_ERR, _("Invalid icon URL: %s\n"), Lurlfn); 00474 goto exit; 00475 /*@notreached@*/ break; 00476 } 00477 00478 fd = Fopen(fn, "r%{?_rpmgio}"); 00479 if (fd == NULL || Ferror(fd)) { 00480 rpmlog(RPMLOG_ERR, _("Unable to open icon %s: %s\n"), 00481 fn, Fstrerror(fd)); 00482 rc = RPMRC_FAIL; 00483 goto exit; 00484 } 00485 00486 *icon = '\0'; 00487 nb = Fread(icon, sizeof(icon[0]), iconsize, fd); 00488 if (Ferror(fd) || nb == 0) { 00489 rpmlog(RPMLOG_ERR, _("Unable to read icon %s: %s\n"), 00490 fn, Fstrerror(fd)); 00491 goto exit; 00492 } 00493 if (nb >= iconsize) { 00494 rpmlog(RPMLOG_ERR, _("Icon %s is too big (max. %d bytes)\n"), 00495 fn, (int)iconsize); 00496 goto exit; 00497 } 00498 00499 if (icon[0] == 'G' && icon[1] == 'I' && icon[2] == 'F') 00500 he->tag = RPMTAG_GIF; 00501 else 00502 if (icon[0] == '/' && icon[1] == '*' && icon[2] == ' ' 00503 && icon[3] == 'X' && icon[4] == 'P' && icon[5] == 'M') 00504 he->tag = RPMTAG_XPM; 00505 else 00506 he->tag = tagValue("Icon"); 00507 he->t = RPM_BIN_TYPE; 00508 he->p.ui8p = icon; 00509 he->c = (rpmTagCount)nb; 00510 xx = headerPut(h, he, 0); 00511 rc = 0; 00512 00513 exit: 00514 if (fd) { 00515 (void) Fclose(fd); 00516 fd = NULL; 00517 } 00518 Lurlfn = _free(Lurlfn); 00519 return rc; 00520 } 00521 00522 spectag stashSt(Spec spec, Header h, rpmTag tag, const char * lang) 00523 { 00524 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 00525 spectag t = NULL; 00526 int xx; 00527 00528 if (spec->st) { 00529 spectags st = spec->st; 00530 if (st->st_ntags == st->st_nalloc) { 00531 st->st_nalloc += 10; 00532 st->st_t = xrealloc(st->st_t, st->st_nalloc * sizeof(*(st->st_t))); 00533 } 00534 t = st->st_t + st->st_ntags++; 00535 t->t_tag = tag; 00536 t->t_startx = spec->lineNum - 1; 00537 t->t_nlines = 1; 00538 t->t_lang = xstrdup(lang); 00539 t->t_msgid = NULL; 00540 if (!(t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG))) { 00541 he->tag = RPMTAG_NAME; 00542 xx = headerGet(h, he, 0); 00543 if (xx) { 00544 char buf[1024]; 00545 sprintf(buf, "%s(%s)", he->p.str, tagName(tag)); 00546 t->t_msgid = xstrdup(buf); 00547 } 00548 he->p.ptr = _free(he->p.ptr); 00549 } 00550 } 00551 /*@-usereleased -compdef@*/ 00552 return t; 00553 /*@=usereleased =compdef@*/ 00554 } 00555 00556 #define SINGLE_TOKEN_ONLY \ 00557 if (multiToken) { \ 00558 rpmlog(RPMLOG_ERR, _("line %d: Tag takes single token only: %s\n"), \ 00559 spec->lineNum, spec->line); \ 00560 return RPMRC_FAIL; \ 00561 } 00562 00563 /*@-redecl@*/ 00564 extern int noLang; 00565 /*@=redecl@*/ 00566 00567 static rpmRC tagValidate(Spec spec, rpmTag tag, const char * value) 00568 /*@*/ 00569 { 00570 const char * tagN = tagName(tag); 00571 const char * pattern = rpmExpand("%{?pattern_", tagN, "}", NULL); 00572 rpmRC ec = RPMRC_OK; 00573 00574 if (pattern && *pattern) { 00575 miRE mire; 00576 int xx; 00577 00578 mire = mireNew(RPMMIRE_REGEX, tag); 00579 xx = mireSetCOptions(mire, RPMMIRE_REGEX, 0, 0, NULL); 00580 if (!xx) 00581 xx = mireRegcomp(mire, pattern); 00582 if (!xx) 00583 xx = mireRegexec(mire, value, strlen(value)); 00584 if (!xx) 00585 ec = RPMRC_OK; 00586 else { 00587 rpmlog(RPMLOG_ERR, _("line %d: invalid tag value(\"%s\") %s: %s\n"), 00588 spec->lineNum, pattern, tagN, spec->line); 00589 ec = RPMRC_FAIL; 00590 } 00591 00592 mire = mireFree(mire); 00593 } 00594 00595 pattern = _free(pattern); 00596 00597 return ec; 00598 } 00599 00602 static rpmRC handlePreambleTag(Spec spec, Package pkg, rpmTag tag, 00603 const char *macro, const char *lang) 00604 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00605 /*@modifies spec->macros, spec->st, 00606 spec->sources, spec->numSources, spec->noSource, 00607 spec->sourceHeader, spec->BANames, spec->BACount, 00608 spec->line, 00609 pkg->header, pkg->autoProv, pkg->autoReq, pkg->noarch, 00610 rpmGlobalMacroContext, fileSystem, internalState @*/ 00611 { 00612 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 00613 char * field = spec->line; 00614 char * end; 00615 int multiToken = 0; 00616 rpmsenseFlags tagflags; 00617 int len; 00618 rpmuint32_t num; 00619 int rc; 00620 int xx; 00621 00622 if (field == NULL) return RPMRC_FAIL; /* XXX can't happen */ 00623 /* Find the start of the "field" and strip trailing space */ 00624 while ((*field) && (*field != ':')) 00625 field++; 00626 if (*field != ':') { 00627 rpmlog(RPMLOG_ERR, _("line %d: Malformed tag: %s\n"), 00628 spec->lineNum, spec->line); 00629 return RPMRC_FAIL; 00630 } 00631 field++; 00632 SKIPSPACE(field); 00633 if (!*field) { 00634 /* Empty field */ 00635 rpmlog(RPMLOG_ERR, _("line %d: Empty tag: %s\n"), 00636 spec->lineNum, spec->line); 00637 return RPMRC_FAIL; 00638 } 00639 end = findLastChar(field); 00640 00641 /* Validate tag data content. */ 00642 if (tagValidate(spec, tag, field) != RPMRC_OK) 00643 return RPMRC_FAIL; 00644 00645 /* See if this is multi-token */ 00646 end = field; 00647 SKIPNONSPACE(end); 00648 if (*end != '\0') 00649 multiToken = 1; 00650 00651 switch (tag) { 00652 case RPMTAG_NAME: 00653 case RPMTAG_VERSION: 00654 case RPMTAG_RELEASE: 00655 case RPMTAG_DISTEPOCH: 00656 case RPMTAG_URL: 00657 case RPMTAG_DISTTAG: 00658 case RPMTAG_REPOTAG: 00659 case RPMTAG_CVSID: 00660 case RPMTAG_BUGURL: 00661 SINGLE_TOKEN_ONLY; 00662 /* These macros are for backward compatibility */ 00663 if (tag == RPMTAG_VERSION) { 00664 if (strchr(field, '-') != NULL) { 00665 rpmlog(RPMLOG_ERR, _("line %d: Illegal char '-' in %s: %s\n"), 00666 spec->lineNum, "version", spec->line); 00667 return RPMRC_FAIL; 00668 } 00669 addMacro(spec->macros, "PACKAGE_VERSION", NULL, field, RMIL_OLDSPEC); 00670 } else if (tag == RPMTAG_RELEASE) { 00671 if (strchr(field, '-') != NULL) { 00672 rpmlog(RPMLOG_ERR, _("line %d: Illegal char '-' in %s: %s\n"), 00673 spec->lineNum, "release", spec->line); 00674 return RPMRC_FAIL; 00675 } 00676 addMacro(spec->macros, "PACKAGE_RELEASE", NULL, field, RMIL_OLDSPEC-1); 00677 } 00678 he->tag = tag; 00679 he->t = RPM_STRING_TYPE; 00680 he->p.str = field; 00681 he->c = 1; 00682 xx = headerPut(pkg->header, he, 0); 00683 break; 00684 case RPMTAG_GROUP: 00685 case RPMTAG_SUMMARY: 00686 #if defined(RPM_VENDOR_OPENPKG) /* make-class-available-as-macro */ 00687 case RPMTAG_CLASS: 00688 #endif 00689 (void) stashSt(spec, pkg->header, tag, lang); 00690 /*@fallthrough@*/ 00691 case RPMTAG_DISTRIBUTION: 00692 case RPMTAG_VENDOR: 00693 case RPMTAG_LICENSE: 00694 case RPMTAG_PACKAGER: 00695 if (!*lang) { 00696 he->tag = tag; 00697 he->t = RPM_STRING_TYPE; 00698 he->p.str = field; 00699 he->c = 1; 00700 xx = headerPut(pkg->header, he, 0); 00701 } else if (!(noLang && strcmp(lang, RPMBUILD_DEFAULT_LANG))) { 00702 (void) headerAddI18NString(pkg->header, tag, field, lang); 00703 } 00704 break; 00705 /* XXX silently ignore BuildRoot: */ 00706 case RPMTAG_BUILDROOT: 00707 SINGLE_TOKEN_ONLY; 00708 macro = NULL; 00709 #ifdef DYING 00710 buildRootURL = rpmGenPath(spec->rootURL, "%{?buildroot}", NULL); 00711 (void) urlPath(buildRootURL, &buildRoot); 00712 if (*buildRoot == '\0') buildRoot = "/"; 00713 if (!strcmp(buildRoot, "/")) { 00714 rpmlog(RPMLOG_ERR, 00715 _("BuildRoot can not be \"/\": %s\n"), spec->buildRootURL); 00716 buildRootURL = _free(buildRootURL); 00717 return RPMRC_FAIL; 00718 } 00719 buildRootURL = _free(buildRootURL); 00720 #endif 00721 break; 00722 case RPMTAG_KEYWORDS: 00723 case RPMTAG_VARIANTS: 00724 case RPMTAG_PREFIXES: 00725 addOrAppendListEntry(pkg->header, tag, field); 00726 he->tag = tag; 00727 xx = headerGet(pkg->header, he, 0); 00728 if (tag == RPMTAG_PREFIXES) 00729 while (he->c--) { 00730 if (he->p.argv[he->c][0] != '/') { 00731 rpmlog(RPMLOG_ERR, 00732 _("line %d: Prefixes must begin with \"/\": %s\n"), 00733 spec->lineNum, spec->line); 00734 he->p.ptr = _free(he->p.ptr); 00735 return RPMRC_FAIL; 00736 } 00737 len = (int)strlen(he->p.argv[he->c]); 00738 if (he->p.argv[he->c][len - 1] == '/' && len > 1) { 00739 rpmlog(RPMLOG_ERR, 00740 _("line %d: Prefixes must not end with \"/\": %s\n"), 00741 spec->lineNum, spec->line); 00742 he->p.ptr = _free(he->p.ptr); 00743 return RPMRC_FAIL; 00744 } 00745 } 00746 he->p.ptr = _free(he->p.ptr); 00747 break; 00748 case RPMTAG_DOCDIR: 00749 SINGLE_TOKEN_ONLY; 00750 if (field[0] != '/') { 00751 rpmlog(RPMLOG_ERR, 00752 _("line %d: Docdir must begin with '/': %s\n"), 00753 spec->lineNum, spec->line); 00754 return RPMRC_FAIL; 00755 } 00756 macro = NULL; 00757 delMacro(NULL, "_docdir"); 00758 addMacro(NULL, "_docdir", NULL, field, RMIL_SPEC); 00759 break; 00760 case RPMTAG_XMAJOR: 00761 case RPMTAG_XMINOR: 00762 case RPMTAG_EPOCH: 00763 SINGLE_TOKEN_ONLY; 00764 if (parseNum(field, &num)) { 00765 rpmlog(RPMLOG_ERR, 00766 _("line %d: %s takes an integer value: %s\n"), 00767 spec->lineNum, tagName(tag), spec->line); 00768 return RPMRC_FAIL; 00769 } 00770 he->tag = tag; 00771 he->t = RPM_UINT32_TYPE; 00772 he->p.ui32p = # 00773 he->c = 1; 00774 xx = headerPut(pkg->header, he, 0); 00775 break; 00776 case RPMTAG_AUTOREQPROV: 00777 pkg->autoReq = parseYesNo(field); 00778 pkg->autoProv = pkg->autoReq; 00779 break; 00780 case RPMTAG_AUTOREQ: 00781 pkg->autoReq = parseYesNo(field); 00782 break; 00783 case RPMTAG_AUTOPROV: 00784 pkg->autoProv = parseYesNo(field); 00785 break; 00786 case RPMTAG_SOURCE: 00787 case RPMTAG_PATCH: 00788 SINGLE_TOKEN_ONLY; 00789 macro = NULL; 00790 if ((rc = addSource(spec, pkg, field, tag))) 00791 return rc; 00792 break; 00793 case RPMTAG_ICON: 00794 SINGLE_TOKEN_ONLY; 00795 macro = NULL; 00796 if ((rc = addSource(spec, pkg, field, tag))) 00797 return rc; 00798 /* XXX the fetch/load of icon needs to be elsewhere. */ 00799 if ((rc = doIcon(spec, pkg->header))) 00800 return rc; 00801 break; 00802 case RPMTAG_NOSOURCE: 00803 case RPMTAG_NOPATCH: 00804 spec->noSource = 1; 00805 if ((rc = parseNoSource(spec, field, tag))) 00806 return rc; 00807 break; 00808 case RPMTAG_BUILDPREREQ: 00809 case RPMTAG_BUILDREQUIRES: 00810 if ((rc = parseBits(lang, buildScriptBits, &tagflags))) { 00811 rpmlog(RPMLOG_ERR, 00812 _("line %d: Bad %s: qualifiers: %s\n"), 00813 spec->lineNum, tagName(tag), spec->line); 00814 return rc; 00815 } 00816 if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags))) 00817 return rc; 00818 break; 00819 case RPMTAG_PREREQ: 00820 case RPMTAG_REQUIREFLAGS: 00821 if ((rc = parseBits(lang, installScriptBits, &tagflags))) { 00822 rpmlog(RPMLOG_ERR, 00823 _("line %d: Bad %s: qualifiers: %s\n"), 00824 spec->lineNum, tagName(tag), spec->line); 00825 return rc; 00826 } 00827 if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags))) 00828 return rc; 00829 break; 00830 /* Aliases for BuildRequires(hint): */ 00831 case RPMTAG_BUILDSUGGESTS: 00832 case RPMTAG_BUILDENHANCES: 00833 tagflags = RPMSENSE_MISSINGOK; 00834 if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags))) 00835 return rc; 00836 break; 00837 /* Aliases for Requires(hint): */ 00838 case RPMTAG_SUGGESTSFLAGS: 00839 case RPMTAG_ENHANCESFLAGS: 00840 tag = RPMTAG_REQUIREFLAGS; 00841 tagflags = RPMSENSE_MISSINGOK; 00842 if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags))) 00843 return rc; 00844 break; 00845 case RPMTAG_BUILDOBSOLETES: 00846 case RPMTAG_BUILDPROVIDES: 00847 case RPMTAG_BUILDCONFLICTS: 00848 case RPMTAG_CONFLICTFLAGS: 00849 case RPMTAG_OBSOLETEFLAGS: 00850 case RPMTAG_PROVIDEFLAGS: 00851 tagflags = RPMSENSE_ANY; 00852 if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags))) 00853 return rc; 00854 break; 00855 case RPMTAG_BUILDPLATFORMS: /* XXX needs pattern parsing */ 00856 case RPMTAG_EXCLUDEARCH: 00857 case RPMTAG_EXCLUSIVEARCH: 00858 case RPMTAG_EXCLUDEOS: 00859 case RPMTAG_EXCLUSIVEOS: 00860 addOrAppendListEntry(spec->sourceHeader, tag, field); 00861 break; 00862 00863 case RPMTAG_BUILDARCHS: 00864 { const char ** BANames = NULL; 00865 int BACount = 0; 00866 if ((rc = poptParseArgvString(field, &BACount, &BANames))) { 00867 rpmlog(RPMLOG_ERR, 00868 _("line %d: Bad BuildArchitecture format: %s\n"), 00869 spec->lineNum, spec->line); 00870 return RPMRC_FAIL; 00871 } 00872 if (spec->toplevel) { 00873 if (BACount > 0 && BANames != NULL) { 00874 spec->BACount = BACount; 00875 spec->BANames = BANames; 00876 BANames = NULL; /* XXX don't free. */ 00877 } 00878 } else { 00879 if (BACount != 1 || strcmp(BANames[0], "noarch")) { 00880 rpmlog(RPMLOG_ERR, 00881 _("line %d: Only \"noarch\" sub-packages are supported: %s\n"), 00882 spec->lineNum, spec->line); 00883 BANames = _free(BANames); 00884 return RPMRC_FAIL; 00885 } 00886 pkg->noarch = 1; 00887 } 00888 BANames = _free(BANames); 00889 } break; 00890 00891 default: 00892 macro = NULL; 00893 he->tag = tag; 00894 he->t = RPM_STRING_ARRAY_TYPE; 00895 he->p.argv= (const char **) &field; /* XXX NOCAST */ 00896 he->c = 1; 00897 he->append = 1; 00898 xx = headerPut(pkg->header, he, 0); 00899 he->append = 0; 00900 break; 00901 } 00902 00903 /*@-usereleased@*/ 00904 if (macro) 00905 addMacro(spec->macros, macro, NULL, field, RMIL_SPEC); 00906 /*@=usereleased@*/ 00907 00908 return RPMRC_OK; 00909 } 00910 00911 /* This table has to be in a peculiar order. If one tag is the */ 00912 /* same as another, plus a few letters, it must come first. */ 00913 00916 typedef struct PreambleRec_s { 00917 rpmTag tag; 00918 int multiLang; 00919 int obsolete; 00920 /*@observer@*/ /*@null@*/ 00921 const char * token; 00922 } * PreambleRec; 00923 00924 /*@unchecked@*/ 00925 static struct PreambleRec_s preambleList[] = { 00926 {RPMTAG_NAME, 0, 0, "name"}, 00927 {RPMTAG_VERSION, 0, 0, "version"}, 00928 {RPMTAG_RELEASE, 0, 0, "release"}, 00929 {RPMTAG_DISTEPOCH, 0, 0, "distepoch"}, 00930 {RPMTAG_EPOCH, 0, 0, "epoch"}, 00931 {RPMTAG_EPOCH, 0, 1, "serial"}, 00932 {RPMTAG_SUMMARY, 1, 0, "summary"}, 00933 {RPMTAG_LICENSE, 0, 0, "copyright"}, 00934 {RPMTAG_LICENSE, 0, 0, "license"}, 00935 {RPMTAG_DISTRIBUTION, 0, 0, "distribution"}, 00936 {RPMTAG_DISTURL, 0, 0, "disturl"}, 00937 {RPMTAG_VENDOR, 0, 0, "vendor"}, 00938 {RPMTAG_GROUP, 1, 0, "group"}, 00939 {RPMTAG_PACKAGER, 0, 0, "packager"}, 00940 {RPMTAG_URL, 0, 0, "url"}, 00941 {RPMTAG_SOURCE, 0, 0, "source"}, 00942 {RPMTAG_PATCH, 0, 0, "patch"}, 00943 {RPMTAG_NOSOURCE, 0, 0, "nosource"}, 00944 {RPMTAG_NOPATCH, 0, 0, "nopatch"}, 00945 {RPMTAG_EXCLUDEARCH, 0, 0, "excludearch"}, 00946 {RPMTAG_EXCLUSIVEARCH, 0, 0, "exclusivearch"}, 00947 {RPMTAG_EXCLUDEOS, 0, 0, "excludeos"}, 00948 {RPMTAG_EXCLUSIVEOS, 0, 0, "exclusiveos"}, 00949 {RPMTAG_ICON, 0, 0, "icon"}, 00950 {RPMTAG_PROVIDEFLAGS, 0, 0, "provides"}, 00951 {RPMTAG_REQUIREFLAGS, 1, 0, "requires"}, 00952 {RPMTAG_PREREQ, 1, 0, "prereq"}, 00953 {RPMTAG_CONFLICTFLAGS, 0, 0, "conflicts"}, 00954 {RPMTAG_OBSOLETEFLAGS, 0, 0, "obsoletes"}, 00955 {RPMTAG_PREFIXES, 0, 0, "prefixes"}, 00956 {RPMTAG_PREFIXES, 0, 0, "prefix"}, 00957 {RPMTAG_BUILDROOT, 0, 0, "buildroot"}, 00958 {RPMTAG_BUILDARCHS, 0, 0, "buildarchitectures"}, 00959 {RPMTAG_BUILDARCHS, 0, 0, "buildarch"}, 00960 {RPMTAG_BUILDCONFLICTS, 0, 0, "buildconflicts"}, 00961 {RPMTAG_BUILDOBSOLETES, 0, 0, "buildobsoletes"}, 00962 {RPMTAG_BUILDPREREQ, 1, 0, "buildprereq"}, 00963 {RPMTAG_BUILDPROVIDES, 0, 0, "buildprovides"}, 00964 {RPMTAG_BUILDREQUIRES, 1, 0, "buildrequires"}, 00965 {RPMTAG_AUTOREQPROV, 0, 0, "autoreqprov"}, 00966 {RPMTAG_AUTOREQ, 0, 0, "autoreq"}, 00967 {RPMTAG_AUTOPROV, 0, 0, "autoprov"}, 00968 {RPMTAG_DOCDIR, 0, 0, "docdir"}, 00969 {RPMTAG_DISTTAG, 0, 0, "disttag"}, 00970 {RPMTAG_BUGURL, 0, 0, "bugurl"}, 00971 {RPMTAG_CVSID, 0, 0, "cvsid"}, 00972 {RPMTAG_SVNID, 0, 0, "svnid"}, 00973 {RPMTAG_SUGGESTSFLAGS, 0, 0, "suggests"}, 00974 {RPMTAG_ENHANCESFLAGS, 0, 0, "enhances"}, 00975 {RPMTAG_BUILDSUGGESTS, 0, 0, "buildsuggests"}, 00976 {RPMTAG_BUILDENHANCES, 0, 0, "buildenhances"}, 00977 {RPMTAG_VARIANTS, 0, 0, "variants"}, 00978 {RPMTAG_VARIANTS, 0, 0, "variant"}, 00979 {RPMTAG_XMAJOR, 0, 0, "xmajor"}, 00980 {RPMTAG_XMINOR, 0, 0, "xminor"}, 00981 {RPMTAG_REPOTAG, 0, 0, "repotag"}, 00982 {RPMTAG_KEYWORDS, 0, 0, "keywords"}, 00983 {RPMTAG_KEYWORDS, 0, 0, "keyword"}, 00984 {RPMTAG_BUILDPLATFORMS, 0, 0, "buildplatforms"}, 00985 #if defined(RPM_VENDOR_OPENPKG) /* make-class-available-as-macro */ 00986 {RPMTAG_CLASS, 0, 0, "class"}, 00987 #endif 00988 /*@-nullassign@*/ /* LCL: can't add null annotation */ 00989 {0, 0, 0, 0} 00990 /*@=nullassign@*/ 00991 }; 00992 00995 static int findPreambleTag(Spec spec, /*@out@*/rpmTag * tagp, 00996 /*@null@*/ /*@out@*/ const char ** macro, /*@out@*/ char * lang) 00997 /*@modifies *tagp, *macro, *lang @*/ 00998 { 00999 PreambleRec p; 01000 char *s; 01001 size_t len = 0; 01002 01003 /* Search for defined tags. */ 01004 for (p = preambleList; p->token != NULL; p++) { 01005 len = strlen(p->token); 01006 if (!(p->token && !xstrncasecmp(spec->line, p->token, len))) 01007 continue; 01008 if (p->obsolete) { 01009 rpmlog(RPMLOG_ERR, _("Legacy syntax is unsupported: %s\n"), 01010 p->token); 01011 p = NULL; 01012 } 01013 break; 01014 } 01015 if (p == NULL) 01016 return 1; 01017 01018 /* Search for arbitrary tags. */ 01019 if (tagp && p->token == NULL) { 01020 ARGV_t aTags = NULL; 01021 int rc = 1; /* assume failure */ 01022 01023 /*@-noeffect@*/ 01024 (void) tagName(0); /* XXX force arbitrary tags to be initialized. */ 01025 /*@=noeffect@*/ 01026 aTags = rpmTags->aTags; 01027 if (aTags != NULL && aTags[0] != NULL) { 01028 ARGV_t av; 01029 s = tagCanonicalize(spec->line); 01030 #if defined(RPM_VENDOR_OPENPKG) /* wildcard-matching-arbitrary-tagnames */ 01031 av = argvSearchLinear(aTags, s, argvFnmatchCasefold); 01032 #else 01033 av = argvSearch(aTags, s, argvStrcasecmp); 01034 #endif 01035 if (av != NULL) { 01036 *tagp = tagGenerate(s); 01037 rc = 0; 01038 } 01039 s = _free(s); 01040 } 01041 return rc; 01042 } 01043 01044 s = spec->line + len; 01045 SKIPSPACE(s); 01046 01047 switch (p->multiLang) { 01048 default: 01049 case 0: 01050 /* Unless this is a source or a patch, a ':' better be next */ 01051 if (p->tag != RPMTAG_SOURCE && p->tag != RPMTAG_PATCH) { 01052 if (*s != ':') return 1; 01053 } 01054 *lang = '\0'; 01055 break; 01056 case 1: /* Parse optional ( <token> ). */ 01057 if (*s == ':') { 01058 strcpy(lang, RPMBUILD_DEFAULT_LANG); 01059 break; 01060 } 01061 if (*s != '(') return 1; 01062 s++; 01063 SKIPSPACE(s); 01064 while (!xisspace(*s) && *s != ')') 01065 *lang++ = *s++; 01066 *lang = '\0'; 01067 SKIPSPACE(s); 01068 if (*s != ')') return 1; 01069 s++; 01070 SKIPSPACE(s); 01071 if (*s != ':') return 1; 01072 break; 01073 } 01074 01075 if (tagp) 01076 *tagp = p->tag; 01077 if (macro) 01078 /*@-onlytrans -observertrans -dependenttrans@*/ /* FIX: double indirection. */ 01079 *macro = p->token; 01080 /*@=onlytrans =observertrans =dependenttrans@*/ 01081 return 0; 01082 } 01083 01084 /* XXX should return rpmParseState, but RPMRC_FAIL forces int return. */ 01085 int parsePreamble(Spec spec, int initialPackage) 01086 { 01087 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 01088 rpmParseState nextPart; 01089 int xx; 01090 char *linep; 01091 Package pkg; 01092 char NVR[BUFSIZ]; 01093 char lang[BUFSIZ]; 01094 rpmRC rc; 01095 01096 strcpy(NVR, "(main package)"); 01097 01098 pkg = newPackage(spec); 01099 if (spec->packages == NULL) { 01100 spec->packages = pkg; 01101 assert(initialPackage); 01102 } else if (! initialPackage) { 01103 char *name = NULL; 01104 rpmParseState flag; 01105 Package lastpkg; 01106 01107 /* There is one option to %package: <pkg> or -n <pkg> */ 01108 flag = PART_NONE; 01109 if (parseSimplePart(spec, &name, &flag)) { 01110 rpmlog(RPMLOG_ERR, _("Bad package specification: %s\n"), 01111 spec->line); 01112 pkg = freePackages(pkg); 01113 return RPMRC_FAIL; 01114 } 01115 01116 lastpkg = NULL; 01117 if (lookupPackage(spec, name, flag, &lastpkg) == RPMRC_OK) { 01118 pkg->next = lastpkg->next; 01119 } else { 01120 /* Add package to end of list */ 01121 for (lastpkg = spec->packages; lastpkg->next != NULL; lastpkg = lastpkg->next) 01122 {}; 01123 } 01124 assert(lastpkg != NULL); 01125 lastpkg->next = pkg; 01126 01127 /* Construct the package */ 01128 if (flag == PART_SUBNAME) { 01129 he->tag = RPMTAG_NAME; 01130 xx = headerGet(spec->packages->header, he, 0); 01131 sprintf(NVR, "%s-%s", he->p.str, name); 01132 he->p.ptr = _free(he->p.ptr); 01133 } else 01134 strcpy(NVR, name); 01135 name = _free(name); 01136 he->tag = RPMTAG_NAME; 01137 he->t = RPM_STRING_TYPE; 01138 he->p.str = NVR; 01139 he->c = 1; 01140 xx = headerPut(pkg->header, he, 0); 01141 } 01142 01143 if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) { 01144 nextPart = PART_NONE; 01145 } else { 01146 if (rc) 01147 return rc; 01148 while ((nextPart = isPart(spec)) == PART_NONE) { 01149 const char * macro = NULL; 01150 rpmTag tag = 0; 01151 01152 /* Skip blank lines */ 01153 linep = spec->line; 01154 SKIPSPACE(linep); 01155 if (*linep != '\0') { 01156 if (findPreambleTag(spec, &tag, ¯o, lang)) { 01157 rpmlog(RPMLOG_ERR, _("line %d: Unknown tag: %s\n"), 01158 spec->lineNum, spec->line); 01159 return RPMRC_FAIL; 01160 } 01161 if (handlePreambleTag(spec, pkg, tag, macro, lang)) 01162 return RPMRC_FAIL; 01163 if (spec->BANames && !spec->recursing && spec->toplevel) 01164 return PART_BUILDARCHITECTURES; 01165 } 01166 if ((rc = 01167 readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) { 01168 nextPart = PART_NONE; 01169 break; 01170 } 01171 if (rc) 01172 return rc; 01173 } 01174 } 01175 01176 /* Do some final processing on the header */ 01177 01178 /* 01179 * Expand buildroot one more time to get %{version} and the like 01180 * from the main package. 01181 */ 01182 if (initialPackage) { 01183 const char *s = rpmExpand("%{?buildroot}", NULL); 01184 if (s && *s) 01185 (void) addMacro(NULL, "buildroot", NULL, s, -1); 01186 s = _free(s); 01187 } 01188 01189 /* XXX Skip valid arch check if not building binary package */ 01190 if (!spec->anyarch && checkForValidArchitectures(spec)) 01191 return RPMRC_FAIL; 01192 01193 if (pkg == spec->packages) 01194 fillOutMainPackage(pkg->header); 01195 01196 if (checkForDuplicates(pkg->header, NVR) != RPMRC_OK) 01197 return RPMRC_FAIL; 01198 01199 if (pkg != spec->packages) 01200 headerCopyTags(spec->packages->header, pkg->header, 01201 (void *)copyTagsDuringParse); 01202 01203 #ifdef RPM_VENDOR_PLD /* rpm-epoch0 */ 01204 /* Add Epoch: 0 to package header if it was not set by spec */ 01205 he->tag = RPMTAG_NAME; 01206 if (headerGet(spec->packages->header, he, 0) == 0) { 01207 rpmuint32_t num = 0; 01208 01209 he->tag = RPMTAG_EPOCH; 01210 he->t = RPM_UINT32_TYPE; 01211 he->p.ui32p = # 01212 he->c = 1; 01213 xx = headerPut(pkg->header, he, 0); 01214 01215 /* also declare %{epoch} to be same */ 01216 addMacro(spec->macros, "epoch", NULL, "0", RMIL_SPEC); 01217 } 01218 #endif /* RPM_VENDOR_PLD rpm-epoch0 */ 01219 01220 if (checkForRequired(pkg->header, NVR) != RPMRC_OK) 01221 return RPMRC_FAIL; 01222 01223 return nextPart; 01224 }
1.7.5.1