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\n"),
706 spec->lineNum, rpmTagGetName(tag));
710 headerPutString(h, tag, field);
712 skip = ((spec->flags & RPMSPEC_NOLANG) &&
713 !rstreq(lang, RPMBUILD_DEFAULT_LANG));
716 headerAddI18NString(h, tag, field, lang);
722 static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag,
723 const char *macro, const char *lang)
725 char * field = spec->line;
728 rpmsenseFlags tagflags = RPMSENSE_ANY;
729 rpmRC rc = RPMRC_FAIL;
731 if (field == NULL) /* XXX can't happen */
733 /* Find the start of the "field" and strip trailing space */
734 while ((*field) && (*field != ':'))
737 rpmlog(RPMLOG_ERR, _("line %d: Malformed tag: %s\n"),
738 spec->lineNum, spec->line);
745 rpmlog(RPMLOG_ERR, _("line %d: Empty tag: %s\n"),
746 spec->lineNum, spec->line);
749 end = findLastChar(field);
752 /* See if this is multi-token */
761 if (rpmCharCheck(spec, field, WHITELIST_NAME))
763 headerPutString(pkg->header, tag, field);
764 /* Main pkg name is unknown at the start, populate as soon as we can */
765 if (pkg == spec->packages)
766 pkg->name = rpmstrPoolId(spec->pool, field, 1);
771 if (rpmCharCheck(spec, field, "._+%{}~"))
773 headerPutString(pkg->header, tag, field);
778 /* XXX TODO: validate format somehow */
781 headerPutString(pkg->header, tag, field);
785 case RPMTAG_DISTRIBUTION:
788 case RPMTAG_PACKAGER:
789 if (addLangTag(spec, pkg->header, tag, field, lang))
792 case RPMTAG_BUILDROOT:
793 /* just silently ignore BuildRoot */
796 case RPMTAG_PREFIXES: {
799 if (addOrAppendListEntry(pkg->header, tag, field))
801 headerGet(pkg->header, tag, &td, HEADERGET_MINMEM);
802 while ((str = rpmtdNextString(&td))) {
803 size_t len = strlen(str);
804 if (len > 1 && str[len-1] == '/') {
806 _("line %d: Prefixes must not end with \"/\": %s\n"),
807 spec->lineNum, spec->line);
817 if (field[0] != '/') {
818 rpmlog(RPMLOG_ERR, _("line %d: Docdir must begin with '/': %s\n"),
819 spec->lineNum, spec->line);
823 rpmPopMacro(NULL, "_docdir");
824 rpmPushMacro(NULL, "_docdir", NULL, field, RMIL_SPEC);
829 if (parseUnsignedNum(field, &epoch)) {
831 _("line %d: Epoch field must be an unsigned number: %s\n"),
832 spec->lineNum, spec->line);
835 headerPutUint32(pkg->header, tag, &epoch, 1);
838 case RPMTAG_AUTOREQPROV:
839 pkg->autoReq = parseYesNo(field);
840 pkg->autoProv = pkg->autoReq;
843 pkg->autoReq = parseYesNo(field);
845 case RPMTAG_AUTOPROV:
846 pkg->autoProv = parseYesNo(field);
851 if (addSource(spec, pkg, field, tag))
856 if (addSource(spec, pkg, field, tag) || readIcon(pkg->header, field))
859 case RPMTAG_NOSOURCE:
862 if (parseNoSource(spec, field, tag))
865 case RPMTAG_ORDERNAME:
866 case RPMTAG_REQUIRENAME:
867 if (parseBits(lang, installScriptBits, &tagflags)) {
868 rpmlog(RPMLOG_ERR, _("line %d: Bad %s: qualifiers: %s\n"),
869 spec->lineNum, rpmTagGetName(tag), spec->line);
874 case RPMTAG_RECOMMENDNAME:
875 case RPMTAG_SUGGESTNAME:
876 case RPMTAG_SUPPLEMENTNAME:
877 case RPMTAG_ENHANCENAME:
878 case RPMTAG_CONFLICTNAME:
879 case RPMTAG_OBSOLETENAME:
880 case RPMTAG_PROVIDENAME:
881 if (parseRCPOT(spec, pkg, field, tag, 0, tagflags, addReqProvPkg, NULL))
884 case RPMTAG_BUILDPREREQ:
885 case RPMTAG_BUILDREQUIRES:
886 case RPMTAG_BUILDCONFLICTS:
887 if (parseRCPOT(spec, spec->sourcePackage, field, tag, 0, tagflags, addReqProvPkg, NULL))
890 case RPMTAG_OLDSUGGESTSFLAGS:
891 case RPMTAG_OLDENHANCESFLAGS:
892 case RPMTAG_BUILDSUGGESTS:
893 case RPMTAG_BUILDENHANCES:
894 tagflags = RPMSENSE_MISSINGOK;
895 if (macro && (!strcmp(macro, "recommends") || !strcmp(macro, "buildrecommends")))
896 tagflags |= RPMSENSE_STRONG;
897 if (macro && (!strcmp(macro, "supplements") || !strcmp(macro, "buildsupplements")))
898 tagflags |= RPMSENSE_STRONG;
899 if (parseRCPOT(spec, pkg, field, tag, 0, tagflags, addReqProvPkg, NULL))
902 case RPMTAG_EXCLUDEARCH:
903 case RPMTAG_EXCLUSIVEARCH:
904 case RPMTAG_EXCLUDEOS:
905 case RPMTAG_EXCLUSIVEOS:
906 if (addOrAppendListEntry(spec->buildRestrictions, tag, field))
909 case RPMTAG_BUILDARCHS: {
911 const char **BANames = NULL;
912 if (poptParseArgvString(field, &BACount, &BANames)) {
914 _("line %d: Bad BuildArchitecture format: %s\n"),
915 spec->lineNum, spec->line);
918 if (spec->packages == pkg) {
921 _("line %d: Duplicate BuildArch entry: %s\n"),
922 spec->lineNum, spec->line);
923 BANames = _free(BANames);
926 spec->BACount = BACount;
927 spec->BANames = BANames;
929 if (BACount != 1 || !rstreq(BANames[0], "noarch")) {
931 _("line %d: Only noarch subpackages are supported: %s\n"),
932 spec->lineNum, spec->line);
933 BANames = _free(BANames);
936 headerPutString(pkg->header, RPMTAG_ARCH, "noarch");
939 spec->BANames = _free(spec->BANames);
942 case RPMTAG_REMOVEPATHPOSTFIXES:
943 argvSplit(&pkg->removePostfixes, field, ":");
945 case RPMTAG_BUILDINFO:
946 if (addOrAppendListEntry(pkg->header, tag, field))
950 rpmlog(RPMLOG_ERR, _("Internal error: Bogus tag %d\n"), tag);
955 rpmPushMacro(spec->macros, macro, NULL, field, RMIL_SPEC);
956 /* Add a separate uppercase macro for tags from the main package */
957 if (pkg == spec->packages) {
958 char *m = xstrdup(macro);
959 for (char *p = m; *p; ++p)
961 rpmPushMacro(spec->macros, m, NULL, field, RMIL_SPEC);
970 /* This table has to be in a peculiar order. If one tag is the */
971 /* same as another, plus a few letters, it must come first. */
975 typedef const struct PreambleRec_s {
983 #define LEN_AND_STR(_tag) (sizeof(_tag)-1), _tag
985 static struct PreambleRec_s const preambleList[] = {
986 {RPMTAG_NAME, 0, 0, LEN_AND_STR("name")},
987 {RPMTAG_VERSION, 0, 0, LEN_AND_STR("version")},
988 {RPMTAG_RELEASE, 0, 0, LEN_AND_STR("release")},
989 {RPMTAG_EPOCH, 0, 0, LEN_AND_STR("epoch")},
990 {RPMTAG_SUMMARY, 1, 0, LEN_AND_STR("summary")},
991 {RPMTAG_LICENSE, 0, 0, LEN_AND_STR("license")},
992 {RPMTAG_DISTRIBUTION, 0, 0, LEN_AND_STR("distribution")},
993 {RPMTAG_DISTURL, 0, 0, LEN_AND_STR("disturl")},
994 {RPMTAG_VENDOR, 0, 0, LEN_AND_STR("vendor")},
995 {RPMTAG_GROUP, 1, 0, LEN_AND_STR("group")},
996 {RPMTAG_PACKAGER, 0, 0, LEN_AND_STR("packager")},
997 {RPMTAG_URL, 0, 0, LEN_AND_STR("url")},
998 {RPMTAG_VCS, 0, 0, LEN_AND_STR("vcs")},
999 {RPMTAG_SOURCE, 0, 0, LEN_AND_STR("source")},
1000 {RPMTAG_PATCH, 0, 0, LEN_AND_STR("patch")},
1001 {RPMTAG_NOSOURCE, 0, 0, LEN_AND_STR("nosource")},
1002 {RPMTAG_NOPATCH, 0, 0, LEN_AND_STR("nopatch")},
1003 {RPMTAG_EXCLUDEARCH, 0, 0, LEN_AND_STR("excludearch")},
1004 {RPMTAG_EXCLUSIVEARCH, 0, 0, LEN_AND_STR("exclusivearch")},
1005 {RPMTAG_EXCLUDEOS, 0, 0, LEN_AND_STR("excludeos")},
1006 {RPMTAG_EXCLUSIVEOS, 0, 0, LEN_AND_STR("exclusiveos")},
1007 {RPMTAG_ICON, 0, 0, LEN_AND_STR("icon")},
1008 {RPMTAG_PROVIDENAME, 0, 0, LEN_AND_STR("provides")},
1009 {RPMTAG_REQUIRENAME, 2, 0, LEN_AND_STR("requires")},
1010 {RPMTAG_RECOMMENDNAME, 0, 0, LEN_AND_STR("recommends")},
1011 {RPMTAG_SUGGESTNAME, 0, 0, LEN_AND_STR("suggests")},
1012 {RPMTAG_SUPPLEMENTNAME, 0, 0, LEN_AND_STR("supplements")},
1013 {RPMTAG_ENHANCENAME, 0, 0, LEN_AND_STR("enhances")},
1014 {RPMTAG_PREREQ, 2, 1, LEN_AND_STR("prereq")},
1015 {RPMTAG_CONFLICTNAME, 0, 0, LEN_AND_STR("conflicts")},
1016 {RPMTAG_OBSOLETENAME, 0, 0, LEN_AND_STR("obsoletes")},
1017 {RPMTAG_PREFIXES, 0, 0, LEN_AND_STR("prefixes")},
1018 {RPMTAG_PREFIXES, 0, 0, LEN_AND_STR("prefix")},
1019 {RPMTAG_BUILDROOT, 0, 0, LEN_AND_STR("buildroot")},
1020 {RPMTAG_BUILDARCHS, 0, 0, LEN_AND_STR("buildarchitectures")},
1021 {RPMTAG_BUILDARCHS, 0, 0, LEN_AND_STR("buildarch")},
1022 {RPMTAG_BUILDCONFLICTS, 0, 0, LEN_AND_STR("buildconflicts")},
1023 {RPMTAG_BUILDPREREQ, 0, 1, LEN_AND_STR("buildprereq")},
1024 {RPMTAG_BUILDREQUIRES, 0, 0, LEN_AND_STR("buildrequires")},
1025 {RPMTAG_AUTOREQPROV, 0, 0, LEN_AND_STR("autoreqprov")},
1026 {RPMTAG_AUTOREQ, 0, 0, LEN_AND_STR("autoreq")},
1027 {RPMTAG_AUTOPROV, 0, 0, LEN_AND_STR("autoprov")},
1028 {RPMTAG_DOCDIR, 0, 0, LEN_AND_STR("docdir")},
1029 {RPMTAG_DISTTAG, 0, 0, LEN_AND_STR("disttag")},
1030 {RPMTAG_BUGURL, 0, 0, LEN_AND_STR("bugurl")},
1031 {RPMTAG_ORDERFLAGS, 2, 0, LEN_AND_STR("orderwithrequires")},
1032 {RPMTAG_OLDSUGGESTSFLAGS, 0, 0, LEN_AND_STR("recommends")},
1033 {RPMTAG_OLDSUGGESTSFLAGS, 0, 0, LEN_AND_STR("suggests")},
1034 {RPMTAG_OLDENHANCESFLAGS, 0, 0, LEN_AND_STR("supplements")},
1035 {RPMTAG_OLDENHANCESFLAGS, 0, 0, LEN_AND_STR("enhances")},
1036 {RPMTAG_BUILDSUGGESTS, 0, 0, LEN_AND_STR("buildrecommends")},
1037 {RPMTAG_BUILDSUGGESTS, 0, 0, LEN_AND_STR("buildsuggests")},
1038 {RPMTAG_BUILDENHANCES, 0, 0, LEN_AND_STR("buildsupplements")},
1039 {RPMTAG_BUILDENHANCES, 0, 0, LEN_AND_STR("buildenhances")},
1040 {RPMTAG_SECMANIFEST, 0, 0, LEN_AND_STR("manifest")},
1041 {RPMTAG_ORDERNAME, 2, 0, LEN_AND_STR("orderwithrequires")},
1042 {RPMTAG_REMOVEPATHPOSTFIXES,0, 0, LEN_AND_STR("removepathpostfixes")},
1043 {RPMTAG_BUILDINFO, 0, 0, LEN_AND_STR("buildinfo")},
1049 static int findPreambleTag(rpmSpec spec,rpmTagVal * tag,
1050 const char ** macro, char * lang)
1055 for (p = preambleList; p->token != NULL; p++) {
1056 if (!(p->token && !rstrncasecmp(spec->line, p->token, p->len)))
1058 if (p->deprecated) {
1059 rpmlog(RPMLOG_WARNING, _("line %d: %s is deprecated: %s\n"),
1060 spec->lineNum, p->token, spec->line);
1064 if (p == NULL || p->token == NULL)
1067 s = spec->line + p->len;
1073 /* Unless this is a source or a patch, a ':' better be next */
1074 if (p->tag != RPMTAG_SOURCE && p->tag != RPMTAG_PATCH) {
1075 if (*s != ':') return 1;
1079 case 1: /* Parse optional ( <token> ). */
1082 /* Type 1 is multilang, 2 is qualifiers with no defaults */
1083 strcpy(lang, (p->type == 1) ? RPMBUILD_DEFAULT_LANG : "");
1086 if (*s != '(') return 1;
1089 while (!risspace(*s) && *s != ')')
1093 if (*s != ')') return 1;
1096 if (*s != ':') return 1;
1106 int parsePreamble(rpmSpec spec, int initialPackage)
1108 int nextPart = PART_ERROR;
1109 int res = PART_ERROR; /* assume failure */
1117 if (! initialPackage) {
1118 /* There is one option to %package: <pkg> or -n <pkg> */
1119 if (parseSimplePart(spec->line, &name, &flag)) {
1120 rpmlog(RPMLOG_ERR, _("Bad package specification: %s\n"),
1125 //if (rpmCharCheck(spec, name, WHITELIST_NAME))
1128 if (!lookupPackage(spec, name, flag, NULL)) {
1133 /* Construct the package */
1134 if (flag == PART_SUBNAME) {
1135 rasprintf(&NVR, "%s-%s",
1136 headerGetString(spec->packages->header, RPMTAG_NAME), name);
1138 NVR = xstrdup(name);
1140 pkg = newPackage(NVR, spec->pool, &spec->packages);
1141 headerPutString(pkg->header, RPMTAG_NAME, NVR);
1143 NVR = xstrdup("(main package)");
1144 pkg = newPackage(NULL, spec->pool, &spec->packages);
1145 spec->sourcePackage = newPackage(NULL, spec->pool, NULL);
1149 if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
1150 nextPart = PART_NONE;
1151 } else if (rc < 0) {
1154 while (! (nextPart = isPart(spec->line))) {
1158 /* Skip blank lines */
1161 if (*linep != '\0') {
1162 if (findPreambleTag(spec, &tag, ¯o, lang)) {
1163 if (spec->lineNum == 1 &&
1164 (unsigned char)(spec->line[0]) == 0xed &&
1165 (unsigned char)(spec->line[1]) == 0xab &&
1166 (unsigned char)(spec->line[2]) == 0xee &&
1167 (unsigned char)(spec->line[3]) == 0xdb) {
1168 rpmlog(RPMLOG_ERR, _("Binary rpm package found. Expected spec file!\n"));
1171 rpmlog(RPMLOG_ERR, _("line %d: Unknown tag: %s\n"),
1172 spec->lineNum, spec->line);
1175 if (handlePreambleTag(spec, pkg, tag, macro, lang)) {
1178 if (spec->BANames && !spec->recursing) {
1179 res = PART_BUILDARCHITECTURES;
1184 readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
1185 nextPart = PART_NONE;
1195 * Expand buildroot one more time to get %{version} and the like
1196 * from the main package, validate sanity. The spec->buildRoot could
1197 * still contain unexpanded macros but it cannot be empty or '/', and it
1198 * can't be messed with by anything spec does beyond this point.
1200 if (initialPackage) {
1201 char *buildRoot = rpmGetPath(spec->buildRoot, NULL);
1202 if (*buildRoot == '\0') {
1203 rpmlog(RPMLOG_ERR, _("%%{buildroot} couldn't be empty\n"));
1206 if (rstreq(buildRoot, "/")) {
1207 rpmlog(RPMLOG_ERR, _("%%{buildroot} can not be \"/\"\n"));
1210 free(spec->buildRoot);
1211 spec->buildRoot = buildRoot;
1212 rpmPushMacro(spec->macros, "buildroot", NULL, spec->buildRoot, RMIL_SPEC);
1215 /* XXX Skip valid arch check if not building binary package */
1216 if (!(spec->flags & RPMSPEC_ANYARCH) && checkForValidArchitectures(spec)) {
1220 /* It is the main package */
1221 if (pkg == spec->packages) {
1222 fillOutMainPackage(pkg->header);
1223 /* Define group tag to something when group is undefined in main package*/
1224 if (!headerIsEntry(pkg->header, RPMTAG_GROUP)) {
1225 headerPutString(pkg->header, RPMTAG_GROUP, "Unspecified");
1229 if (checkForDuplicates(pkg->header, NVR)) {
1233 if (pkg != spec->packages) {
1234 copyInheritedTags(pkg->header, spec->packages->header);
1237 if (checkForRequired(pkg->header, NVR)) {
1241 /* if we get down here nextPart has been set to non-error */