rpm
4.5
|
00001 00006 #include "system.h" 00007 00008 #include <rpmio_internal.h> 00009 #define _RPMEVR_INTERNAL 00010 #include <rpmbuild.h> 00011 #include "debug.h" 00012 00013 /*@access FD_t @*/ /* compared with NULL */ 00014 00017 /*@observer@*/ /*@unchecked@*/ 00018 static rpmTag copyTagsDuringParse[] = { 00019 RPMTAG_EPOCH, 00020 RPMTAG_VERSION, 00021 RPMTAG_RELEASE, 00022 RPMTAG_LICENSE, 00023 RPMTAG_PACKAGER, 00024 RPMTAG_DISTRIBUTION, 00025 RPMTAG_DISTURL, 00026 RPMTAG_VENDOR, 00027 RPMTAG_ICON, 00028 RPMTAG_GIF, 00029 RPMTAG_XPM, 00030 RPMTAG_URL, 00031 RPMTAG_CHANGELOGTIME, 00032 RPMTAG_CHANGELOGNAME, 00033 RPMTAG_CHANGELOGTEXT, 00034 RPMTAG_PREFIXES, 00035 RPMTAG_DISTTAG, 00036 RPMTAG_CVSID, 00037 RPMTAG_VARIANTS, 00038 RPMTAG_XMAJOR, 00039 RPMTAG_XMINOR, 00040 RPMTAG_REPOTAG, 00041 RPMTAG_KEYWORDS, 00042 0 00043 }; 00044 00047 /*@observer@*/ /*@unchecked@*/ 00048 static rpmTag requiredTags[] = { 00049 RPMTAG_NAME, 00050 RPMTAG_VERSION, 00051 RPMTAG_RELEASE, 00052 RPMTAG_SUMMARY, 00053 RPMTAG_GROUP, 00054 RPMTAG_LICENSE, 00055 0 00056 }; 00057 00060 static void addOrAppendListEntry(Header h, int_32 tag, char * line) 00061 /*@modifies h @*/ 00062 { 00063 int xx; 00064 int argc; 00065 const char **argv; 00066 00067 xx = poptParseArgvString(line, &argc, &argv); 00068 if (argc) 00069 xx = headerAddOrAppendEntry(h, tag, RPM_STRING_ARRAY_TYPE, argv, argc); 00070 argv = _free(argv); 00071 } 00072 00073 /* Parse a simple part line that only take -n <pkg> or <pkg> */ 00074 /* <pkg> is return in name as a pointer into a static buffer */ 00075 00078 /*@-boundswrite@*/ 00079 static int parseSimplePart(char *line, /*@out@*/char **name, 00080 /*@out@*/rpmParseState *flag) 00081 /*@globals internalState@*/ 00082 /*@modifies *name, *flag, internalState @*/ 00083 { 00084 char *tok; 00085 char linebuf[BUFSIZ]; 00086 static char buf[BUFSIZ]; 00087 00088 strcpy(linebuf, line); 00089 00090 /* Throw away the first token (the %xxxx) */ 00091 (void)strtok(linebuf, " \t\n"); 00092 00093 if (!(tok = strtok(NULL, " \t\n"))) { 00094 *name = NULL; 00095 return 0; 00096 } 00097 00098 if (!strcmp(tok, "-n")) { 00099 if (!(tok = strtok(NULL, " \t\n"))) 00100 return 1; 00101 *flag = PART_NAME; 00102 } else { 00103 *flag = PART_SUBNAME; 00104 } 00105 strcpy(buf, tok); 00106 *name = buf; 00107 00108 return (strtok(NULL, " \t\n")) ? 1 : 0; 00109 } 00110 /*@=boundswrite@*/ 00111 00114 static inline int parseYesNo(const char * s) 00115 /*@*/ 00116 { 00117 return ((!s || (s[0] == 'n' || s[0] == 'N' || s[0] == '0') || 00118 !xstrcasecmp(s, "false") || !xstrcasecmp(s, "off")) 00119 ? 0 : 1); 00120 } 00121 00122 typedef struct tokenBits_s { 00123 /*@observer@*/ /*@null@*/ 00124 const char * name; 00125 rpmsenseFlags bits; 00126 } * tokenBits; 00127 00130 /*@observer@*/ /*@unchecked@*/ 00131 static struct tokenBits_s installScriptBits[] = { 00132 { "interp", RPMSENSE_INTERP }, 00133 { "preun", RPMSENSE_SCRIPT_PREUN }, 00134 { "pre", RPMSENSE_SCRIPT_PRE }, 00135 { "postun", RPMSENSE_SCRIPT_POSTUN }, 00136 { "post", RPMSENSE_SCRIPT_POST }, 00137 { "rpmlib", RPMSENSE_RPMLIB }, 00138 { "verify", RPMSENSE_SCRIPT_VERIFY }, 00139 { "hint", RPMSENSE_MISSINGOK }, 00140 { NULL, 0 } 00141 }; 00142 00145 /*@observer@*/ /*@unchecked@*/ 00146 static struct tokenBits_s buildScriptBits[] = { 00147 { "prep", RPMSENSE_SCRIPT_PREP }, 00148 { "build", RPMSENSE_SCRIPT_BUILD }, 00149 { "install", RPMSENSE_SCRIPT_INSTALL }, 00150 { "clean", RPMSENSE_SCRIPT_CLEAN }, 00151 { "hint", RPMSENSE_MISSINGOK }, 00152 { NULL, 0 } 00153 }; 00154 00157 /*@-boundswrite@*/ 00158 static int parseBits(const char * s, const tokenBits tokbits, 00159 /*@out@*/ rpmsenseFlags * bp) 00160 /*@modifies *bp @*/ 00161 { 00162 tokenBits tb; 00163 const char * se; 00164 rpmsenseFlags bits = RPMSENSE_ANY; 00165 int c = 0; 00166 00167 if (s) { 00168 while (*s != '\0') { 00169 while ((c = *s) && xisspace(c)) s++; 00170 se = s; 00171 while ((c = *se) && xisalpha(c)) se++; 00172 if (s == se) 00173 break; 00174 for (tb = tokbits; tb->name; tb++) { 00175 if (tb->name != NULL && 00176 strlen(tb->name) == (se-s) && !strncmp(tb->name, s, (se-s))) 00177 /*@innerbreak@*/ break; 00178 } 00179 if (tb->name == NULL) 00180 break; 00181 bits |= tb->bits; 00182 while ((c = *se) && xisspace(c)) se++; 00183 if (c != ',') 00184 break; 00185 s = ++se; 00186 } 00187 } 00188 if (c == 0 && bp) *bp = bits; 00189 return (c ? RPMERR_BADSPEC : 0); 00190 } 00191 /*@=boundswrite@*/ 00192 00195 static inline char * findLastChar(char * s) 00196 /*@modifies *s @*/ 00197 { 00198 char *se = s + strlen(s); 00199 00200 /*@-bounds@*/ 00201 while (--se > s && strchr(" \t\n\r", *se) != NULL) 00202 *se = '\0'; 00203 /*@=bounds@*/ 00204 /*@-temptrans -retalias @*/ 00205 return se; 00206 /*@=temptrans =retalias @*/ 00207 } 00208 00211 static int isMemberInEntry(Header h, const char *name, rpmTag tag) 00212 /*@*/ 00213 { 00214 HGE_t hge = (HGE_t)headerGetEntryMinMemory; 00215 HFD_t hfd = headerFreeData; 00216 const char ** names; 00217 rpmTagType type; 00218 int count; 00219 00220 if (!hge(h, tag, &type, &names, &count)) 00221 return -1; 00222 /*@-boundsread@*/ 00223 while (count--) { 00224 if (!xstrcasecmp(names[count], name)) 00225 break; 00226 } 00227 names = hfd(names, type); 00228 /*@=boundsread@*/ 00229 return (count >= 0 ? 1 : 0); 00230 } 00231 00234 static int checkForValidArchitectures(Spec spec) 00235 /*@globals rpmGlobalMacroContext, h_errno @*/ 00236 /*@modifies rpmGlobalMacroContext @*/ 00237 { 00238 const char *arch = rpmExpand("%{_target_cpu}", NULL); 00239 const char *os = rpmExpand("%{_target_os}", NULL); 00240 int rc = RPMERR_BADSPEC; /* assume failure. */ 00241 00242 if (isMemberInEntry(spec->sourceHeader, arch, RPMTAG_EXCLUDEARCH) == 1) { 00243 rpmError(RPMERR_BADSPEC, _("Architecture is excluded: %s\n"), arch); 00244 goto exit; 00245 } 00246 if (isMemberInEntry(spec->sourceHeader, arch, RPMTAG_EXCLUSIVEARCH) == 0) { 00247 rpmError(RPMERR_BADSPEC, _("Architecture is not included: %s\n"), arch); 00248 goto exit; 00249 } 00250 if (isMemberInEntry(spec->sourceHeader, os, RPMTAG_EXCLUDEOS) == 1) { 00251 rpmError(RPMERR_BADSPEC, _("OS is excluded: %s\n"), os); 00252 goto exit; 00253 } 00254 if (isMemberInEntry(spec->sourceHeader, os, RPMTAG_EXCLUSIVEOS) == 0) { 00255 rpmError(RPMERR_BADSPEC, _("OS is not included: %s\n"), os); 00256 goto exit; 00257 } 00258 rc = 0; 00259 exit: 00260 arch = _free(arch); 00261 os = _free(os); 00262 return rc; 00263 } 00264 00271 static int checkForRequired(Header h, const char * NVR) 00272 /*@modifies h @*/ /* LCL: parse error here with modifies */ 00273 { 00274 int res = 0; 00275 rpmTag * p; 00276 00277 /*@-boundsread@*/ 00278 for (p = requiredTags; *p != 0; p++) { 00279 if (!headerIsEntry(h, *p)) { 00280 rpmError(RPMERR_BADSPEC, 00281 _("%s field must be present in package: %s\n"), 00282 tagName(*p), NVR); 00283 res = 1; 00284 } 00285 } 00286 /*@=boundsread@*/ 00287 00288 return res; 00289 } 00290 00297 static int checkForDuplicates(Header h, const char * NVR) 00298 /*@modifies h @*/ 00299 { 00300 int res = 0; 00301 int lastTag, tag; 00302 HeaderIterator hi; 00303 00304 for (hi = headerInitIterator(h), lastTag = 0; 00305 headerNextIterator(hi, &tag, NULL, NULL, NULL); 00306 lastTag = tag) 00307 { 00308 if (tag != lastTag) 00309 continue; 00310 rpmError(RPMERR_BADSPEC, _("Duplicate %s entries in package: %s\n"), 00311 tagName(tag), NVR); 00312 res = 1; 00313 } 00314 hi = headerFreeIterator(hi); 00315 00316 return res; 00317 } 00318 00321 /*@observer@*/ /*@unchecked@*/ 00322 static struct optionalTag { 00323 rpmTag ot_tag; 00324 /*@observer@*/ /*@null@*/ 00325 const char * ot_mac; 00326 } optionalTags[] = { 00327 { RPMTAG_VENDOR, "%{vendor}" }, 00328 { RPMTAG_PACKAGER, "%{packager}" }, 00329 { RPMTAG_DISTRIBUTION, "%{distribution}" }, 00330 { RPMTAG_DISTURL, "%{disturl}" }, 00331 { -1, NULL } 00332 }; 00333 00336 static void fillOutMainPackage(Header h) 00337 /*@globals rpmGlobalMacroContext, h_errno @*/ 00338 /*@modifies h, rpmGlobalMacroContext @*/ 00339 { 00340 struct optionalTag *ot; 00341 00342 for (ot = optionalTags; ot->ot_mac != NULL; ot++) { 00343 if (!headerIsEntry(h, ot->ot_tag)) { 00344 /*@-boundsread@*/ 00345 const char *val = rpmExpand(ot->ot_mac, NULL); 00346 if (val && *val != '%') 00347 (void) headerAddEntry(h, ot->ot_tag, RPM_STRING_TYPE, (void *)val, 1); 00348 val = _free(val); 00349 /*@=boundsread@*/ 00350 } 00351 } 00352 } 00353 00356 /*@-boundswrite@*/ 00357 static int doIcon(Spec spec, Header h) 00358 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00359 /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/ 00360 { 00361 static size_t iconsize = 0; 00362 const char *fn, *Lurlfn = NULL; 00363 struct Source *sp; 00364 size_t nb; 00365 char *icon; 00366 FD_t fd = NULL; 00367 int rc = RPMERR_BADSPEC; /* assume error */ 00368 int urltype; 00369 int xx; 00370 00371 if (iconsize == 0) { 00372 iconsize = rpmExpandNumeric("%{?_build_iconsize}"); 00373 if (iconsize < 2048) 00374 iconsize = 2048; 00375 } 00376 icon = alloca(iconsize+1); 00377 00378 for (sp = spec->sources; sp != NULL; sp = sp->next) { 00379 if (sp->flags & RPMFILE_ICON) 00380 break; 00381 } 00382 if (sp == NULL) { 00383 rpmError(RPMERR_BADSPEC, _("No icon file in sources\n")); 00384 goto exit; 00385 } 00386 00387 Lurlfn = rpmGenPath(NULL, "%{_icondir}/", sp->source); 00388 00389 fn = NULL; 00390 urltype = urlPath(Lurlfn, &fn); 00391 switch (urltype) { 00392 case URL_IS_HTTPS: 00393 case URL_IS_HTTP: 00394 case URL_IS_FTP: 00395 case URL_IS_PATH: 00396 case URL_IS_UNKNOWN: 00397 break; 00398 case URL_IS_DASH: 00399 case URL_IS_HKP: 00400 rpmError(RPMERR_BADSPEC, _("Invalid icon URL: %s\n"), Lurlfn); 00401 goto exit; 00402 /*@notreached@*/ break; 00403 } 00404 00405 fd = Fopen(fn, "r"); 00406 if (fd == NULL || Ferror(fd)) { 00407 rpmError(RPMERR_BADSPEC, _("Unable to open icon %s: %s\n"), 00408 fn, Fstrerror(fd)); 00409 rc = RPMERR_BADSPEC; 00410 goto exit; 00411 } 00412 00413 *icon = '\0'; 00414 nb = Fread(icon, sizeof(icon[0]), iconsize, fd); 00415 if (Ferror(fd) || nb == 0) { 00416 rpmError(RPMERR_BADSPEC, _("Unable to read icon %s: %s\n"), 00417 fn, Fstrerror(fd)); 00418 goto exit; 00419 } 00420 if (nb >= iconsize) { 00421 rpmError(RPMERR_BADSPEC, _("Icon %s is too big (max. %d bytes)\n"), 00422 fn, iconsize); 00423 goto exit; 00424 } 00425 00426 if (!strncmp(icon, "GIF", sizeof("GIF")-1)) 00427 xx = headerAddEntry(h, RPMTAG_GIF, RPM_BIN_TYPE, icon, nb); 00428 else if (!strncmp(icon, "/* XPM", sizeof("/* XPM")-1)) 00429 xx = headerAddEntry(h, RPMTAG_XPM, RPM_BIN_TYPE, icon, nb); 00430 else { 00431 rpmError(RPMERR_BADSPEC, _("Unknown icon type: %s\n"), fn); 00432 goto exit; 00433 } 00434 rc = 0; 00435 00436 exit: 00437 if (fd) { 00438 (void) Fclose(fd); 00439 fd = NULL; 00440 } 00441 Lurlfn = _free(Lurlfn); 00442 return rc; 00443 } 00444 /*@=boundswrite@*/ 00445 00446 spectag stashSt(Spec spec, Header h, int tag, const char * lang) 00447 { 00448 HGE_t hge = (HGE_t)headerGetEntryMinMemory; 00449 spectag t = NULL; 00450 00451 if (spec->st) { 00452 spectags st = spec->st; 00453 if (st->st_ntags == st->st_nalloc) { 00454 st->st_nalloc += 10; 00455 st->st_t = xrealloc(st->st_t, st->st_nalloc * sizeof(*(st->st_t))); 00456 } 00457 t = st->st_t + st->st_ntags++; 00458 t->t_tag = tag; 00459 t->t_startx = spec->lineNum - 1; 00460 t->t_nlines = 1; 00461 t->t_lang = xstrdup(lang); 00462 t->t_msgid = NULL; 00463 if (!(t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG))) { 00464 char *n; 00465 if (hge(h, RPMTAG_NAME, NULL, &n, NULL)) { 00466 char buf[1024]; 00467 sprintf(buf, "%s(%s)", n, tagName(tag)); 00468 t->t_msgid = xstrdup(buf); 00469 } 00470 } 00471 } 00472 /*@-usereleased -compdef@*/ 00473 return t; 00474 /*@=usereleased =compdef@*/ 00475 } 00476 00477 #define SINGLE_TOKEN_ONLY \ 00478 if (multiToken) { \ 00479 rpmError(RPMERR_BADSPEC, _("line %d: Tag takes single token only: %s\n"), \ 00480 spec->lineNum, spec->line); \ 00481 return RPMERR_BADSPEC; \ 00482 } 00483 00484 /*@-redecl@*/ 00485 extern int noLang; 00486 /*@=redecl@*/ 00487 00490 /*@-boundswrite@*/ 00491 static int handlePreambleTag(Spec spec, Package pkg, rpmTag tag, 00492 const char *macro, const char *lang) 00493 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00494 /*@modifies spec->macros, spec->st, 00495 spec->sources, spec->numSources, spec->noSource, 00496 spec->sourceHeader, spec->BANames, spec->BACount, 00497 spec->line, 00498 pkg->header, pkg->autoProv, pkg->autoReq, pkg->icon, 00499 rpmGlobalMacroContext, fileSystem, internalState @*/ 00500 { 00501 HGE_t hge = (HGE_t)headerGetEntryMinMemory; 00502 HFD_t hfd = headerFreeData; 00503 char * field = spec->line; 00504 char * end; 00505 char ** array; 00506 int multiToken = 0; 00507 rpmsenseFlags tagflags; 00508 rpmTagType type; 00509 int len; 00510 int num; 00511 int rc; 00512 int xx; 00513 00514 if (field == NULL) return RPMERR_BADSPEC; /* XXX can't happen */ 00515 /* Find the start of the "field" and strip trailing space */ 00516 while ((*field) && (*field != ':')) 00517 field++; 00518 if (*field != ':') { 00519 rpmError(RPMERR_BADSPEC, _("line %d: Malformed tag: %s\n"), 00520 spec->lineNum, spec->line); 00521 return RPMERR_BADSPEC; 00522 } 00523 field++; 00524 SKIPSPACE(field); 00525 if (!*field) { 00526 /* Empty field */ 00527 rpmError(RPMERR_BADSPEC, _("line %d: Empty tag: %s\n"), 00528 spec->lineNum, spec->line); 00529 return RPMERR_BADSPEC; 00530 } 00531 end = findLastChar(field); 00532 00533 /* See if this is multi-token */ 00534 end = field; 00535 SKIPNONSPACE(end); 00536 if (*end != '\0') 00537 multiToken = 1; 00538 00539 switch (tag) { 00540 case RPMTAG_NAME: 00541 case RPMTAG_VERSION: 00542 case RPMTAG_RELEASE: 00543 case RPMTAG_URL: 00544 case RPMTAG_DISTTAG: 00545 case RPMTAG_REPOTAG: 00546 case RPMTAG_CVSID: 00547 SINGLE_TOKEN_ONLY; 00548 /* These macros are for backward compatibility */ 00549 if (tag == RPMTAG_VERSION) { 00550 if (strchr(field, '-') != NULL) { 00551 rpmError(RPMERR_BADSPEC, _("line %d: Illegal char '-' in %s: %s\n"), 00552 spec->lineNum, "version", spec->line); 00553 return RPMERR_BADSPEC; 00554 } 00555 addMacro(spec->macros, "PACKAGE_VERSION", NULL, field, RMIL_OLDSPEC); 00556 } else if (tag == RPMTAG_RELEASE) { 00557 if (strchr(field, '-') != NULL) { 00558 rpmError(RPMERR_BADSPEC, _("line %d: Illegal char '-' in %s: %s\n"), 00559 spec->lineNum, "release", spec->line); 00560 return RPMERR_BADSPEC; 00561 } 00562 addMacro(spec->macros, "PACKAGE_RELEASE", NULL, field, RMIL_OLDSPEC-1); 00563 } 00564 (void) headerAddEntry(pkg->header, tag, RPM_STRING_TYPE, field, 1); 00565 break; 00566 case RPMTAG_GROUP: 00567 case RPMTAG_SUMMARY: 00568 (void) stashSt(spec, pkg->header, tag, lang); 00569 /*@fallthrough@*/ 00570 case RPMTAG_DISTRIBUTION: 00571 case RPMTAG_VENDOR: 00572 case RPMTAG_LICENSE: 00573 case RPMTAG_PACKAGER: 00574 if (!*lang) 00575 (void) headerAddEntry(pkg->header, tag, RPM_STRING_TYPE, field, 1); 00576 else if (!(noLang && strcmp(lang, RPMBUILD_DEFAULT_LANG))) 00577 (void) headerAddI18NString(pkg->header, tag, field, lang); 00578 break; 00579 /* XXX silently ignore BuildRoot: */ 00580 case RPMTAG_BUILDROOT: 00581 SINGLE_TOKEN_ONLY; 00582 macro = NULL; 00583 #ifdef DYING 00584 buildRootURL = rpmGenPath(spec->rootURL, "%{?buildroot}", NULL); 00585 (void) urlPath(buildRootURL, &buildRoot); 00586 /*@-branchstate@*/ 00587 if (*buildRoot == '\0') buildRoot = "/"; 00588 /*@=branchstate@*/ 00589 if (!strcmp(buildRoot, "/")) { 00590 rpmError(RPMERR_BADSPEC, 00591 _("BuildRoot can not be \"/\": %s\n"), spec->buildRootURL); 00592 buildRootURL = _free(buildRootURL); 00593 return RPMERR_BADSPEC; 00594 } 00595 buildRootURL = _free(buildRootURL); 00596 #endif 00597 break; 00598 case RPMTAG_KEYWORDS: 00599 case RPMTAG_VARIANTS: 00600 case RPMTAG_PREFIXES: 00601 addOrAppendListEntry(pkg->header, tag, field); 00602 xx = hge(pkg->header, tag, &type, &array, &num); 00603 if (tag == RPMTAG_PREFIXES) 00604 while (num--) { 00605 if (array[num][0] != '/') { 00606 rpmError(RPMERR_BADSPEC, 00607 _("line %d: Prefixes must begin with \"/\": %s\n"), 00608 spec->lineNum, spec->line); 00609 array = hfd(array, type); 00610 return RPMERR_BADSPEC; 00611 } 00612 len = strlen(array[num]); 00613 if (array[num][len - 1] == '/' && len > 1) { 00614 rpmError(RPMERR_BADSPEC, 00615 _("line %d: Prefixes must not end with \"/\": %s\n"), 00616 spec->lineNum, spec->line); 00617 array = hfd(array, type); 00618 return RPMERR_BADSPEC; 00619 } 00620 } 00621 array = hfd(array, type); 00622 break; 00623 case RPMTAG_DOCDIR: 00624 SINGLE_TOKEN_ONLY; 00625 if (field[0] != '/') { 00626 rpmError(RPMERR_BADSPEC, 00627 _("line %d: Docdir must begin with '/': %s\n"), 00628 spec->lineNum, spec->line); 00629 return RPMERR_BADSPEC; 00630 } 00631 macro = NULL; 00632 delMacro(NULL, "_docdir"); 00633 addMacro(NULL, "_docdir", NULL, field, RMIL_SPEC); 00634 break; 00635 case RPMTAG_XMAJOR: 00636 case RPMTAG_XMINOR: 00637 case RPMTAG_EPOCH: 00638 SINGLE_TOKEN_ONLY; 00639 if (parseNum(field, &num)) { 00640 rpmError(RPMERR_BADSPEC, 00641 _("line %d: %s takes an integer value: %s\n"), 00642 spec->lineNum, tagName(tag), spec->line); 00643 return RPMERR_BADSPEC; 00644 } 00645 xx = headerAddEntry(pkg->header, tag, RPM_INT32_TYPE, &num, 1); 00646 break; 00647 case RPMTAG_AUTOREQPROV: 00648 pkg->autoReq = parseYesNo(field); 00649 pkg->autoProv = pkg->autoReq; 00650 break; 00651 case RPMTAG_AUTOREQ: 00652 pkg->autoReq = parseYesNo(field); 00653 break; 00654 case RPMTAG_AUTOPROV: 00655 pkg->autoProv = parseYesNo(field); 00656 break; 00657 case RPMTAG_SOURCE: 00658 case RPMTAG_PATCH: 00659 SINGLE_TOKEN_ONLY; 00660 macro = NULL; 00661 if ((rc = addSource(spec, pkg, field, tag))) 00662 return rc; 00663 break; 00664 case RPMTAG_ICON: 00665 SINGLE_TOKEN_ONLY; 00666 macro = NULL; 00667 if ((rc = addSource(spec, pkg, field, tag))) 00668 return rc; 00669 /* XXX the fetch/load of icon needs to be elsewhere. */ 00670 if ((rc = doIcon(spec, pkg->header))) 00671 return rc; 00672 break; 00673 case RPMTAG_NOSOURCE: 00674 case RPMTAG_NOPATCH: 00675 spec->noSource = 1; 00676 if ((rc = parseNoSource(spec, field, tag))) 00677 return rc; 00678 break; 00679 case RPMTAG_BUILDPREREQ: 00680 case RPMTAG_BUILDREQUIRES: 00681 if ((rc = parseBits(lang, buildScriptBits, &tagflags))) { 00682 rpmError(RPMERR_BADSPEC, 00683 _("line %d: Bad %s: qualifiers: %s\n"), 00684 spec->lineNum, tagName(tag), spec->line); 00685 return rc; 00686 } 00687 if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags))) 00688 return rc; 00689 break; 00690 case RPMTAG_PREREQ: 00691 case RPMTAG_REQUIREFLAGS: 00692 if ((rc = parseBits(lang, installScriptBits, &tagflags))) { 00693 rpmError(RPMERR_BADSPEC, 00694 _("line %d: Bad %s: qualifiers: %s\n"), 00695 spec->lineNum, tagName(tag), spec->line); 00696 return rc; 00697 } 00698 if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags))) 00699 return rc; 00700 break; 00701 /* Aliases for BuildRequires(hint): */ 00702 case RPMTAG_BUILDSUGGESTS: 00703 case RPMTAG_BUILDENHANCES: 00704 tagflags = RPMSENSE_MISSINGOK; 00705 if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags))) 00706 return rc; 00707 break; 00708 /* Aliases for Requires(hint): */ 00709 case RPMTAG_SUGGESTSFLAGS: 00710 case RPMTAG_ENHANCESFLAGS: 00711 tag = RPMTAG_REQUIREFLAGS; 00712 tagflags = RPMSENSE_MISSINGOK; 00713 if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags))) 00714 return rc; 00715 break; 00716 case RPMTAG_BUILDOBSOLETES: 00717 case RPMTAG_BUILDPROVIDES: 00718 case RPMTAG_BUILDCONFLICTS: 00719 case RPMTAG_CONFLICTFLAGS: 00720 case RPMTAG_OBSOLETEFLAGS: 00721 case RPMTAG_PROVIDEFLAGS: 00722 tagflags = RPMSENSE_ANY; 00723 if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags))) 00724 return rc; 00725 break; 00726 case RPMTAG_BUILDPLATFORMS: /* XXX needs pattern parsing */ 00727 case RPMTAG_EXCLUDEARCH: 00728 case RPMTAG_EXCLUSIVEARCH: 00729 case RPMTAG_EXCLUDEOS: 00730 case RPMTAG_EXCLUSIVEOS: 00731 addOrAppendListEntry(spec->sourceHeader, tag, field); 00732 break; 00733 case RPMTAG_BUILDARCHS: 00734 if ((rc = poptParseArgvString(field, 00735 &(spec->BACount), 00736 &(spec->BANames)))) { 00737 rpmError(RPMERR_BADSPEC, 00738 _("line %d: Bad BuildArchitecture format: %s\n"), 00739 spec->lineNum, spec->line); 00740 return RPMERR_BADSPEC; 00741 } 00742 if (!spec->BACount) 00743 spec->BANames = _free(spec->BANames); 00744 break; 00745 00746 default: 00747 rpmError(RPMERR_INTERNAL, _("Internal error: Bogus tag %d\n"), tag); 00748 return RPMERR_INTERNAL; 00749 } 00750 00751 if (macro) 00752 addMacro(spec->macros, macro, NULL, field, RMIL_SPEC); 00753 00754 return 0; 00755 } 00756 /*@=boundswrite@*/ 00757 00758 /* This table has to be in a peculiar order. If one tag is the */ 00759 /* same as another, plus a few letters, it must come first. */ 00760 00763 typedef struct PreambleRec_s { 00764 rpmTag tag; 00765 int multiLang; 00766 int obsolete; 00767 /*@observer@*/ /*@null@*/ 00768 const char * token; 00769 } * PreambleRec; 00770 00771 /*@unchecked@*/ 00772 static struct PreambleRec_s preambleList[] = { 00773 {RPMTAG_NAME, 0, 0, "name"}, 00774 {RPMTAG_VERSION, 0, 0, "version"}, 00775 {RPMTAG_RELEASE, 0, 0, "release"}, 00776 {RPMTAG_EPOCH, 0, 0, "epoch"}, 00777 {RPMTAG_EPOCH, 0, 1, "serial"}, 00778 {RPMTAG_SUMMARY, 1, 0, "summary"}, 00779 {RPMTAG_LICENSE, 0, 0, "copyright"}, 00780 {RPMTAG_LICENSE, 0, 0, "license"}, 00781 {RPMTAG_DISTRIBUTION, 0, 0, "distribution"}, 00782 {RPMTAG_DISTURL, 0, 0, "disturl"}, 00783 {RPMTAG_VENDOR, 0, 0, "vendor"}, 00784 {RPMTAG_GROUP, 1, 0, "group"}, 00785 {RPMTAG_PACKAGER, 0, 0, "packager"}, 00786 {RPMTAG_URL, 0, 0, "url"}, 00787 {RPMTAG_SOURCE, 0, 0, "source"}, 00788 {RPMTAG_PATCH, 0, 0, "patch"}, 00789 {RPMTAG_NOSOURCE, 0, 0, "nosource"}, 00790 {RPMTAG_NOPATCH, 0, 0, "nopatch"}, 00791 {RPMTAG_EXCLUDEARCH, 0, 0, "excludearch"}, 00792 {RPMTAG_EXCLUSIVEARCH, 0, 0, "exclusivearch"}, 00793 {RPMTAG_EXCLUDEOS, 0, 0, "excludeos"}, 00794 {RPMTAG_EXCLUSIVEOS, 0, 0, "exclusiveos"}, 00795 {RPMTAG_ICON, 0, 0, "icon"}, 00796 {RPMTAG_PROVIDEFLAGS, 0, 0, "provides"}, 00797 {RPMTAG_REQUIREFLAGS, 1, 0, "requires"}, 00798 {RPMTAG_PREREQ, 1, 0, "prereq"}, 00799 {RPMTAG_CONFLICTFLAGS, 0, 0, "conflicts"}, 00800 {RPMTAG_OBSOLETEFLAGS, 0, 0, "obsoletes"}, 00801 {RPMTAG_PREFIXES, 0, 0, "prefixes"}, 00802 {RPMTAG_PREFIXES, 0, 0, "prefix"}, 00803 {RPMTAG_BUILDROOT, 0, 0, "buildroot"}, 00804 {RPMTAG_BUILDARCHS, 0, 0, "buildarchitectures"}, 00805 {RPMTAG_BUILDARCHS, 0, 0, "buildarch"}, 00806 {RPMTAG_BUILDCONFLICTS, 0, 0, "buildconflicts"}, 00807 {RPMTAG_BUILDOBSOLETES, 0, 0, "buildobsoletes"}, 00808 {RPMTAG_BUILDPREREQ, 1, 0, "buildprereq"}, 00809 {RPMTAG_BUILDPROVIDES, 0, 0, "buildprovides"}, 00810 {RPMTAG_BUILDREQUIRES, 1, 0, "buildrequires"}, 00811 {RPMTAG_AUTOREQPROV, 0, 0, "autoreqprov"}, 00812 {RPMTAG_AUTOREQ, 0, 0, "autoreq"}, 00813 {RPMTAG_AUTOPROV, 0, 0, "autoprov"}, 00814 {RPMTAG_DOCDIR, 0, 0, "docdir"}, 00815 {RPMTAG_DISTTAG, 0, 0, "disttag"}, 00816 {RPMTAG_CVSID, 0, 0, "cvsid"}, 00817 {RPMTAG_SVNID, 0, 0, "svnid"}, 00818 {RPMTAG_SUGGESTSFLAGS, 0, 0, "suggests"}, 00819 {RPMTAG_ENHANCESFLAGS, 0, 0, "enhances"}, 00820 {RPMTAG_BUILDSUGGESTS, 0, 0, "buildsuggests"}, 00821 {RPMTAG_BUILDENHANCES, 0, 0, "buildenhances"}, 00822 {RPMTAG_VARIANTS, 0, 0, "variants"}, 00823 {RPMTAG_VARIANTS, 0, 0, "variant"}, 00824 {RPMTAG_XMAJOR, 0, 0, "xmajor"}, 00825 {RPMTAG_XMINOR, 0, 0, "xminor"}, 00826 {RPMTAG_REPOTAG, 0, 0, "repotag"}, 00827 {RPMTAG_KEYWORDS, 0, 0, "keywords"}, 00828 {RPMTAG_KEYWORDS, 0, 0, "keyword"}, 00829 {RPMTAG_BUILDPLATFORMS, 0, 0, "buildplatforms"}, 00830 /*@-nullassign@*/ /* LCL: can't add null annotation */ 00831 {0, 0, 0, 0} 00832 /*@=nullassign@*/ 00833 }; 00834 00837 /*@-boundswrite@*/ 00838 static int findPreambleTag(Spec spec, /*@out@*/rpmTag * tag, 00839 /*@null@*/ /*@out@*/ const char ** macro, /*@out@*/ char * lang) 00840 /*@modifies *tag, *macro, *lang @*/ 00841 { 00842 PreambleRec p; 00843 char *s; 00844 size_t len = 0; 00845 00846 for (p = preambleList; p->token != NULL; p++) { 00847 len = strlen(p->token); 00848 if (!(p->token && !xstrncasecmp(spec->line, p->token, len))) 00849 continue; 00850 if (p->obsolete) { 00851 rpmError(RPMERR_BADSPEC, _("Legacy syntax is unsupported: %s\n"), 00852 p->token); 00853 p = NULL; 00854 } 00855 break; 00856 } 00857 if (p == NULL || p->token == NULL) 00858 return 1; 00859 00860 s = spec->line + len; 00861 SKIPSPACE(s); 00862 00863 switch (p->multiLang) { 00864 default: 00865 case 0: 00866 /* Unless this is a source or a patch, a ':' better be next */ 00867 if (p->tag != RPMTAG_SOURCE && p->tag != RPMTAG_PATCH) { 00868 if (*s != ':') return 1; 00869 } 00870 *lang = '\0'; 00871 break; 00872 case 1: /* Parse optional ( <token> ). */ 00873 if (*s == ':') { 00874 strcpy(lang, RPMBUILD_DEFAULT_LANG); 00875 break; 00876 } 00877 if (*s != '(') return 1; 00878 s++; 00879 SKIPSPACE(s); 00880 while (!xisspace(*s) && *s != ')') 00881 *lang++ = *s++; 00882 *lang = '\0'; 00883 SKIPSPACE(s); 00884 if (*s != ')') return 1; 00885 s++; 00886 SKIPSPACE(s); 00887 if (*s != ':') return 1; 00888 break; 00889 } 00890 00891 *tag = p->tag; 00892 if (macro) 00893 /*@-onlytrans -observertrans -dependenttrans@*/ /* FIX: double indirection. */ 00894 *macro = p->token; 00895 /*@=onlytrans =observertrans =dependenttrans@*/ 00896 return 0; 00897 } 00898 /*@=boundswrite@*/ 00899 00900 /*@-boundswrite@*/ 00901 /* XXX should return rpmParseState, but RPMERR_BADSPEC forces int return. */ 00902 int parsePreamble(Spec spec, int initialPackage) 00903 { 00904 rpmParseState nextPart; 00905 int rc, xx; 00906 char *name, *linep; 00907 Package pkg; 00908 char NVR[BUFSIZ]; 00909 char lang[BUFSIZ]; 00910 00911 strcpy(NVR, "(main package)"); 00912 00913 pkg = newPackage(spec); 00914 00915 if (! initialPackage) { 00916 rpmParseState flag; 00917 /* There is one option to %package: <pkg> or -n <pkg> */ 00918 flag = PART_NONE; 00919 if (parseSimplePart(spec->line, &name, &flag)) { 00920 rpmError(RPMERR_BADSPEC, _("Bad package specification: %s\n"), 00921 spec->line); 00922 return RPMERR_BADSPEC; 00923 } 00924 00925 if (!lookupPackage(spec, name, flag, NULL)) { 00926 rpmError(RPMERR_BADSPEC, _("Package already exists: %s\n"), 00927 spec->line); 00928 return RPMERR_BADSPEC; 00929 } 00930 00931 /* Construct the package */ 00932 if (flag == PART_SUBNAME) { 00933 const char * mainName; 00934 xx = headerNVR(spec->packages->header, &mainName, NULL, NULL); 00935 sprintf(NVR, "%s-%s", mainName, name); 00936 } else 00937 strcpy(NVR, name); 00938 xx = headerAddEntry(pkg->header, RPMTAG_NAME, RPM_STRING_TYPE, NVR, 1); 00939 } 00940 00941 if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) { 00942 nextPart = PART_NONE; 00943 } else { 00944 if (rc) 00945 return rc; 00946 while (! (nextPart = isPart(spec->line))) { 00947 const char * macro; 00948 rpmTag tag; 00949 00950 /* Skip blank lines */ 00951 linep = spec->line; 00952 SKIPSPACE(linep); 00953 if (*linep != '\0') { 00954 if (findPreambleTag(spec, &tag, ¯o, lang)) { 00955 rpmError(RPMERR_BADSPEC, _("line %d: Unknown tag: %s\n"), 00956 spec->lineNum, spec->line); 00957 return RPMERR_BADSPEC; 00958 } 00959 if (handlePreambleTag(spec, pkg, tag, macro, lang)) 00960 return RPMERR_BADSPEC; 00961 if (spec->BANames && !spec->recursing) 00962 return PART_BUILDARCHITECTURES; 00963 } 00964 if ((rc = 00965 readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) { 00966 nextPart = PART_NONE; 00967 break; 00968 } 00969 if (rc) 00970 return rc; 00971 } 00972 } 00973 00974 /* Do some final processing on the header */ 00975 00976 /* XXX Skip valid arch check if not building binary package */ 00977 if (!spec->anyarch && checkForValidArchitectures(spec)) 00978 return RPMERR_BADSPEC; 00979 00980 if (pkg == spec->packages) 00981 fillOutMainPackage(pkg->header); 00982 00983 if (checkForDuplicates(pkg->header, NVR)) 00984 return RPMERR_BADSPEC; 00985 00986 if (pkg != spec->packages) 00987 headerCopyTags(spec->packages->header, pkg->header, 00988 (int_32 *)copyTagsDuringParse); 00989 00990 if (headerGetEntry(pkg->header, RPMTAG_EPOCH, NULL, NULL, NULL) == 0) { 00991 int num = 0; 00992 headerAddEntry(pkg->header, RPMTAG_EPOCH, RPM_INT32_TYPE, &num, 1); 00993 addMacro(spec->macros, "epoch", NULL, "0", RMIL_SPEC); 00994 } 00995 00996 if (checkForRequired(pkg->header, NVR)) 00997 return RPMERR_BADSPEC; 00998 00999 return nextPart; 01000 } 01001 /*@=boundswrite@*/