2 * \file build/parsePreamble.c
3 * Parse tags in global section from spec file.
11 #include <rpm/header.h>
12 #include <rpm/rpmlog.h>
13 #include <rpm/rpmurl.h>
14 #include <rpm/rpmfileutil.h>
15 #include "rpmio/rpmlua.h"
16 #include "build/rpmbuild_internal.h"
17 #include "build/rpmbuild_misc.h"
20 #define SKIPSPACE(s) { while (*(s) && risspace(*(s))) (s)++; }
21 #define SKIPNONSPACE(s) { while (*(s) && !risspace(*(s))) (s)++; }
22 #define SKIPWHITE(_x) {while (*(_x) && (risspace(*_x) || *(_x) == ',')) (_x)++;}
23 #define SKIPNONWHITE(_x){while (*(_x) &&!(risspace(*_x) || *(_x) == ',')) (_x)++;}
27 static const rpmTagVal copyTagsDuringParse[] = {
51 static const rpmTagVal requiredTags[] = {
62 static rpmRC addOrAppendListEntry(Header h, rpmTagVal tag, const char * line)
68 if ((xx = poptParseArgvString(line, &argc, &argv))) {
69 rpmlog(RPMLOG_ERR, _("Error parsing tag field: %s\n"), poptStrerror(xx));
73 headerPutStringArray(h, tag, argv, argc);
79 /* Parse a simple part line that only take -n <pkg> or <pkg> */
80 /* <pkg> is returned in name as a pointer into a dynamic buffer */
84 static int parseSimplePart(const char *line, char **name, int *flag)
87 char *linebuf = xstrdup(line);
90 /* Throw away the first token (the %xxxx) */
91 (void)strtok(linebuf, " \t\n");
94 if (!(tok = strtok(NULL, " \t\n"))) {
99 if (rstreq(tok, "-n")) {
100 if (!(tok = strtok(NULL, " \t\n"))) {
106 *flag = PART_SUBNAME;
108 *name = xstrdup(tok);
109 rc = strtok(NULL, " \t\n") ? 1 : 0;
118 static inline int parseYesNo(const char * s)
120 return ((!s || (s[0] == 'n' || s[0] == 'N' || s[0] == '0') ||
121 !rstrcasecmp(s, "false") || !rstrcasecmp(s, "off"))
125 static struct Source *findSource(rpmSpec spec, uint32_t num, int flag)
129 for (p = spec->sources; p != NULL; p = p->next)
130 if ((num == p->num) && (p->flags & flag)) return p;
135 static int parseNoSource(rpmSpec spec, const char * field, rpmTagVal tag)
142 if (tag == RPMTAG_NOSOURCE) {
143 flag = RPMBUILD_ISSOURCE;
146 flag = RPMBUILD_ISPATCH;
151 for (f = fe; *f != '\0'; f = fe) {
159 if (*fe != '\0') fe++;
161 if (parseUnsignedNum(f, &num)) {
162 rpmlog(RPMLOG_ERR, _("line %d: Bad number: %s\n"),
167 if (! (p = findSource(spec, num, flag))) {
168 rpmlog(RPMLOG_ERR, _("line %d: Bad no%s number: %u\n"),
169 spec->lineNum, name, num);
173 p->flags |= RPMBUILD_ISNO;
180 static int addSource(rpmSpec spec, Package pkg, const char *field, rpmTagVal tag)
184 const char *name = NULL;
192 flag = RPMBUILD_ISSOURCE;
194 fieldp = spec->line + 6;
197 flag = RPMBUILD_ISPATCH;
199 fieldp = spec->line + 5;
202 flag = RPMBUILD_ISICON;
211 if (tag != RPMTAG_ICON) {
212 /* We already know that a ':' exists, and that there */
213 /* are no spaces before it. */
214 /* This also now allows for spaces and tabs between */
215 /* the number and the ':' */
217 char *fieldp_backup = fieldp;
219 while ((*fieldp != ':') && (*fieldp != ' ') && (*fieldp != '\t')) {
225 nump = fieldp_backup;
227 if (nump == NULL || *nump == '\0') {
228 num = flag == RPMBUILD_ISSOURCE ? 0 : INT_MAX;
230 if (parseUnsignedNum(fieldp_backup, &num)) {
231 rpmlog(RPMLOG_ERR, _("line %d: Bad %s number: %s\n"),
232 spec->lineNum, name, spec->line);
240 /* Check whether tags of the same number haven't already been defined */
241 for (p = spec->sources; p != NULL; p = p->next) {
242 if ( p->num != num ) continue;
243 if ((tag == RPMTAG_SOURCE && p->flags == RPMBUILD_ISSOURCE) ||
244 (tag == RPMTAG_PATCH && p->flags == RPMBUILD_ISPATCH)) {
245 rpmlog(RPMLOG_ERR, _("%s %d defined multiple times\n"), name, num);
250 /* Create the entry and link it in */
251 p = xmalloc(sizeof(*p));
253 p->fullSource = xstrdup(field);
255 p->source = strrchr(p->fullSource, '/');
257 if ((buf = strrchr(p->source,'='))) p->source = buf;
260 p->source = p->fullSource;
263 if (tag != RPMTAG_ICON) {
264 p->next = spec->sources;
273 if (tag != RPMTAG_ICON) {
274 char *body = rpmGetPath("%{_sourcedir}/", p->source, NULL);
276 int nofetch = (spec->flags & RPMSPEC_FORCE) ||
277 rpmExpandNumeric("%{_disable_source_fetch}");
279 /* try to download source/patch if it's missing */
280 if (lstat(body, &st) != 0 && errno == ENOENT && !nofetch) {
282 if (urlIsURL(p->fullSource) != URL_IS_UNKNOWN) {
283 url = rstrdup(p->fullSource);
285 url = rpmExpand("%{_default_source_url}", NULL);
286 rstrcat(&url, p->source);
287 if (*url == '%') url = _free(url);
290 rpmlog(RPMLOG_WARNING, _("Downloading %s to %s\n"), url, body);
291 if (urlGetFile(url, body) != 0) {
293 rpmlog(RPMLOG_ERR, _("Couldn't download %s\n"), p->fullSource);
300 rasprintf(&buf, "%s%d",
301 (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
302 rpmPushMacro(spec->macros, buf, NULL, body, RMIL_SPEC);
304 rasprintf(&buf, "%sURL%d",
305 (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
306 rpmPushMacro(spec->macros, buf, NULL, p->fullSource, RMIL_SPEC);
310 rpmlua lua = NULL; /* global state */
311 const char * what = (flag & RPMBUILD_ISPATCH) ? "patches" : "sources";
312 rpmluaPushTable(lua, what);
313 rpmluav var = rpmluavNew();
314 rpmluavSetListMode(var, 1);
315 rpmluavSetValue(var, RPMLUAV_STRING, body);
316 rpmluaSetVar(lua, var);
327 typedef const struct tokenBits_s {
334 static struct tokenBits_s const installScriptBits[] = {
335 { "interp", RPMSENSE_INTERP },
336 { "preun", RPMSENSE_SCRIPT_PREUN },
337 { "pre", RPMSENSE_SCRIPT_PRE },
338 { "postun", RPMSENSE_SCRIPT_POSTUN },
339 { "post", RPMSENSE_SCRIPT_POST },
340 { "rpmlib", RPMSENSE_RPMLIB },
341 { "verify", RPMSENSE_SCRIPT_VERIFY },
342 { "pretrans", RPMSENSE_PRETRANS },
343 { "posttrans", RPMSENSE_POSTTRANS },
344 { "hint", RPMSENSE_MISSINGOK },
345 { "strong", RPMSENSE_STRONG },
351 static int parseBits(const char * s, const tokenBits tokbits,
356 rpmsenseFlags bits = RPMSENSE_ANY;
362 while ((c = *s) && risspace(c)) s++;
364 while ((c = *se) && risalpha(c)) se++;
367 for (tb = tokbits; tb->name; tb++) {
368 if (tb->name != NULL &&
369 strlen(tb->name) == (se-s) && rstreqn(tb->name, s, (se-s)))
372 if (tb->name == NULL) {
377 while ((c = *se) && risspace(c)) se++;
389 static inline char * findLastChar(char * s)
404 static int isMemberInEntry(Header h, const char *name, rpmTagVal tag)
410 if (!headerGet(h, tag, &td, HEADERGET_MINMEM))
413 while ((str = rpmtdNextString(&td))) {
414 if (!rstrcasecmp(str, name)) {
426 static rpmRC checkForValidArchitectures(rpmSpec spec)
428 char *arch = rpmExpand("%{_target_cpu}", NULL);
429 char *os = rpmExpand("%{_target_os}", NULL);
430 rpmRC rc = RPMRC_FAIL; /* assume failure */
432 if (!strcmp(arch, "noarch")) {
434 arch = rpmExpand("%{_build_cpu}", NULL);
437 if (isMemberInEntry(spec->buildRestrictions,
438 arch, RPMTAG_EXCLUDEARCH) == 1) {
439 rpmlog(RPMLOG_ERR, _("Architecture is excluded: %s\n"), arch);
442 if (isMemberInEntry(spec->buildRestrictions,
443 arch, RPMTAG_EXCLUSIVEARCH) == 0) {
444 rpmlog(RPMLOG_ERR, _("Architecture is not included: %s\n"), arch);
447 if (isMemberInEntry(spec->buildRestrictions,
448 os, RPMTAG_EXCLUDEOS) == 1) {
449 rpmlog(RPMLOG_ERR, _("OS is excluded: %s\n"), os);
452 if (isMemberInEntry(spec->buildRestrictions,
453 os, RPMTAG_EXCLUSIVEOS) == 0) {
454 rpmlog(RPMLOG_ERR, _("OS is not included: %s\n"), os);
467 * Check that required tags are present in header.
469 * @param NVR package name-version-release
470 * @return RPMRC_OK if OK
472 static int checkForRequired(Header h, const char * NVR)
477 for (p = requiredTags; *p != 0; p++) {
478 if (!headerIsEntry(h, *p)) {
480 _("%s field must be present in package: %s\n"),
481 rpmTagGetName(*p), NVR);
490 * Check that no duplicate tags are present in header.
492 * @param NVR package name-version-release
493 * @return RPMRC_OK if OK
495 static int checkForDuplicates(Header h, const char * NVR)
498 rpmTagVal tag, lastTag = RPMTAG_NOT_FOUND;
499 HeaderIterator hi = headerInitIterator(h);
501 while ((tag = headerNextTag(hi)) != RPMTAG_NOT_FOUND) {
502 if (tag == lastTag) {
503 rpmlog(RPMLOG_ERR, _("Duplicate %s entries in package: %s\n"),
504 rpmTagGetName(tag), NVR);
509 headerFreeIterator(hi);
516 static struct optionalTag {
519 } const optionalTags[] = {
520 { RPMTAG_VENDOR, "%{vendor}" },
521 { RPMTAG_PACKAGER, "%{packager}" },
522 { RPMTAG_DISTRIBUTION, "%{distribution}" },
523 { RPMTAG_DISTURL, "%{disturl}" },
524 { RPMTAG_BUGURL, "%{bugurl}" },
530 static void fillOutMainPackage(Header h)
532 const struct optionalTag *ot;
534 for (ot = optionalTags; ot->ot_mac != NULL; ot++) {
535 if (!headerIsEntry(h, ot->ot_tag)) {
536 char *val = rpmExpand(ot->ot_mac, NULL);
537 if (val && *val != '%') {
538 headerPutString(h, ot->ot_tag, val);
547 void copyInheritedTags(Header h, Header fromh)
549 headerCopyTags(fromh, h, (rpmTagVal *)copyTagsDuringParse);
554 static rpmRC readIcon(Header h, const char * file)
557 uint8_t *icon = NULL;
559 rpmRC rc = RPMRC_FAIL; /* assume failure */
563 /* XXX use rpmGenPath(rootdir, "%{_sourcedir}/", file) for icon path. */
564 fn = rpmGetPath("%{_sourcedir}/", file, NULL);
566 fd = Fopen(fn, "r.ufdio");
568 rpmlog(RPMLOG_ERR, _("Unable to open icon %s: %s\n"),
573 iconsize = (size >= 0 ? size : (8 * BUFSIZ));
575 rc = RPMRC_OK; /* XXX Eh? */
579 icon = xmalloc(iconsize + 1);
582 nb = Fread(icon, sizeof(icon[0]), iconsize, fd);
583 if (Ferror(fd) || (size >= 0 && nb != size)) {
584 rpmlog(RPMLOG_ERR, _("Unable to read icon %s: %s\n"),
589 if (rstreqn((char*)icon, "GIF", sizeof("GIF")-1)) {
590 headerPutBin(h, RPMTAG_GIF, icon, iconsize);
591 } else if (rstreqn((char*)icon, "/* XPM", sizeof("/* XPM")-1)) {
592 headerPutBin(h, RPMTAG_XPM, icon, iconsize);
594 rpmlog(RPMLOG_ERR, _("Unknown icon type: %s\n"), file);
606 #define SINGLE_TOKEN_ONLY \
608 rpmlog(RPMLOG_ERR, _("line %d: Tag takes single token only: %s\n"), \
609 spec->lineNum, spec->line); \
613 static void specLog(rpmSpec spec, int lvl, const char *line, const char *msg)
616 rpmlog(lvl, _("line %d: %s in: %s\n"), spec->lineNum, msg, spec->line);
618 rpmlog(lvl, _("%s in: %s\n"), msg, line);
623 * Check for inappropriate characters. All alphanums are considered sane.
624 * @param spec spec (or NULL)
625 * @param field string to check
626 * @param whitelist string of permitted characters
627 * @return RPMRC_OK if OK
629 rpmRC rpmCharCheck(rpmSpec spec, const char *field, const char *whitelist)
635 for (ch=field; *ch; ch++) {
636 if (risalnum(*ch) || strchr(whitelist, *ch)) continue;
637 rasprintf(&err, _("Illegal char '%c' (0x%x)"),
638 isprint(*ch) ? *ch : '?', *ch);
640 for (ch=field; *ch; ch++) {
641 if (strchr("%{}", *ch)) {
642 specLog(spec, RPMLOG_WARNING, field,
643 _("Possible unexpanded macro"));
648 if (err == NULL && strstr(field, "..") != NULL) {
649 rasprintf(&err, _("Illegal sequence \"..\""));
653 specLog(spec, RPMLOG_ERR, field, err);
660 static int haveLangTag(Header h, rpmTagVal tag, const char *lang)
662 int rc = 0; /* assume tag not present */
666 /* See if the language is in header i18n table */
667 struct rpmtd_s langtd;
668 const char *s = NULL;
669 headerGet(h, RPMTAG_HEADERI18NTABLE, &langtd, HEADERGET_MINMEM);
670 while ((s = rpmtdNextString(&langtd)) != NULL) {
671 if (rstreq(s, lang)) {
672 langNum = rpmtdGetIndex(&langtd);
676 rpmtdFreeData(&langtd);
682 /* If locale is present, check the actual tag content */
685 headerGet(h, tag, &td, HEADERGET_MINMEM|HEADERGET_RAW);
686 if (rpmtdSetIndex(&td, langNum) == langNum) {
687 const char *s = rpmtdGetString(&td);
688 /* non-empty string means a dupe */
698 int addLangTag(rpmSpec spec, Header h, rpmTagVal tag,
699 const char *field, const char *lang)
703 if (haveLangTag(h, tag, lang)) {
704 /* Turn this into an error eventually */
705 rpmlog(RPMLOG_WARNING, _("line %d: second %s, please remove it\n"),
706 spec->lineNum, rpmTagGetName(tag));
711 headerPutString(h, tag, field);
713 skip = ((spec->flags & RPMSPEC_NOLANG) &&
714 !rstreq(lang, RPMBUILD_DEFAULT_LANG));
717 headerAddI18NString(h, tag, field, lang);
723 static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag,
724 const char *macro, const char *lang)
726 char * field = spec->line;
729 rpmsenseFlags tagflags = RPMSENSE_ANY;
730 rpmRC rc = RPMRC_FAIL;
732 if (field == NULL) /* XXX can't happen */
734 /* Find the start of the "field" and strip trailing space */
735 while ((*field) && (*field != ':'))
738 rpmlog(RPMLOG_ERR, _("line %d: Malformed tag: %s\n"),
739 spec->lineNum, spec->line);
746 rpmlog(RPMLOG_ERR, _("line %d: Empty tag: %s\n"),
747 spec->lineNum, spec->line);
750 end = findLastChar(field);
753 /* See if this is multi-token */
762 if (rpmCharCheck(spec, field, WHITELIST_NAME))
764 headerPutString(pkg->header, tag, field);
765 /* Main pkg name is unknown at the start, populate as soon as we can */
766 if (pkg == spec->packages)
767 pkg->name = rpmstrPoolId(spec->pool, field, 1);
772 if (rpmCharCheck(spec, field, "._+%{}~"))
774 headerPutString(pkg->header, tag, field);
779 /* XXX TODO: validate format somehow */
782 headerPutString(pkg->header, tag, field);
786 case RPMTAG_DISTRIBUTION:
789 case RPMTAG_PACKAGER:
790 if (addLangTag(spec, pkg->header, tag, field, lang))
793 case RPMTAG_BUILDROOT:
794 /* just silently ignore BuildRoot */
797 case RPMTAG_PREFIXES: {
800 if (addOrAppendListEntry(pkg->header, tag, field))
802 headerGet(pkg->header, tag, &td, HEADERGET_MINMEM);
803 while ((str = rpmtdNextString(&td))) {
804 size_t len = strlen(str);
805 if (len > 1 && str[len-1] == '/') {
807 _("line %d: Prefixes must not end with \"/\": %s\n"),
808 spec->lineNum, spec->line);
818 if (field[0] != '/') {
819 rpmlog(RPMLOG_ERR, _("line %d: Docdir must begin with '/': %s\n"),
820 spec->lineNum, spec->line);
824 rpmPopMacro(NULL, "_docdir");
825 rpmPushMacro(NULL, "_docdir", NULL, field, RMIL_SPEC);
830 if (parseUnsignedNum(field, &epoch)) {
832 _("line %d: Epoch field must be an unsigned number: %s\n"),
833 spec->lineNum, spec->line);
836 headerPutUint32(pkg->header, tag, &epoch, 1);
839 case RPMTAG_AUTOREQPROV:
840 pkg->autoReq = parseYesNo(field);
841 pkg->autoProv = pkg->autoReq;
844 pkg->autoReq = parseYesNo(field);
846 case RPMTAG_AUTOPROV:
847 pkg->autoProv = parseYesNo(field);
852 if (addSource(spec, pkg, field, tag))
857 if (addSource(spec, pkg, field, tag) || readIcon(pkg->header, field))
860 case RPMTAG_NOSOURCE:
863 if (parseNoSource(spec, field, tag))
866 case RPMTAG_ORDERNAME:
867 case RPMTAG_REQUIRENAME:
868 if (parseBits(lang, installScriptBits, &tagflags)) {
869 rpmlog(RPMLOG_ERR, _("line %d: Bad %s: qualifiers: %s\n"),
870 spec->lineNum, rpmTagGetName(tag), spec->line);
875 case RPMTAG_RECOMMENDNAME:
876 case RPMTAG_SUGGESTNAME:
877 case RPMTAG_SUPPLEMENTNAME:
878 case RPMTAG_ENHANCENAME:
879 case RPMTAG_CONFLICTNAME:
880 case RPMTAG_OBSOLETENAME:
881 case RPMTAG_PROVIDENAME:
882 if (parseRCPOT(spec, pkg, field, tag, 0, tagflags, addReqProvPkg, NULL))
885 case RPMTAG_BUILDPREREQ:
886 case RPMTAG_BUILDREQUIRES:
887 case RPMTAG_BUILDCONFLICTS:
888 if (parseRCPOT(spec, spec->sourcePackage, field, tag, 0, tagflags, addReqProvPkg, NULL))
891 case RPMTAG_OLDSUGGESTSFLAGS:
892 case RPMTAG_OLDENHANCESFLAGS:
893 case RPMTAG_BUILDSUGGESTS:
894 case RPMTAG_BUILDENHANCES:
895 tagflags = RPMSENSE_MISSINGOK;
896 if (macro && (!strcmp(macro, "recommends") || !strcmp(macro, "buildrecommends")))
897 tagflags |= RPMSENSE_STRONG;
898 if (macro && (!strcmp(macro, "supplements") || !strcmp(macro, "buildsupplements")))
899 tagflags |= RPMSENSE_STRONG;
900 if (parseRCPOT(spec, pkg, field, tag, 0, tagflags, addReqProvPkg, NULL))
903 case RPMTAG_EXCLUDEARCH:
904 case RPMTAG_EXCLUSIVEARCH:
905 case RPMTAG_EXCLUDEOS:
906 case RPMTAG_EXCLUSIVEOS:
907 if (addOrAppendListEntry(spec->buildRestrictions, tag, field))
910 case RPMTAG_BUILDARCHS: {
912 const char **BANames = NULL;
913 if (poptParseArgvString(field, &BACount, &BANames)) {
915 _("line %d: Bad BuildArchitecture format: %s\n"),
916 spec->lineNum, spec->line);
919 if (spec->packages == pkg) {
922 _("line %d: Duplicate BuildArch entry: %s\n"),
923 spec->lineNum, spec->line);
924 BANames = _free(BANames);
927 spec->BACount = BACount;
928 spec->BANames = BANames;
930 if (BACount != 1 || !rstreq(BANames[0], "noarch")) {
932 _("line %d: Only noarch subpackages are supported: %s\n"),
933 spec->lineNum, spec->line);
934 BANames = _free(BANames);
937 headerPutString(pkg->header, RPMTAG_ARCH, "noarch");
940 spec->BANames = _free(spec->BANames);
943 case RPMTAG_REMOVEPATHPOSTFIXES:
944 argvSplit(&pkg->removePostfixes, field, ":");
946 case RPMTAG_BUILDINFO:
947 if (addOrAppendListEntry(pkg->header, tag, field))
951 rpmlog(RPMLOG_ERR, _("Internal error: Bogus tag %d\n"), tag);
956 rpmPushMacro(spec->macros, macro, NULL, field, RMIL_SPEC);
957 /* Add a separate uppercase macro for tags from the main package */
958 if (pkg == spec->packages) {
959 char *m = xstrdup(macro);
960 for (char *p = m; *p; ++p)
962 rpmPushMacro(spec->macros, m, NULL, field, RMIL_SPEC);
971 /* This table has to be in a peculiar order. If one tag is the */
972 /* same as another, plus a few letters, it must come first. */
976 typedef const struct PreambleRec_s {
984 #define LEN_AND_STR(_tag) (sizeof(_tag)-1), _tag
986 static struct PreambleRec_s const preambleList[] = {
987 {RPMTAG_NAME, 0, 0, LEN_AND_STR("name")},
988 {RPMTAG_VERSION, 0, 0, LEN_AND_STR("version")},
989 {RPMTAG_RELEASE, 0, 0, LEN_AND_STR("release")},
990 {RPMTAG_EPOCH, 0, 0, LEN_AND_STR("epoch")},
991 {RPMTAG_SUMMARY, 1, 0, LEN_AND_STR("summary")},
992 {RPMTAG_LICENSE, 0, 0, LEN_AND_STR("license")},
993 {RPMTAG_DISTRIBUTION, 0, 0, LEN_AND_STR("distribution")},
994 {RPMTAG_DISTURL, 0, 0, LEN_AND_STR("disturl")},
995 {RPMTAG_VENDOR, 0, 0, LEN_AND_STR("vendor")},
996 {RPMTAG_GROUP, 1, 0, LEN_AND_STR("group")},
997 {RPMTAG_PACKAGER, 0, 0, LEN_AND_STR("packager")},
998 {RPMTAG_URL, 0, 0, LEN_AND_STR("url")},
999 {RPMTAG_VCS, 0, 0, LEN_AND_STR("vcs")},
1000 {RPMTAG_SOURCE, 0, 0, LEN_AND_STR("source")},
1001 {RPMTAG_PATCH, 0, 0, LEN_AND_STR("patch")},
1002 {RPMTAG_NOSOURCE, 0, 0, LEN_AND_STR("nosource")},
1003 {RPMTAG_NOPATCH, 0, 0, LEN_AND_STR("nopatch")},
1004 {RPMTAG_EXCLUDEARCH, 0, 0, LEN_AND_STR("excludearch")},
1005 {RPMTAG_EXCLUSIVEARCH, 0, 0, LEN_AND_STR("exclusivearch")},
1006 {RPMTAG_EXCLUDEOS, 0, 0, LEN_AND_STR("excludeos")},
1007 {RPMTAG_EXCLUSIVEOS, 0, 0, LEN_AND_STR("exclusiveos")},
1008 {RPMTAG_ICON, 0, 0, LEN_AND_STR("icon")},
1009 {RPMTAG_PROVIDENAME, 0, 0, LEN_AND_STR("provides")},
1010 {RPMTAG_REQUIRENAME, 2, 0, LEN_AND_STR("requires")},
1011 {RPMTAG_RECOMMENDNAME, 0, 0, LEN_AND_STR("recommends")},
1012 {RPMTAG_SUGGESTNAME, 0, 0, LEN_AND_STR("suggests")},
1013 {RPMTAG_SUPPLEMENTNAME, 0, 0, LEN_AND_STR("supplements")},
1014 {RPMTAG_ENHANCENAME, 0, 0, LEN_AND_STR("enhances")},
1015 {RPMTAG_PREREQ, 2, 1, LEN_AND_STR("prereq")},
1016 {RPMTAG_CONFLICTNAME, 0, 0, LEN_AND_STR("conflicts")},
1017 {RPMTAG_OBSOLETENAME, 0, 0, LEN_AND_STR("obsoletes")},
1018 {RPMTAG_PREFIXES, 0, 0, LEN_AND_STR("prefixes")},
1019 {RPMTAG_PREFIXES, 0, 0, LEN_AND_STR("prefix")},
1020 {RPMTAG_BUILDROOT, 0, 0, LEN_AND_STR("buildroot")},
1021 {RPMTAG_BUILDARCHS, 0, 0, LEN_AND_STR("buildarchitectures")},
1022 {RPMTAG_BUILDARCHS, 0, 0, LEN_AND_STR("buildarch")},
1023 {RPMTAG_BUILDCONFLICTS, 0, 0, LEN_AND_STR("buildconflicts")},
1024 {RPMTAG_BUILDPREREQ, 0, 1, LEN_AND_STR("buildprereq")},
1025 {RPMTAG_BUILDREQUIRES, 0, 0, LEN_AND_STR("buildrequires")},
1026 {RPMTAG_AUTOREQPROV, 0, 0, LEN_AND_STR("autoreqprov")},
1027 {RPMTAG_AUTOREQ, 0, 0, LEN_AND_STR("autoreq")},
1028 {RPMTAG_AUTOPROV, 0, 0, LEN_AND_STR("autoprov")},
1029 {RPMTAG_DOCDIR, 0, 0, LEN_AND_STR("docdir")},
1030 {RPMTAG_DISTTAG, 0, 0, LEN_AND_STR("disttag")},
1031 {RPMTAG_BUGURL, 0, 0, LEN_AND_STR("bugurl")},
1032 {RPMTAG_ORDERFLAGS, 2, 0, LEN_AND_STR("orderwithrequires")},
1033 {RPMTAG_OLDSUGGESTSFLAGS, 0, 0, LEN_AND_STR("recommends")},
1034 {RPMTAG_OLDSUGGESTSFLAGS, 0, 0, LEN_AND_STR("suggests")},
1035 {RPMTAG_OLDENHANCESFLAGS, 0, 0, LEN_AND_STR("supplements")},
1036 {RPMTAG_OLDENHANCESFLAGS, 0, 0, LEN_AND_STR("enhances")},
1037 {RPMTAG_BUILDSUGGESTS, 0, 0, LEN_AND_STR("buildrecommends")},
1038 {RPMTAG_BUILDSUGGESTS, 0, 0, LEN_AND_STR("buildsuggests")},
1039 {RPMTAG_BUILDENHANCES, 0, 0, LEN_AND_STR("buildsupplements")},
1040 {RPMTAG_BUILDENHANCES, 0, 0, LEN_AND_STR("buildenhances")},
1041 {RPMTAG_SECMANIFEST, 0, 0, LEN_AND_STR("manifest")},
1042 {RPMTAG_ORDERNAME, 2, 0, LEN_AND_STR("orderwithrequires")},
1043 {RPMTAG_REMOVEPATHPOSTFIXES,0, 0, LEN_AND_STR("removepathpostfixes")},
1044 {RPMTAG_BUILDINFO, 0, 0, LEN_AND_STR("buildinfo")},
1050 static int findPreambleTag(rpmSpec spec,rpmTagVal * tag,
1051 const char ** macro, char * lang)
1056 for (p = preambleList; p->token != NULL; p++) {
1057 if (!(p->token && !rstrncasecmp(spec->line, p->token, p->len)))
1059 if (p->deprecated) {
1060 rpmlog(RPMLOG_WARNING, _("line %d: %s is deprecated: %s\n"),
1061 spec->lineNum, p->token, spec->line);
1065 if (p == NULL || p->token == NULL)
1068 s = spec->line + p->len;
1074 /* Unless this is a source or a patch, a ':' better be next */
1075 if (p->tag != RPMTAG_SOURCE && p->tag != RPMTAG_PATCH) {
1076 if (*s != ':') return 1;
1080 case 1: /* Parse optional ( <token> ). */
1083 /* Type 1 is multilang, 2 is qualifiers with no defaults */
1084 strcpy(lang, (p->type == 1) ? RPMBUILD_DEFAULT_LANG : "");
1087 if (*s != '(') return 1;
1090 while (!risspace(*s) && *s != ')')
1094 if (*s != ')') return 1;
1097 if (*s != ':') return 1;
1107 int parsePreamble(rpmSpec spec, int initialPackage)
1109 int nextPart = PART_ERROR;
1110 int res = PART_ERROR; /* assume failure */
1118 if (! initialPackage) {
1119 /* There is one option to %package: <pkg> or -n <pkg> */
1120 if (parseSimplePart(spec->line, &name, &flag)) {
1121 rpmlog(RPMLOG_ERR, _("Bad package specification: %s\n"),
1126 //if (rpmCharCheck(spec, name, WHITELIST_NAME))
1129 if (!lookupPackage(spec, name, flag, NULL)) {
1130 //exist %package debuginfo, need to ignore it, because there has been
1131 //debuginfo package created by %debug_package macro.
1132 if ((name != NULL) && (0 == strncmp(name, "debuginfo", 9)))
1134 rpmlog(RPMLOG_WARNING, _("debuginfo package has been in spec file, Don't write again this %s"), spec->line);
1135 if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
1136 nextPart = PART_NONE;
1137 } else if (rc < 0) {
1141 while (! (nextPart = isPart(spec->line))) {
1142 if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
1143 nextPart = PART_NONE;
1158 /* Construct the package */
1159 if (flag == PART_SUBNAME) {
1160 rasprintf(&NVR, "%s-%s",
1161 headerGetString(spec->packages->header, RPMTAG_NAME), name);
1163 NVR = xstrdup(name);
1165 pkg = newPackage(NVR, spec->pool, &spec->packages);
1166 headerPutString(pkg->header, RPMTAG_NAME, NVR);
1168 NVR = xstrdup("(main package)");
1169 pkg = newPackage(NULL, spec->pool, &spec->packages);
1170 spec->sourcePackage = newPackage(NULL, spec->pool, NULL);
1174 if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
1175 nextPart = PART_NONE;
1176 } else if (rc < 0) {
1179 while (! (nextPart = isPart(spec->line))) {
1183 /* Skip blank lines */
1186 if (*linep != '\0') {
1187 if (findPreambleTag(spec, &tag, ¯o, lang)) {
1188 if (spec->lineNum == 1 &&
1189 (unsigned char)(spec->line[0]) == 0xed &&
1190 (unsigned char)(spec->line[1]) == 0xab &&
1191 (unsigned char)(spec->line[2]) == 0xee &&
1192 (unsigned char)(spec->line[3]) == 0xdb) {
1193 rpmlog(RPMLOG_ERR, _("Binary rpm package found. Expected spec file!\n"));
1196 rpmlog(RPMLOG_ERR, _("line %d: Unknown tag: %s\n"),
1197 spec->lineNum, spec->line);
1200 if (handlePreambleTag(spec, pkg, tag, macro, lang)) {
1203 if (spec->BANames && !spec->recursing) {
1204 res = PART_BUILDARCHITECTURES;
1209 readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
1210 nextPart = PART_NONE;
1220 * Expand buildroot one more time to get %{version} and the like
1221 * from the main package, validate sanity. The spec->buildRoot could
1222 * still contain unexpanded macros but it cannot be empty or '/', and it
1223 * can't be messed with by anything spec does beyond this point.
1225 if (initialPackage) {
1226 char *buildRoot = rpmGetPath(spec->buildRoot, NULL);
1227 if (*buildRoot == '\0') {
1228 rpmlog(RPMLOG_ERR, _("%%{buildroot} couldn't be empty\n"));
1231 if (rstreq(buildRoot, "/")) {
1232 rpmlog(RPMLOG_ERR, _("%%{buildroot} can not be \"/\"\n"));
1235 free(spec->buildRoot);
1236 spec->buildRoot = buildRoot;
1237 rpmPushMacro(spec->macros, "buildroot", NULL, spec->buildRoot, RMIL_SPEC);
1240 /* XXX Skip valid arch check if not building binary package */
1241 if (!(spec->flags & RPMSPEC_ANYARCH) && checkForValidArchitectures(spec)) {
1245 /* It is the main package */
1246 if (pkg == spec->packages) {
1247 fillOutMainPackage(pkg->header);
1248 /* Define group tag to something when group is undefined in main package*/
1249 if (!headerIsEntry(pkg->header, RPMTAG_GROUP)) {
1250 headerPutString(pkg->header, RPMTAG_GROUP, "Unspecified");
1254 if (checkForDuplicates(pkg->header, NVR)) {
1258 if (pkg != spec->packages) {
1259 copyInheritedTags(pkg->header, spec->packages->header);
1262 if (checkForRequired(pkg->header, NVR)) {
1266 /* if we get down here nextPart has been set to non-error */