1 /** \ingroup rpmbuild
2  * \file build/parsePreamble.c
3  *  Parse tags in global section from spec file.
4  */
5 
6 #include "system.h"
7 
8 #include <ctype.h>
9 #include <errno.h>
10 
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"
18 #include "debug.h"
19 
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)++;}
24 
25 /**
26  */
27 static const rpmTagVal copyTagsDuringParse[] = {
28     RPMTAG_EPOCH,
29     RPMTAG_VERSION,
30     RPMTAG_RELEASE,
31     RPMTAG_LICENSE,
32     RPMTAG_PACKAGER,
33     RPMTAG_DISTRIBUTION,
34     RPMTAG_DISTURL,
35     RPMTAG_VENDOR,
36     RPMTAG_ICON,
37     RPMTAG_URL,
38     RPMTAG_VCS,
39     RPMTAG_CHANGELOGTIME,
40     RPMTAG_CHANGELOGNAME,
41     RPMTAG_CHANGELOGTEXT,
42     RPMTAG_PREFIXES,
43     RPMTAG_DISTTAG,
44     RPMTAG_BUGURL,
45     RPMTAG_GROUP,
46     RPMTAG_MODULARITYLABEL,
47     0
48 };
49 
50 /**
51  */
52 static const rpmTagVal requiredTags[] = {
53     RPMTAG_NAME,
54     RPMTAG_VERSION,
55     RPMTAG_RELEASE,
56     RPMTAG_SUMMARY,
57     RPMTAG_LICENSE,
58     0
59 };
60 
61 /**
62  */
addOrAppendListEntry(Header h,rpmTagVal tag,const char * line)63 static rpmRC addOrAppendListEntry(Header h, rpmTagVal tag, const char * line)
64 {
65     int xx;
66     int argc;
67     const char **argv;
68 
69     if ((xx = poptParseArgvString(line, &argc, &argv))) {
70 	rpmlog(RPMLOG_ERR, _("Error parsing tag field: %s\n"), poptStrerror(xx));
71 	return RPMRC_FAIL;
72     }
73     if (argc)
74 	headerPutStringArray(h, tag, argv, argc);
75     argv = _free(argv);
76 
77     return RPMRC_OK;
78 }
79 
80 /* Parse a simple part line that only take -n <pkg> or <pkg> */
81 /* <pkg> is returned in name as a pointer into a dynamic buffer */
82 
83 /**
84  */
parseSimplePart(const char * line,char ** name,int * flag)85 static int parseSimplePart(const char *line, char **name, int *flag)
86 {
87     char *tok;
88     char *linebuf = xstrdup(line);
89     int rc;
90 
91     /* Throw away the first token (the %xxxx) */
92     (void)strtok(linebuf, " \t\n");
93     *name = NULL;
94 
95     if (!(tok = strtok(NULL, " \t\n"))) {
96 	rc = 1;
97 	goto exit;
98     }
99 
100     if (rstreq(tok, "-n")) {
101 	if (!(tok = strtok(NULL, " \t\n"))) {
102 	    rc = 1;
103 	    goto exit;
104 	}
105 	*flag = PART_NAME;
106     } else {
107 	*flag = PART_SUBNAME;
108     }
109     *name = xstrdup(tok);
110     rc = strtok(NULL, " \t\n") ? 1 : 0;
111 
112 exit:
113     free(linebuf);
114     return rc;
115 }
116 
117 /**
118  */
parseYesNo(const char * s)119 static inline int parseYesNo(const char * s)
120 {
121     return ((!s || (s[0] == 'n' || s[0] == 'N' || s[0] == '0') ||
122 	!rstrcasecmp(s, "false") || !rstrcasecmp(s, "off"))
123 	    ? 0 : 1);
124 }
125 
newSource(uint32_t num,const char * path,int flags)126 static struct Source *newSource(uint32_t num, const char *path, int flags)
127 {
128     struct Source *p = xmalloc(sizeof(*p));
129     p->num = num;
130     p->fullSource = xstrdup(path);
131     p->flags = flags;
132     p->source = strrchr(p->fullSource, '/');
133     if (p->source) {
134 	const char *buf = strrchr(p->source,'=');
135 	if (buf)
136 	    p->source = buf;
137 	p->source++;
138     } else {
139 	p->source = p->fullSource;
140     }
141     p->path = rpmGetPath("%{_sourcedir}/", p->source, NULL);
142     return p;
143 }
144 
findSource(rpmSpec spec,uint32_t num,int flag)145 struct Source *findSource(rpmSpec spec, uint32_t num, int flag)
146 {
147     struct Source *p;
148 
149     for (p = spec->sources; p != NULL; p = p->next)
150 	if ((num == p->num) && (p->flags & flag)) return p;
151 
152     return NULL;
153 }
154 
parseNoSource(rpmSpec spec,const char * field,rpmTagVal tag)155 static int parseNoSource(rpmSpec spec, const char * field, rpmTagVal tag)
156 {
157     const char *f, *fe;
158     const char *name;
159     int flag;
160     uint32_t num;
161 
162     if (tag == RPMTAG_NOSOURCE) {
163 	flag = RPMBUILD_ISSOURCE;
164 	name = "source";
165     } else {
166 	flag = RPMBUILD_ISPATCH;
167 	name = "patch";
168     }
169 
170     fe = field;
171     for (f = fe; *f != '\0'; f = fe) {
172         struct Source *p;
173 
174 	SKIPWHITE(f);
175 	if (*f == '\0')
176 	    break;
177 	fe = f;
178 	SKIPNONWHITE(fe);
179 	if (*fe != '\0') fe++;
180 
181 	if (parseUnsignedNum(f, &num)) {
182 	    rpmlog(RPMLOG_ERR, _("line %d: Bad number: %s\n"),
183 		     spec->lineNum, f);
184 	    return RPMRC_FAIL;
185 	}
186 
187 	if (! (p = findSource(spec, num, flag))) {
188 	    rpmlog(RPMLOG_ERR, _("line %d: Bad no%s number: %u\n"),
189 		     spec->lineNum, name, num);
190 	    return RPMRC_FAIL;
191 	}
192 
193 	p->flags |= RPMBUILD_ISNO;
194 
195     }
196 
197     return 0;
198 }
199 
addLuaSource(const struct Source * p)200 static void addLuaSource(const struct Source *p)
201 {
202 #ifdef WITH_LUA
203     rpmlua lua = NULL; /* global state */
204     const char * what = (p->flags & RPMBUILD_ISPATCH) ? "patches" : "sources";
205     rpmluaPushTable(lua, what);
206     rpmluav var = rpmluavNew();
207     rpmluavSetListMode(var, 1);
208     rpmluavSetValue(var, RPMLUAV_STRING, p->path);
209     rpmluaSetVar(lua, var);
210     rpmluavFree(var);
211     rpmluaPop(lua);
212 
213     what = (p->flags & RPMBUILD_ISPATCH) ? "patch_nums" : "source_nums";
214     rpmluaPushTable(lua, what);
215     var = rpmluavNew();
216     rpmluavSetListMode(var, 1);
217     rpmluavSetValueNum(var, p->num);
218     rpmluaSetVar(lua, var);
219     rpmluavFree(var);
220     rpmluaPop(lua);
221 #endif
222 }
223 
tryDownload(const struct Source * p)224 static int tryDownload(const struct Source *p)
225 {
226     int rc = 0;
227     struct stat st;
228 
229     /* try to download source/patch if it's missing */
230     if (lstat(p->path, &st) != 0 && errno == ENOENT) {
231 	char *url = NULL;
232 	if (urlIsURL(p->fullSource) != URL_IS_UNKNOWN) {
233 	    url = rstrdup(p->fullSource);
234 	} else {
235 	    url = rpmExpand("%{_default_source_url}", NULL);
236 	    rstrcat(&url, p->source);
237 	    if (*url == '%') url = _free(url);
238 	}
239 	if (url) {
240 	    rpmlog(RPMLOG_WARNING, _("Downloading %s to %s\n"), url, p->path);
241 	    if (urlGetFile(url, p->path) != 0) {
242 		rpmlog(RPMLOG_ERR, _("Couldn't download %s\n"), p->fullSource);
243 		rc = -1;
244 	    }
245 	}
246 	free(url);
247     }
248     return rc;
249 }
250 
251 /*
252  * Parse an option number of a tag, such as in sources and patches.
253  * Return -1 on error, 0 if number present and 1 if no number found.
254  */
parseTagNumber(const char * line,uint32_t * snum)255 static int parseTagNumber(const char *line, uint32_t *snum)
256 {
257     int rc = 0;
258     char *l = xstrdup(line);
259     char *fieldp = l;
260     char *nump = l;
261 
262     /* We already know that a ':' exists, and that there */
263     /* are no spaces before it.                          */
264     /* This also now allows for spaces and tabs between  */
265     /* the number and the ':'                            */
266     while ((*fieldp != ':') && (*fieldp != ' ') && (*fieldp != '\t')) {
267 	fieldp++;
268     }
269     *fieldp = '\0';
270 
271     SKIPSPACE(nump);
272     if (nump == NULL || *nump == '\0') {
273 	rc = 1;
274     } else {
275 	rc = parseUnsignedNum(l, snum);
276     }
277     free(l);
278     return rc;
279 }
280 
addSource(rpmSpec spec,int specline,const char * srcname,rpmTagVal tag)281 int addSource(rpmSpec spec, int specline, const char *srcname, rpmTagVal tag)
282 {
283     struct Source *p;
284     int flag = 0;
285     int nonum = 1; /* assume autonumbering */
286     const char *name = NULL;
287     char *buf = NULL;
288     uint32_t num = 0;
289     int *autonum = NULL;
290     int nofetch = (spec->flags & RPMSPEC_FORCE) ||
291 		      rpmExpandNumeric("%{_disable_source_fetch}");
292 
293     switch (tag) {
294       case RPMTAG_SOURCE:
295 	flag = RPMBUILD_ISSOURCE;
296 	name = "source";
297 	autonum = &spec->autonum_source;
298 	break;
299       case RPMTAG_PATCH:
300 	flag = RPMBUILD_ISPATCH;
301 	name = "patch";
302 	autonum = &spec->autonum_patch;
303 	break;
304       default:
305 	return -1;
306 	break;
307     }
308 
309     if (specline) {
310 	nonum = parseTagNumber(spec->line + strlen(name), &num);
311 	if (nonum < 0) {
312 	    rpmlog(RPMLOG_ERR, _("line %d: Bad %s number: %s\n"),
313 		     spec->lineNum, name, spec->line);
314 	    return RPMRC_FAIL;
315 	}
316     }
317 
318     if (nonum > 0) {
319 	/* No number specified, use autonumbering */
320 	(*autonum)++;
321 	num = *autonum;
322     } else {
323 	/* Autonumbering continues from last specified number */
324 	if ((int)num > *autonum)
325 	    *autonum = num;
326     }
327 
328     /* Check whether tags of the same number haven't already been defined */
329     if (findSource(spec, num, flag)) {
330 	rpmlog(RPMLOG_ERR, _("%s %d defined multiple times\n"), name, num);
331 	return RPMRC_FAIL;
332     }
333 
334     /* Create the entry and link it in */
335     p = newSource(num, srcname, flag);
336     p->next = spec->sources;
337     spec->sources = p;
338     spec->numSources++;
339 
340     rasprintf(&buf, "%s%d",
341 	    (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
342     rpmPushMacro(spec->macros, buf, NULL, p->path, RMIL_SPEC);
343     free(buf);
344     rasprintf(&buf, "%sURL%d",
345 	    (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
346     rpmPushMacro(spec->macros, buf, NULL, p->fullSource, RMIL_SPEC);
347     free(buf);
348 
349     addLuaSource(p);
350 
351     if (!nofetch && tryDownload(p))
352 	return RPMRC_FAIL;
353 
354     return 0;
355 }
356 
357 typedef const struct tokenBits_s {
358     const char * name;
359     rpmsenseFlags bits;
360 } * tokenBits;
361 
362 /**
363  */
364 static struct tokenBits_s const installScriptBits[] = {
365     { "interp",		RPMSENSE_INTERP },
366     { "meta",		RPMSENSE_META },
367     { "preun",		RPMSENSE_SCRIPT_PREUN },
368     { "pre",		RPMSENSE_SCRIPT_PRE },
369     { "postun",		RPMSENSE_SCRIPT_POSTUN },
370     { "post",		RPMSENSE_SCRIPT_POST },
371     { "rpmlib",		RPMSENSE_RPMLIB },
372     { "verify",		RPMSENSE_SCRIPT_VERIFY },
373     { "pretrans",	RPMSENSE_PRETRANS },
374     { "posttrans",	RPMSENSE_POSTTRANS },
375     { NULL, 0 }
376 };
377 
378 /**
379  */
parseBits(const char * s,const tokenBits tokbits,rpmsenseFlags * bp)380 static int parseBits(const char * s, const tokenBits tokbits,
381 		rpmsenseFlags * bp)
382 {
383     tokenBits tb = NULL;
384     const char * se;
385     rpmsenseFlags bits = RPMSENSE_ANY;
386     int c = 0;
387     int rc = RPMRC_OK;
388 
389     if (s) {
390 	for (;;) {
391 	    while ((c = *s) && risspace(c)) s++;
392 	    se = s;
393 	    while ((c = *se) && risalpha(c)) se++;
394 	    if (s == se) {
395 		if (c || tb)
396 		    rc = RPMRC_FAIL;
397 		break;
398 	    }
399 	    for (tb = tokbits; tb->name; tb++) {
400 		if (tb->name != NULL &&
401 		    strlen(tb->name) == (se-s) && rstreqn(tb->name, s, (se-s)))
402 		    break;
403 	    }
404 	    if (tb->name == NULL) {
405 		rc = RPMRC_FAIL;
406 		break;
407 	    }
408 	    bits |= tb->bits;
409 	    while ((c = *se) && risspace(c)) se++;
410 	    if (c != ',') {
411 		if (c)
412 		    rc = RPMRC_FAIL;
413 		break;
414 	    }
415 	    s = ++se;
416 	}
417     }
418     *bp |= bits;
419     return rc;
420 }
421 
422 /**
423  */
findLastChar(char * s)424 static inline char * findLastChar(char * s)
425 {
426     char *res = s;
427 
428     while (*s != '\0') {
429 	if (! risspace(*s))
430 	    res = s;
431 	s++;
432     }
433 
434     return res;
435 }
436 
437 /**
438  */
isMemberInEntry(Header h,const char * name,rpmTagVal tag)439 static int isMemberInEntry(Header h, const char *name, rpmTagVal tag)
440 {
441     struct rpmtd_s td;
442     int found = 0;
443     const char *str;
444 
445     if (!headerGet(h, tag, &td, HEADERGET_MINMEM))
446 	return -1;
447 
448     while ((str = rpmtdNextString(&td))) {
449 	if (!rstrcasecmp(str, name)) {
450 	    found = 1;
451 	    break;
452 	}
453     }
454     rpmtdFreeData(&td);
455 
456     return found;
457 }
458 
459 /**
460  */
checkForValidArchitectures(rpmSpec spec)461 static rpmRC checkForValidArchitectures(rpmSpec spec)
462 {
463     char *arch = rpmExpand("%{_target_cpu}", NULL);
464     char *os = rpmExpand("%{_target_os}", NULL);
465     rpmRC rc = RPMRC_FAIL; /* assume failure */
466 
467     if (!strcmp(arch, "noarch")) {
468 	free(arch);
469 	arch = rpmExpand("%{_build_cpu}", NULL);
470     }
471 
472     if (isMemberInEntry(spec->buildRestrictions,
473 			arch, RPMTAG_EXCLUDEARCH) == 1) {
474 	rpmlog(RPMLOG_ERR, _("Architecture is excluded: %s\n"), arch);
475 	goto exit;
476     }
477     if (isMemberInEntry(spec->buildRestrictions,
478 			arch, RPMTAG_EXCLUSIVEARCH) == 0) {
479 	rpmlog(RPMLOG_ERR, _("Architecture is not included: %s\n"), arch);
480 	goto exit;
481     }
482     if (isMemberInEntry(spec->buildRestrictions,
483 			os, RPMTAG_EXCLUDEOS) == 1) {
484 	rpmlog(RPMLOG_ERR, _("OS is excluded: %s\n"), os);
485 	goto exit;
486     }
487     if (isMemberInEntry(spec->buildRestrictions,
488 			os, RPMTAG_EXCLUSIVEOS) == 0) {
489 	rpmlog(RPMLOG_ERR, _("OS is not included: %s\n"), os);
490 	goto exit;
491     }
492     rc = RPMRC_OK;
493 
494 exit:
495     free(arch);
496     free(os);
497 
498     return rc;
499 }
500 
501 /**
502  * Check that required tags are present in header.
503  * @param h		header
504  * @param NVR		package name-version-release
505  * @return		RPMRC_OK if OK
506  */
checkForRequired(Header h,const char * NVR)507 static int checkForRequired(Header h, const char * NVR)
508 {
509     int res = RPMRC_OK;
510     const rpmTagVal * p;
511 
512     for (p = requiredTags; *p != 0; p++) {
513 	if (!headerIsEntry(h, *p)) {
514 	    rpmlog(RPMLOG_ERR,
515 			_("%s field must be present in package: %s\n"),
516 			rpmTagGetName(*p), NVR);
517 	    res = RPMRC_FAIL;
518 	}
519     }
520 
521     return res;
522 }
523 
524 /**
525  * Check that no duplicate tags are present in header.
526  * @param h		header
527  * @param NVR		package name-version-release
528  * @return		RPMRC_OK if OK
529  */
checkForDuplicates(Header h,const char * NVR)530 static int checkForDuplicates(Header h, const char * NVR)
531 {
532     int res = RPMRC_OK;
533     rpmTagVal tag, lastTag = RPMTAG_NOT_FOUND;
534     HeaderIterator hi = headerInitIterator(h);
535 
536     while ((tag = headerNextTag(hi)) != RPMTAG_NOT_FOUND) {
537 	if (tag == lastTag) {
538 	    rpmlog(RPMLOG_ERR, _("Duplicate %s entries in package: %s\n"),
539 		     rpmTagGetName(tag), NVR);
540 	    res = RPMRC_FAIL;
541 	}
542 	lastTag = tag;
543     }
544     headerFreeIterator(hi);
545 
546     return res;
547 }
548 
549 /**
550  */
551 static struct optionalTag {
552     rpmTagVal	ot_tag;
553     const char * ot_mac;
554 } const optionalTags[] = {
555     { RPMTAG_VENDOR,		"%{vendor}" },
556     { RPMTAG_PACKAGER,		"%{packager}" },
557     { RPMTAG_DISTRIBUTION,	"%{distribution}" },
558     { RPMTAG_DISTURL,		"%{disturl}" },
559     { RPMTAG_DISTTAG,		"%{disttag}" },
560     { RPMTAG_BUGURL,		"%{bugurl}" },
561     { RPMTAG_MODULARITYLABEL,	"%{modularitylabel}"},
562     { -1, NULL }
563 };
564 
565 /**
566  */
fillOutMainPackage(Header h)567 static void fillOutMainPackage(Header h)
568 {
569     const struct optionalTag *ot;
570 
571     for (ot = optionalTags; ot->ot_mac != NULL; ot++) {
572 	if (!headerIsEntry(h, ot->ot_tag)) {
573 	    char *val = rpmExpand(ot->ot_mac, NULL);
574 	    if (val && *val != '%') {
575 		headerPutString(h, ot->ot_tag, val);
576 	    }
577 	    free(val);
578 	}
579     }
580 }
581 
582 /**
583  */
copyInheritedTags(Header h,Header fromh)584 void copyInheritedTags(Header h, Header fromh)
585 {
586     headerCopyTags(fromh, h, (rpmTagVal *)copyTagsDuringParse);
587 }
588 
589 /**
590  */
addIcon(Package pkg,const char * file)591 static rpmRC addIcon(Package pkg, const char * file)
592 {
593     struct Source *p = newSource(0, file, RPMBUILD_ISICON);
594     char *fn = NULL;
595     uint8_t *icon = NULL;
596     FD_t fd = NULL;
597     rpmRC rc = RPMRC_FAIL; /* assume failure */
598     off_t size;
599     size_t nb, iconsize;
600 
601     p->next = pkg->icon;
602     pkg->icon = p;
603 
604     /* XXX use rpmGenPath(rootdir, "%{_sourcedir}/", file) for icon path. */
605     fn = rpmGetPath("%{_sourcedir}/", file, NULL);
606 
607     fd = Fopen(fn, "r.ufdio");
608     if (fd == NULL) {
609 	rpmlog(RPMLOG_ERR, _("Unable to open icon %s: %s\n"),
610 		fn, Fstrerror(fd));
611 	goto exit;
612     }
613     size = fdSize(fd);
614     iconsize = (size >= 0 ? size : (8 * BUFSIZ));
615     if (iconsize == 0) {
616 	rc = RPMRC_OK; /* XXX Eh? */
617 	goto exit;
618     }
619 
620     icon = xmalloc(iconsize + 1);
621     *icon = '\0';
622 
623     nb = Fread(icon, sizeof(icon[0]), iconsize, fd);
624     if (Ferror(fd) || (size >= 0 && nb != size)) {
625 	rpmlog(RPMLOG_ERR, _("Unable to read icon %s: %s\n"),
626 		fn, Fstrerror(fd));
627 	goto exit;
628     }
629 
630     if (rstreqn((char*)icon, "GIF", sizeof("GIF")-1)) {
631 	headerPutBin(pkg->header, RPMTAG_GIF, icon, iconsize);
632     } else if (rstreqn((char*)icon, "/* XPM", sizeof("/* XPM")-1)) {
633 	headerPutBin(pkg->header, RPMTAG_XPM, icon, iconsize);
634     } else {
635 	rpmlog(RPMLOG_ERR, _("Unknown icon type: %s\n"), file);
636 	goto exit;
637     }
638     rc = RPMRC_OK;
639 
640 exit:
641     Fclose(fd);
642     free(fn);
643     free(icon);
644     return rc;
645 }
646 
647 #define SINGLE_TOKEN_ONLY \
648 if (multiToken) { \
649     rpmlog(RPMLOG_ERR, _("line %d: Tag takes single token only: %s\n"), \
650 	     spec->lineNum, spec->line); \
651     return RPMRC_FAIL; \
652 }
653 
specLog(rpmSpec spec,int lvl,const char * line,const char * msg)654 static void specLog(rpmSpec spec, int lvl, const char *line, const char *msg)
655 {
656     if (spec) {
657 	rpmlog(lvl, _("line %d: %s in: %s\n"), spec->lineNum, msg, spec->line);
658     } else {
659 	rpmlog(lvl, _("%s in: %s\n"), msg, line);
660     }
661 }
662 
663 /**
664  * Check for inappropriate characters. All alphanums are considered sane.
665  * @param spec		spec (or NULL)
666  * @param field		string to check
667  * @param whitelist	string of permitted characters
668  * @return		RPMRC_OK if OK
669  */
rpmCharCheck(rpmSpec spec,const char * field,const char * whitelist)670 rpmRC rpmCharCheck(rpmSpec spec, const char *field, const char *whitelist)
671 {
672     const char *ch;
673     char *err = NULL;
674     rpmRC rc = RPMRC_OK;
675 
676     for (ch=field; *ch; ch++) {
677 	if (risalnum(*ch) || strchr(whitelist, *ch)) continue;
678 	rasprintf(&err, _("Illegal char '%c' (0x%x)"),
679 		  isprint(*ch) ? *ch : '?', *ch);
680     }
681     for (ch=field; *ch; ch++) {
682 	if (strchr("%{}", *ch)) {
683 	    specLog(spec, RPMLOG_WARNING, field,
684 		    _("Possible unexpanded macro"));
685 	    break;
686 	}
687     }
688 
689     if (err == NULL && strstr(field, "..") != NULL) {
690 	rasprintf(&err, _("Illegal sequence \"..\""));
691     }
692 
693     if (err) {
694 	specLog(spec, RPMLOG_ERR, field, err);
695 	free(err);
696 	rc = RPMRC_FAIL;
697     }
698     return rc;
699 }
700 
haveLangTag(Header h,rpmTagVal tag,const char * lang)701 static int haveLangTag(Header h, rpmTagVal tag, const char *lang)
702 {
703     int rc = 0;	/* assume tag not present */
704     int langNum = -1;
705 
706     if (lang && *lang) {
707 	/* See if the language is in header i18n table */
708 	struct rpmtd_s langtd;
709 	const char *s = NULL;
710 	headerGet(h, RPMTAG_HEADERI18NTABLE, &langtd, HEADERGET_MINMEM);
711 	while ((s = rpmtdNextString(&langtd)) != NULL) {
712 	    if (rstreq(s, lang)) {
713 		langNum = rpmtdGetIndex(&langtd);
714 		break;
715 	    }
716 	}
717 	rpmtdFreeData(&langtd);
718     } else {
719 	/* C locale */
720 	langNum = 0;
721     }
722 
723     /* If locale is present, check the actual tag content */
724     if (langNum >= 0) {
725 	struct rpmtd_s td;
726 	headerGet(h, tag, &td, HEADERGET_MINMEM|HEADERGET_RAW);
727 	if (rpmtdSetIndex(&td, langNum) == langNum) {
728 	    const char *s = rpmtdGetString(&td);
729 	    /* non-empty string means a dupe */
730 	    if (s && *s)
731 		rc = 1;
732 	}
733 	rpmtdFreeData(&td);
734     };
735 
736     return rc;
737 }
738 
addLangTag(rpmSpec spec,Header h,rpmTagVal tag,const char * field,const char * lang)739 int addLangTag(rpmSpec spec, Header h, rpmTagVal tag,
740 		      const char *field, const char *lang)
741 {
742     int skip = 0;
743 
744     if (haveLangTag(h, tag, lang)) {
745 	/* Turn this into an error eventually */
746 	rpmlog(RPMLOG_WARNING, _("line %d: second %s\n"),
747 		spec->lineNum, rpmTagGetName(tag));
748     }
749 
750     if (!*lang) {
751 	headerPutString(h, tag, field);
752     } else {
753     	skip = ((spec->flags & RPMSPEC_NOLANG) &&
754 		!rstreq(lang, RPMBUILD_DEFAULT_LANG));
755 	if (skip)
756 	    return 0;
757 	headerAddI18NString(h, tag, field, lang);
758     }
759 
760     return 0;
761 }
762 
handlePreambleTag(rpmSpec spec,Package pkg,rpmTagVal tag,const char * macro,const char * lang)763 static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag,
764 		const char *macro, const char *lang)
765 {
766     char * field = spec->line;
767     char * end;
768     int multiToken = 0;
769     rpmsenseFlags tagflags = RPMSENSE_ANY;
770     rpmRC rc = RPMRC_FAIL;
771 
772     if (field == NULL) /* XXX can't happen */
773 	goto exit;
774     /* Find the start of the "field" and strip trailing space */
775     while ((*field) && (*field != ':'))
776 	field++;
777     if (*field != ':') {
778 	rpmlog(RPMLOG_ERR, _("line %d: Malformed tag: %s\n"),
779 		 spec->lineNum, spec->line);
780 	goto exit;
781     }
782     field++;
783     SKIPSPACE(field);
784     if (!*field) {
785 	/* Empty field */
786 	rpmlog(RPMLOG_ERR, _("line %d: Empty tag: %s\n"),
787 		 spec->lineNum, spec->line);
788 	goto exit;
789     }
790     end = findLastChar(field);
791     *(end+1) = '\0';
792 
793     /* See if this is multi-token */
794     end = field;
795     SKIPNONSPACE(end);
796     if (*end != '\0')
797 	multiToken = 1;
798 
799     switch (tag) {
800     case RPMTAG_NAME:
801 	SINGLE_TOKEN_ONLY;
802 	if (rpmCharCheck(spec, field, WHITELIST_NAME))
803 	   goto exit;
804 	headerPutString(pkg->header, tag, field);
805 	/* Main pkg name is unknown at the start, populate as soon as we can */
806 	if (pkg == spec->packages)
807 	    pkg->name = rpmstrPoolId(spec->pool, field, 1);
808 	break;
809     case RPMTAG_VERSION:
810     case RPMTAG_RELEASE:
811 	SINGLE_TOKEN_ONLY;
812 	if (rpmCharCheck(spec, field, WHITELIST_VERREL))
813 	   goto exit;
814 	headerPutString(pkg->header, tag, field);
815 	break;
816     case RPMTAG_URL:
817     case RPMTAG_DISTTAG:
818     case RPMTAG_BUGURL:
819     case RPMTAG_MODULARITYLABEL:
820     /* XXX TODO: validate format somehow */
821     case RPMTAG_VCS:
822 	SINGLE_TOKEN_ONLY;
823 	headerPutString(pkg->header, tag, field);
824 	break;
825     case RPMTAG_GROUP:
826     case RPMTAG_SUMMARY:
827     case RPMTAG_DISTRIBUTION:
828     case RPMTAG_VENDOR:
829     case RPMTAG_LICENSE:
830     case RPMTAG_PACKAGER:
831 	if (addLangTag(spec, pkg->header, tag, field, lang))
832 	    goto exit;
833 	break;
834     case RPMTAG_BUILDROOT:
835 	/* just silently ignore BuildRoot */
836 	break;
837     case RPMTAG_PREFIXES: {
838 	struct rpmtd_s td;
839 	const char *str;
840 	if (addOrAppendListEntry(pkg->header, tag, field))
841 	   goto exit;
842 	headerGet(pkg->header, tag, &td, HEADERGET_MINMEM);
843 	while ((str = rpmtdNextString(&td))) {
844 	    size_t len = strlen(str);
845 	    if (len > 1 && str[len-1] == '/') {
846 		rpmlog(RPMLOG_ERR,
847 			 _("line %d: Prefixes must not end with \"/\": %s\n"),
848 			 spec->lineNum, spec->line);
849 		rpmtdFreeData(&td);
850 		goto exit;
851 	    }
852 	}
853 	rpmtdFreeData(&td);
854 	break;
855     }
856     case RPMTAG_DOCDIR:
857 	SINGLE_TOKEN_ONLY;
858 	if (field[0] != '/') {
859 	    rpmlog(RPMLOG_ERR, _("line %d: Docdir must begin with '/': %s\n"),
860 		     spec->lineNum, spec->line);
861 	    goto exit;
862 	}
863 	rpmPopMacro(NULL, "_docdir");
864 	rpmPushMacro(NULL, "_docdir", NULL, field, RMIL_SPEC);
865 	break;
866     case RPMTAG_EPOCH: {
867 	SINGLE_TOKEN_ONLY;
868 	uint32_t epoch;
869 	if (parseUnsignedNum(field, &epoch)) {
870 	    rpmlog(RPMLOG_ERR,
871 		   _("line %d: Epoch field must be an unsigned number: %s\n"),
872 		   spec->lineNum, spec->line);
873 	    goto exit;
874 	}
875 	headerPutUint32(pkg->header, tag, &epoch, 1);
876 	break;
877     }
878     case RPMTAG_AUTOREQPROV:
879 	pkg->autoReq = parseYesNo(field);
880 	pkg->autoProv = pkg->autoReq;
881 	break;
882     case RPMTAG_AUTOREQ:
883 	pkg->autoReq = parseYesNo(field);
884 	break;
885     case RPMTAG_AUTOPROV:
886 	pkg->autoProv = parseYesNo(field);
887 	break;
888     case RPMTAG_SOURCE:
889     case RPMTAG_PATCH:
890 	if (addSource(spec, 1, field, tag))
891 	    goto exit;
892 	break;
893     case RPMTAG_ICON:
894 	SINGLE_TOKEN_ONLY;
895 	if (addIcon(pkg, field))
896 	    goto exit;
897 	spec->numSources++;
898 	break;
899     case RPMTAG_NOSOURCE:
900     case RPMTAG_NOPATCH:
901 	spec->noSource = 1;
902 	if (parseNoSource(spec, field, tag))
903 	    goto exit;
904 	break;
905     case RPMTAG_ORDERNAME:
906     case RPMTAG_REQUIRENAME:
907 	if (parseBits(lang, installScriptBits, &tagflags)) {
908 	    rpmlog(RPMLOG_ERR, _("line %d: Bad %s: qualifiers: %s\n"),
909 		     spec->lineNum, rpmTagGetName(tag), spec->line);
910 	    goto exit;
911 	}
912 	/* fallthrough */
913     case RPMTAG_PREREQ:
914     case RPMTAG_RECOMMENDNAME:
915     case RPMTAG_SUGGESTNAME:
916     case RPMTAG_SUPPLEMENTNAME:
917     case RPMTAG_ENHANCENAME:
918     case RPMTAG_CONFLICTNAME:
919     case RPMTAG_OBSOLETENAME:
920     case RPMTAG_PROVIDENAME:
921 	if (parseRCPOT(spec, pkg, field, tag, 0, tagflags, addReqProvPkg, NULL))
922 	    goto exit;
923 	break;
924     case RPMTAG_BUILDPREREQ:
925     case RPMTAG_BUILDREQUIRES:
926     case RPMTAG_BUILDCONFLICTS:
927 	if (parseRCPOT(spec, spec->sourcePackage, field, tag, 0, tagflags, addReqProvPkg, NULL))
928 	    goto exit;
929 	break;
930     case RPMTAG_EXCLUDEARCH:
931     case RPMTAG_EXCLUSIVEARCH:
932     case RPMTAG_EXCLUDEOS:
933     case RPMTAG_EXCLUSIVEOS:
934 	if (addOrAppendListEntry(spec->buildRestrictions, tag, field))
935 	   goto exit;
936 	break;
937     case RPMTAG_BUILDARCHS: {
938 	int BACount;
939 	const char **BANames = NULL;
940 	if (poptParseArgvString(field, &BACount, &BANames)) {
941 	    rpmlog(RPMLOG_ERR,
942 		     _("line %d: Bad BuildArchitecture format: %s\n"),
943 		     spec->lineNum, spec->line);
944 	    goto exit;
945 	}
946 	if (spec->packages == pkg) {
947 	    if (spec->BANames) {
948 		rpmlog(RPMLOG_ERR,
949 		       _("line %d: Duplicate BuildArch entry: %s\n"),
950 		       spec->lineNum, spec->line);
951 		BANames = _free(BANames);
952 		goto exit;
953 	    }
954 	    spec->BACount = BACount;
955 	    spec->BANames = BANames;
956 	} else {
957 	    if (BACount != 1 || !rstreq(BANames[0], "noarch")) {
958 		rpmlog(RPMLOG_ERR,
959 		     _("line %d: Only noarch subpackages are supported: %s\n"),
960 		     spec->lineNum, spec->line);
961 		BANames = _free(BANames);
962 		goto exit;
963 	    }
964 	    headerPutString(pkg->header, RPMTAG_ARCH, "noarch");
965 	}
966 	if (!BACount)
967 	    spec->BANames = _free(spec->BANames);
968 	break;
969     }
970     case RPMTAG_REMOVEPATHPOSTFIXES:
971 	argvSplit(&pkg->removePostfixes, field, ":");
972 	break;
973     default:
974 	rpmlog(RPMLOG_ERR, _("Internal error: Bogus tag %d\n"), tag);
975 	goto exit;
976     }
977 
978     if (macro) {
979 	rpmPushMacro(spec->macros, macro, NULL, field, RMIL_SPEC);
980 	/* Add a separate uppercase macro for tags from the main package */
981 	if (pkg == spec->packages) {
982 	    char *m = xstrdup(macro);
983 	    for (char *p = m; *p; ++p)
984 		*p = rtoupper(*p);
985 	    rpmPushMacro(spec->macros, m, NULL, field, RMIL_SPEC);
986 	    free(m);
987 	}
988     }
989     rc = RPMRC_OK;
990 exit:
991     return rc;
992 }
993 
994 /* This table has to be in a peculiar order.  If one tag is the */
995 /* same as another, plus a few letters, it must come first.     */
996 
997 /**
998  */
999 typedef const struct PreambleRec_s {
1000     rpmTagVal tag;
1001     int type;
1002     int deprecated;
1003     int ismacro;
1004     size_t len;
1005     const char * token;
1006 } * PreambleRec;
1007 
1008 static struct PreambleRec_s const preambleList[] = {
1009     {RPMTAG_NAME,		0, 0, 1, LEN_AND_STR("name")},
1010     {RPMTAG_VERSION,		0, 0, 1, LEN_AND_STR("version")},
1011     {RPMTAG_RELEASE,		0, 0, 1, LEN_AND_STR("release")},
1012     {RPMTAG_EPOCH,		0, 0, 1, LEN_AND_STR("epoch")},
1013     {RPMTAG_SUMMARY,		1, 0, 1, LEN_AND_STR("summary")},
1014     {RPMTAG_LICENSE,		0, 0, 1, LEN_AND_STR("license")},
1015     {RPMTAG_DISTRIBUTION,	0, 0, 1, LEN_AND_STR("distribution")},
1016     {RPMTAG_DISTURL,		0, 0, 1, LEN_AND_STR("disturl")},
1017     {RPMTAG_VENDOR,		0, 0, 1, LEN_AND_STR("vendor")},
1018     {RPMTAG_GROUP,		1, 0, 1, LEN_AND_STR("group")},
1019     {RPMTAG_PACKAGER,		0, 0, 1, LEN_AND_STR("packager")},
1020     {RPMTAG_URL,		0, 0, 1, LEN_AND_STR("url")},
1021     {RPMTAG_VCS,		0, 0, 1, LEN_AND_STR("vcs")},
1022     {RPMTAG_SOURCE,		0, 0, 0, LEN_AND_STR("source")},
1023     {RPMTAG_PATCH,		0, 0, 0, LEN_AND_STR("patch")},
1024     {RPMTAG_NOSOURCE,		0, 0, 0, LEN_AND_STR("nosource")},
1025     {RPMTAG_NOPATCH,		0, 0, 0, LEN_AND_STR("nopatch")},
1026     {RPMTAG_EXCLUDEARCH,	0, 0, 0, LEN_AND_STR("excludearch")},
1027     {RPMTAG_EXCLUSIVEARCH,	0, 0, 0, LEN_AND_STR("exclusivearch")},
1028     {RPMTAG_EXCLUDEOS,		0, 0, 0, LEN_AND_STR("excludeos")},
1029     {RPMTAG_EXCLUSIVEOS,	0, 0, 0, LEN_AND_STR("exclusiveos")},
1030     {RPMTAG_ICON,		0, 0, 0, LEN_AND_STR("icon")},
1031     {RPMTAG_PROVIDENAME,	0, 0, 0, LEN_AND_STR("provides")},
1032     {RPMTAG_REQUIRENAME,	2, 0, 0, LEN_AND_STR("requires")},
1033     {RPMTAG_RECOMMENDNAME,	0, 0, 0, LEN_AND_STR("recommends")},
1034     {RPMTAG_SUGGESTNAME,	0, 0, 0, LEN_AND_STR("suggests")},
1035     {RPMTAG_SUPPLEMENTNAME,	0, 0, 0, LEN_AND_STR("supplements")},
1036     {RPMTAG_ENHANCENAME,	0, 0, 0, LEN_AND_STR("enhances")},
1037     {RPMTAG_PREREQ,		2, 1, 0, LEN_AND_STR("prereq")},
1038     {RPMTAG_CONFLICTNAME,	0, 0, 0, LEN_AND_STR("conflicts")},
1039     {RPMTAG_OBSOLETENAME,	0, 0, 0, LEN_AND_STR("obsoletes")},
1040     {RPMTAG_PREFIXES,		0, 0, 1, LEN_AND_STR("prefixes")},
1041     {RPMTAG_PREFIXES,		0, 0, 1, LEN_AND_STR("prefix")},
1042     {RPMTAG_BUILDROOT,		0, 0, 0, LEN_AND_STR("buildroot")},
1043     {RPMTAG_BUILDARCHS,		0, 0, 0, LEN_AND_STR("buildarchitectures")},
1044     {RPMTAG_BUILDARCHS,		0, 0, 0, LEN_AND_STR("buildarch")},
1045     {RPMTAG_BUILDCONFLICTS,	0, 0, 0, LEN_AND_STR("buildconflicts")},
1046     {RPMTAG_BUILDPREREQ,	0, 1, 0, LEN_AND_STR("buildprereq")},
1047     {RPMTAG_BUILDREQUIRES,	0, 0, 0, LEN_AND_STR("buildrequires")},
1048     {RPMTAG_AUTOREQPROV,	0, 0, 0, LEN_AND_STR("autoreqprov")},
1049     {RPMTAG_AUTOREQ,		0, 0, 0, LEN_AND_STR("autoreq")},
1050     {RPMTAG_AUTOPROV,		0, 0, 0, LEN_AND_STR("autoprov")},
1051     {RPMTAG_DOCDIR,		0, 0, 0, LEN_AND_STR("docdir")},
1052     {RPMTAG_DISTTAG,		0, 0, 1, LEN_AND_STR("disttag")},
1053     {RPMTAG_BUGURL,		0, 0, 1, LEN_AND_STR("bugurl")},
1054     {RPMTAG_ORDERNAME,		2, 0, 0, LEN_AND_STR("orderwithrequires")},
1055     {RPMTAG_REMOVEPATHPOSTFIXES,0, 0, 1, LEN_AND_STR("removepathpostfixes")},
1056     {RPMTAG_MODULARITYLABEL,	0, 0, 1, LEN_AND_STR("modularitylabel")},
1057     {0, 0, 0, 0}
1058 };
1059 
1060 /**
1061  */
findPreambleTag(rpmSpec spec,rpmTagVal * tag,const char ** macro,char * lang)1062 static int findPreambleTag(rpmSpec spec,rpmTagVal * tag,
1063 		const char ** macro, char * lang)
1064 {
1065     PreambleRec p;
1066     char *s;
1067 
1068     for (p = preambleList; p->token != NULL; p++) {
1069 	if (!(p->token && !rstrncasecmp(spec->line, p->token, p->len)))
1070 	    continue;
1071 	if (p->deprecated) {
1072 	    rpmlog(RPMLOG_WARNING, _("line %d: %s is deprecated: %s\n"),
1073 			spec->lineNum, p->token, spec->line);
1074 	}
1075 	break;
1076     }
1077     if (p == NULL || p->token == NULL)
1078 	return 1;
1079 
1080     s = spec->line + p->len;
1081     SKIPSPACE(s);
1082 
1083     switch (p->type) {
1084     default:
1085     case 0:
1086 	/* Unless this is a source or a patch, a ':' better be next */
1087 	if (p->tag != RPMTAG_SOURCE && p->tag != RPMTAG_PATCH) {
1088 	    if (*s != ':') return 1;
1089 	}
1090 	*lang = '\0';
1091 	break;
1092     case 1:	/* Parse optional ( <token> ). */
1093     case 2:
1094 	if (*s == ':') {
1095 	    /* Type 1 is multilang, 2 is qualifiers with no defaults */
1096 	    strcpy(lang, (p->type == 1) ? RPMBUILD_DEFAULT_LANG : "");
1097 	    break;
1098 	}
1099 	if (*s != '(') return 1;
1100 	s++;
1101 	SKIPSPACE(s);
1102 	while (!risspace(*s) && *s != ')')
1103 	    *lang++ = *s++;
1104 	*lang = '\0';
1105 	SKIPSPACE(s);
1106 	if (*s != ')') return 1;
1107 	s++;
1108 	SKIPSPACE(s);
1109 	if (*s != ':') return 1;
1110 	break;
1111     }
1112 
1113     *tag = p->tag;
1114     *macro = p->ismacro ? p->token : NULL;
1115     return 0;
1116 }
1117 
parsePreamble(rpmSpec spec,int initialPackage)1118 int parsePreamble(rpmSpec spec, int initialPackage)
1119 {
1120     int nextPart = PART_ERROR;
1121     int res = PART_ERROR; /* assume failure */
1122     int rc;
1123     char *linep;
1124     int flag = 0;
1125     Package pkg;
1126     char *name = NULL;
1127     char *NVR = NULL;
1128     char lang[BUFSIZ];
1129 
1130     if (! initialPackage) {
1131 	/* There is one option to %package: <pkg> or -n <pkg> */
1132 	if (parseSimplePart(spec->line, &name, &flag)) {
1133 	    rpmlog(RPMLOG_ERR, _("Bad package specification: %s\n"),
1134 			spec->line);
1135 	    goto exit;
1136 	}
1137 
1138 	if (rpmCharCheck(spec, name, WHITELIST_NAME))
1139 	    goto exit;
1140 
1141 	if (!lookupPackage(spec, name, flag, NULL))
1142 	    goto exit;
1143 
1144 	/* Construct the package */
1145 	if (flag == PART_SUBNAME) {
1146 	    rasprintf(&NVR, "%s-%s",
1147 		    headerGetString(spec->packages->header, RPMTAG_NAME), name);
1148 	} else
1149 	    NVR = xstrdup(name);
1150 	pkg = newPackage(NVR, spec->pool, &spec->packages);
1151 	headerPutString(pkg->header, RPMTAG_NAME, NVR);
1152     } else {
1153 	NVR = xstrdup("(main package)");
1154 	pkg = newPackage(NULL, spec->pool, &spec->packages);
1155 	spec->sourcePackage = newPackage(NULL, spec->pool, NULL);
1156 
1157     }
1158 
1159     if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
1160 	nextPart = PART_NONE;
1161     } else if (rc < 0) {
1162 	goto exit;
1163     } else {
1164 	while (! (nextPart = isPart(spec->line))) {
1165 	    const char * macro;
1166 	    rpmTagVal tag;
1167 
1168 	    /* Skip blank lines */
1169 	    linep = spec->line;
1170 	    SKIPSPACE(linep);
1171 	    if (*linep != '\0') {
1172 		if (findPreambleTag(spec, &tag, &macro, lang)) {
1173 		    if (spec->lineNum == 1 &&
1174 			(unsigned char)(spec->line[0]) == 0xed &&
1175 			(unsigned char)(spec->line[1]) == 0xab &&
1176 			(unsigned char)(spec->line[2]) == 0xee &&
1177 			(unsigned char)(spec->line[3]) == 0xdb) {
1178 			rpmlog(RPMLOG_ERR, _("Binary rpm package found. Expected spec file!\n"));
1179 			goto exit;
1180 		    }
1181 		    rpmlog(RPMLOG_ERR, _("line %d: Unknown tag: %s\n"),
1182 				spec->lineNum, spec->line);
1183 		    goto exit;
1184 		}
1185 		if (handlePreambleTag(spec, pkg, tag, macro, lang)) {
1186 		    goto exit;
1187 		}
1188 		if (spec->BANames && !spec->recursing) {
1189 		    res = PART_BUILDARCHITECTURES;
1190 		    goto exit;
1191 		}
1192 	    }
1193 	    if ((rc =
1194 		 readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
1195 		nextPart = PART_NONE;
1196 		break;
1197 	    }
1198 	    if (rc) {
1199 		goto exit;
1200 	    }
1201 	}
1202     }
1203 
1204     /*
1205      * Expand buildroot one more time to get %{version} and the like
1206      * from the main package, validate sanity. The spec->buildRoot could
1207      * still contain unexpanded macros but it cannot be empty or '/', and it
1208      * can't be messed with by anything spec does beyond this point.
1209      */
1210     if (initialPackage) {
1211 	char *buildRoot = rpmGetPath(spec->buildRoot, NULL);
1212 	free(spec->buildRoot);
1213 	spec->buildRoot = buildRoot;
1214 	rpmPushMacro(spec->macros, "buildroot", NULL, spec->buildRoot, RMIL_SPEC);
1215 	if (*buildRoot == '\0') {
1216 	    rpmlog(RPMLOG_ERR, _("%%{buildroot} couldn't be empty\n"));
1217 	    goto exit;
1218 	}
1219 	if (rstreq(buildRoot, "/")) {
1220 	    rpmlog(RPMLOG_ERR, _("%%{buildroot} can not be \"/\"\n"));
1221 	    goto exit;
1222 	}
1223     }
1224 
1225     /* XXX Skip valid arch check if not building binary package */
1226     if (!(spec->flags & RPMSPEC_ANYARCH) && checkForValidArchitectures(spec)) {
1227 	goto exit;
1228     }
1229 
1230     /* It is the main package */
1231     if (pkg == spec->packages) {
1232 	fillOutMainPackage(pkg->header);
1233 	/* Define group tag to something when group is undefined in main package*/
1234 	if (!headerIsEntry(pkg->header, RPMTAG_GROUP)) {
1235 	    headerPutString(pkg->header, RPMTAG_GROUP, "Unspecified");
1236 	}
1237     }
1238 
1239     if (checkForDuplicates(pkg->header, NVR)) {
1240 	goto exit;
1241     }
1242 
1243     if (pkg != spec->packages) {
1244 	copyInheritedTags(pkg->header, spec->packages->header);
1245     }
1246 
1247     if (checkForRequired(pkg->header, NVR)) {
1248 	goto exit;
1249     }
1250 
1251     /* if we get down here nextPart has been set to non-error */
1252     res = nextPart;
1253 
1254 exit:
1255     free(name);
1256     free(NVR);
1257     return res;
1258 }
1259