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