rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

parsePreamble.c
Go to the documentation of this file.
1
6 #include "system.h"
7
8 #include <rpmio.h>
9 #include <rpmiotypes.h>
10 #include <rpmlog.h>
11 #include <rpmurl.h>
12 #include <argv.h>
13 #include <mire.h>
14
15 #define _RPMEVR_INTERNAL
16 #define _RPMTAG_INTERNAL /* XXX rpmTags->aTags */
17 #include <rpmbuild.h>
18 #include "debug.h"
19
20 /*@access FD_t @*/ /* compared with NULL */
21 /*@access headerTagIndices @*/ /* rpmTags->aTags */
22
25 /*@observer@*/ /*@unchecked@*/
26 static rpmTag copyTagsDuringParse[] = {
27 RPMTAG_EPOCH,
28 RPMTAG_VERSION,
29 RPMTAG_RELEASE,
30 RPMTAG_DISTEPOCH,
31 RPMTAG_LICENSE,
32 RPMTAG_GROUP, /* XXX permissive. */
33 RPMTAG_SUMMARY, /* XXX permissive. */
34 RPMTAG_DESCRIPTION, /* XXX permissive. */
35 RPMTAG_PACKAGER,
36 RPMTAG_DISTRIBUTION,
37 RPMTAG_DISTURL,
38 RPMTAG_VENDOR,
39 RPMTAG_ICON,
40 RPMTAG_GIF,
41 RPMTAG_XPM,
42 RPMTAG_URL,
43 RPMTAG_CHANGELOGTIME,
44 RPMTAG_CHANGELOGNAME,
45 RPMTAG_CHANGELOGTEXT,
46 RPMTAG_PREFIXES,
47 RPMTAG_DISTTAG,
48 RPMTAG_CVSID,
49 RPMTAG_VARIANTS,
50 RPMTAG_XMAJOR,
51 RPMTAG_XMINOR,
52 RPMTAG_REPOTAG,
53 RPMTAG_KEYWORDS,
54 0
55 };
56
59 /*@observer@*/ /*@unchecked@*/
60 static rpmTag requiredTags[] = {
61 RPMTAG_NAME,
62 RPMTAG_VERSION,
63 RPMTAG_RELEASE,
64 RPMTAG_SUMMARY,
65 RPMTAG_GROUP,
66 RPMTAG_LICENSE,
67 0
68 };
69
72 static void addOrAppendListEntry(Header h, rpmTag tag, char * line)
73 /*@modifies h @*/
74 {
75 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
76 int xx;
77 int argc;
78 const char **argv;
79
80 xx = poptParseArgvString(line, &argc, &argv);
81 if (argc) {
82 he->tag = tag;
83 he->t = RPM_STRING_ARRAY_TYPE;
84 he->p.argv = argv;
85 he->c = argc;
86 he->append = 1;
87 xx = headerPut(h, he, 0);
88 he->append = 0;
89 }
90 argv = _free(argv);
91 }
92
93 /* Parse a simple part line that only take -n <pkg> or <pkg> */
94 /* <pkg> is returned in name as a pointer into malloc'd storage. */
95
98 static int parseSimplePart(Spec spec, /*@out@*/char ** Np,
99 /*@out@*/rpmParseState *flag)
100 /*@globals internalState@*/
101 /*@modifies *Np, *flag, internalState, spec->line @*/
102 {
103 char * s, * se;
104 int rc = 0; /* assume failure */
105
106 if (Np)
107 *Np = NULL;
108
109 se = strchr(spec->line, '#');
110 if (se) {
111 *se = '\0';
112 while (--se >= spec->line && strchr(" \t\n\r", *se) != NULL)
113 *se = '\0';
114 }
115
116 s = xstrdup(spec->line);
117 /* Throw away the first token (the %xxxx) */
118 (void)strtok(s, " \t\n");
119
120 if (!(se = strtok(NULL, " \t\n")))
121 goto exit;
122
123 if (!strcmp(se, "-n")) {
124 if (!(se = strtok(NULL, " \t\n"))) {
125 rc = 1;
126 goto exit;
127 }
128 *flag = PART_NAME;
129 } else
130 *flag = PART_SUBNAME;
131
132 if (Np)
133 *Np = xstrdup(se);
134
135 rc = (strtok(NULL, " \t\n") ? 1 : 0);
136
137 exit:
138 s = _free(s);
139 return rc;
140 }
141
144 static inline int parseYesNo(const char * s)
145 /*@*/
146 {
147 return ((!s || (s[0] == 'n' || s[0] == 'N' || s[0] == '0') ||
148 !xstrcasecmp(s, "false") || !xstrcasecmp(s, "off"))
149 ? 0 : 1);
150 }
151
152 typedef struct tokenBits_s {
153 /*@observer@*/ /*@null@*/
154 const char * name;
155 rpmsenseFlags bits;
156 } * tokenBits;
157
160 /*@observer@*/ /*@unchecked@*/
161 static struct tokenBits_s installScriptBits[] = {
162 { "interp", RPMSENSE_INTERP },
163 { "preun", RPMSENSE_SCRIPT_PREUN },
164 { "pre", RPMSENSE_SCRIPT_PRE },
165 { "postun", RPMSENSE_SCRIPT_POSTUN },
166 { "post", RPMSENSE_SCRIPT_POST },
167 { "rpmlib", RPMSENSE_RPMLIB },
168 { "verify", RPMSENSE_SCRIPT_VERIFY },
169 { "hint", RPMSENSE_MISSINGOK },
170 { NULL, 0 }
171 };
172
175 /*@observer@*/ /*@unchecked@*/
176 static struct tokenBits_s buildScriptBits[] = {
177 { "prep", RPMSENSE_SCRIPT_PREP },
178 { "build", RPMSENSE_SCRIPT_BUILD },
179 { "install", RPMSENSE_SCRIPT_INSTALL },
180 { "clean", RPMSENSE_SCRIPT_CLEAN },
181 { "hint", RPMSENSE_MISSINGOK },
182 { NULL, 0 }
183 };
184
187 static int parseBits(const char * s, const tokenBits tokbits,
188 /*@out@*/ rpmsenseFlags * bp)
189 /*@modifies *bp @*/
190 {
191 tokenBits tb;
192 const char * se;
193 rpmsenseFlags bits = RPMSENSE_ANY;
194 int c = 0;
195
196 if (s) {
197 while (*s != '\0') {
198 while ((c = *s) && xisspace(c)) s++;
199 se = s;
200 while ((c = *se) && xisalpha(c)) se++;
201 if (s == se)
202 break;
203 for (tb = tokbits; tb->name; tb++) {
204 if (tb->name != NULL &&
205 strlen(tb->name) == (size_t)(se-s) && !strncmp(tb->name, s, (se-s)))
206 /*@innerbreak@*/ break;
207 }
208 if (tb->name == NULL)
209 break;
210 bits |= tb->bits;
211 while ((c = *se) && xisspace(c)) se++;
212 if (c != ',')
213 break;
214 s = ++se;
215 }
216 }
217 if (c == 0 && bp) *bp = bits;
218 return (c ? RPMRC_FAIL : RPMRC_OK);
219 }
220
223 /*@null@*/
224 static inline char * findLastChar(char * s)
225 /*@modifies *s @*/
226 {
227 char *se = s + strlen(s);
228
229 /* Right trim white space. */
230 while (--se > s && strchr(" \t\n\r", *se) != NULL)
231 *se = '\0';
232 /* Truncate comments. */
233 if ((se = strchr(s, '#')) != NULL) {
234 *se = '\0';
235 while (--se > s && strchr(" \t\n\r", *se) != NULL)
236 *se = '\0';
237 }
238 /*@-temptrans -retalias @*/
239 return se;
240 /*@=temptrans =retalias @*/
241 }
242
245 static int isMemberInEntry(Header h, const char *name, rpmTag tag)
246 /*@globals internalState @*/
247 /*@modifies internalState @*/
248 {
249 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
250 int rc = -1;
251 int xx;
252
253 he->tag = tag;
254 xx = headerGet(h, he, 0);
255 if (!xx)
256 return rc;
257 rc = 0;
258 while (he->c) {
259 he->c--;
260 if (xstrcasecmp(he->p.argv[he->c], name))
261 continue;
262 rc = 1;
263 break;
264 }
265 he->p.ptr = _free(he->p.ptr);
266 return rc;
267 }
268
271 static int checkForValidArchitectures(Spec spec)
272 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
273 /*@modifies rpmGlobalMacroContext, internalState @*/
274 {
275 const char *arch = rpmExpand("%{_target_cpu}", NULL);
276 const char *os = rpmExpand("%{_target_os}", NULL);
277 int rc = RPMRC_FAIL; /* assume failure. */
278
279 if (isMemberInEntry(spec->sourceHeader, arch, RPMTAG_EXCLUDEARCH) == 1) {
280 rpmlog(RPMLOG_ERR, _("Architecture is excluded: %s\n"), arch);
281 goto exit;
282 }
283 if (isMemberInEntry(spec->sourceHeader, arch, RPMTAG_EXCLUSIVEARCH) == 0) {
284 rpmlog(RPMLOG_ERR, _("Architecture is not included: %s\n"), arch);
285 goto exit;
286 }
287 if (isMemberInEntry(spec->sourceHeader, os, RPMTAG_EXCLUDEOS) == 1) {
288 rpmlog(RPMLOG_ERR, _("OS is excluded: %s\n"), os);
289 goto exit;
290 }
291 if (isMemberInEntry(spec->sourceHeader, os, RPMTAG_EXCLUSIVEOS) == 0) {
292 rpmlog(RPMLOG_ERR, _("OS is not included: %s\n"), os);
293 goto exit;
294 }
295 rc = 0;
296 exit:
297 arch = _free(arch);
298 os = _free(os);
299 return rc;
300 }
301
308 static rpmRC checkForRequired(Header h, const char * NVR)
309 /*@*/
310 {
311 rpmTag * p;
312 rpmRC rc = RPMRC_OK;
313
314 for (p = requiredTags; *p != 0; p++) {
315 if (!headerIsEntry(h, *p)) {
316 rpmlog(RPMLOG_ERR,
317 _("%s field must be present in package: %s\n"),
318 tagName(*p), NVR);
319 rc = RPMRC_FAIL;
320 }
321 }
322
323 return rc;
324 }
325
332 static rpmRC checkForDuplicates(Header h, const char * NVR)
333 /*@globals internalState @*/
334 /*@modifies h, internalState @*/
335 {
336 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
337 HeaderIterator hi;
338 rpmTag lastTag = 0;
339 rpmRC rc = RPMRC_OK;
340
341 for (hi = headerInit(h);
342 headerNext(hi, he, 0);
343 he->p.ptr = _free(he->p.ptr))
344 {
345 if (he->tag != lastTag) {
346 lastTag = he->tag;
347 continue;
348 }
349 rpmlog(RPMLOG_ERR, _("Duplicate %s entries in package: %s\n"),
350 tagName(he->tag), NVR);
351 rc = RPMRC_FAIL;
352 }
353 hi = headerFini(hi);
354
355 return rc;
356 }
357
360 /*@observer@*/ /*@unchecked@*/
361 static struct optionalTag {
362 rpmTag ot_tag;
363 /*@observer@*/ /*@null@*/
364 const char * ot_mac;
365 } optionalTags[] = {
366 { RPMTAG_VENDOR, "%{vendor}" },
367 { RPMTAG_PACKAGER, "%{packager}" },
368 { RPMTAG_DISTEPOCH, "%{distepoch}" },
369 { RPMTAG_DISTRIBUTION, "%{distribution}" },
370 { RPMTAG_DISTTAG, "%{disttag}" },
371 { RPMTAG_DISTURL, "%{disturl}" },
372 { 0xffffffff, "%{class}" },
373 { -1, NULL }
374 };
375
378 static void fillOutMainPackage(Header h)
379 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
380 /*@modifies h, rpmGlobalMacroContext, internalState @*/
381 {
382 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
383 struct optionalTag *ot;
384 int xx;
385
386 for (ot = optionalTags; ot->ot_mac != NULL; ot++) {
387 const char * val;
388 rpmTag tag;
389
390 tag = ot->ot_tag;
391
392 /* Generate arbitrary tag (if necessary). */
393 if (tag == 0xffffffff) {
394 val = tagCanonicalize(ot->ot_mac + (sizeof("%{")-1));
395 tag = tagGenerate(val);
396 val = _free(val);
397 }
398
399 if (headerIsEntry(h, tag))
400 continue;
401 val = rpmExpand(ot->ot_mac, NULL);
402 if (val && *val != '%') {
403 he->tag = tag;
404 he->t = RPM_STRING_TYPE;
405 he->p.str = val;
406 he->c = 1;
407 xx = headerPut(h, he, 0);
408 }
409 val = _free(val);
410 }
411 }
412
415 static int doIcon(Spec spec, Header h)
416 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
417 /*@modifies h, rpmGlobalMacroContext, fileSystem, internalState @*/
418 {
419 static size_t iconsize = 0;
420 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
421 const char *fn, *Lurlfn = NULL;
422 struct Source *sp;
423 size_t nb;
424 rpmuint8_t * icon;
425 FD_t fd = NULL;
426 int rc = RPMRC_FAIL; /* assume error */
427 int urltype;
428 int xx;
429
430 if (iconsize == 0) {
431 iconsize = rpmExpandNumeric("%{?_build_iconsize}");
432 if (iconsize < 2048)
433 iconsize = 2048;
434 }
435 icon = alloca(iconsize+1);
436
437 for (sp = spec->sources; sp != NULL; sp = sp->next) {
438 if (sp->flags & RPMFILE_ICON)
439 break;
440 }
441 if (sp == NULL) {
442 rpmlog(RPMLOG_ERR, _("No icon file in sources\n"));
443 goto exit;
444 }
445
446 #if defined(RPM_VENDOR_OPENPKG) /* splitted-source-directory */
447 /* support splitted source directories, i.e., source files which
448 are alternatively placed into the .spec directory and picked
449 up from there, too. */
450 Lurlfn = rpmGenPath(NULL, "%{_specdir}/", sp->source);
451 if (access(Lurlfn, F_OK) == -1) {
452 Lurlfn = _free(Lurlfn);
453 Lurlfn = rpmGenPath(NULL, "%{_icondir}/", sp->source);
454 }
455 #else
456 Lurlfn = rpmGenPath(NULL, "%{_icondir}/", sp->source);
457 #endif
458
459 fn = NULL;
460 urltype = urlPath(Lurlfn, &fn);
461 switch (urltype) {
462 case URL_IS_HTTPS:
463 case URL_IS_HTTP:
464 case URL_IS_FTP:
465 case URL_IS_PATH:
466 case URL_IS_UNKNOWN:
467 break;
468 case URL_IS_DASH:
469 case URL_IS_HKP:
470 rpmlog(RPMLOG_ERR, _("Invalid icon URL: %s\n"), Lurlfn);
471 goto exit;
472 /*@notreached@*/ break;
473 }
474
475 fd = Fopen(fn, "r%{?_rpmgio}");
476 if (fd == NULL || Ferror(fd)) {
477 rpmlog(RPMLOG_ERR, _("Unable to open icon %s: %s\n"),
478 fn, Fstrerror(fd));
479 rc = RPMRC_FAIL;
480 goto exit;
481 }
482
483 *icon = '\0';
484 nb = Fread(icon, sizeof(icon[0]), iconsize, fd);
485 if (Ferror(fd) || nb == 0) {
486 rpmlog(RPMLOG_ERR, _("Unable to read icon %s: %s\n"),
487 fn, Fstrerror(fd));
488 goto exit;
489 }
490 if (nb >= iconsize) {
491 rpmlog(RPMLOG_ERR, _("Icon %s is too big (max. %d bytes)\n"),
492 fn, (int)iconsize);
493 goto exit;
494 }
495
496 if (icon[0] == 'G' && icon[1] == 'I' && icon[2] == 'F')
497 he->tag = RPMTAG_GIF;
498 else
499 if (icon[0] == '/' && icon[1] == '*' && icon[2] == ' '
500 && icon[3] == 'X' && icon[4] == 'P' && icon[5] == 'M')
501 he->tag = RPMTAG_XPM;
502 else
503 he->tag = tagValue("Icon");
504 he->t = RPM_BIN_TYPE;
505 he->p.ui8p = icon;
506 he->c = (rpmTagCount)nb;
507 xx = headerPut(h, he, 0);
508 rc = 0;
509
510 exit:
511 if (fd) {
512 (void) Fclose(fd);
513 fd = NULL;
514 }
515 Lurlfn = _free(Lurlfn);
516 return rc;
517 }
518
519 spectag stashSt(Spec spec, Header h, rpmTag tag, const char * lang)
520 {
521 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
522 spectag t = NULL;
523 int xx;
524
525 if (spec->st) {
526 spectags st = spec->st;
527 if (st->st_ntags == st->st_nalloc) {
528 st->st_nalloc += 10;
529 st->st_t = xrealloc(st->st_t, st->st_nalloc * sizeof(*(st->st_t)));
530 }
531 t = st->st_t + st->st_ntags++;
532 t->t_tag = tag;
533 t->t_startx = spec->lineNum - 1;
534 t->t_nlines = 1;
535 t->t_lang = xstrdup(lang);
536 t->t_msgid = NULL;
537 if (!(t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG))) {
538 he->tag = RPMTAG_NAME;
539 xx = headerGet(h, he, 0);
540 if (xx) {
541 char buf[1024];
542 sprintf(buf, "%s(%s)", he->p.str, tagName(tag));
543 t->t_msgid = xstrdup(buf);
544 }
545 he->p.ptr = _free(he->p.ptr);
546 }
547 }
548 /*@-usereleased -compdef@*/
549 return t;
550 /*@=usereleased =compdef@*/
551 }
552
553 #define SINGLE_TOKEN_ONLY \
554 if (multiToken) { \
555 rpmlog(RPMLOG_ERR, _("line %d: Tag takes single token only: %s\n"), \
556 spec->lineNum, spec->line); \
557 return RPMRC_FAIL; \
558 }
559
560 /*@-redecl@*/
561 extern int noLang;
562 /*@=redecl@*/
563
564 static rpmRC tagValidate(Spec spec, rpmTag tag, const char * value)
565 /*@*/
566 {
567 const char * tagN = tagName(tag);
568 const char * pattern = rpmExpand("%{?pattern_", tagN, "}", NULL);
569 rpmRC ec = RPMRC_OK;
570
571 if (pattern && *pattern) {
572 miRE mire;
573 int xx;
574
575 mire = mireNew(RPMMIRE_REGEX, tag);
576 xx = mireSetCOptions(mire, RPMMIRE_REGEX, 0, 0, NULL);
577 if (!xx)
578 xx = mireRegcomp(mire, pattern);
579 if (!xx)
580 xx = mireRegexec(mire, value, strlen(value));
581 if (!xx)
582 ec = RPMRC_OK;
583 else {
584 rpmlog(RPMLOG_ERR, _("line %d: invalid tag value(\"%s\") %s: %s\n"),
585 spec->lineNum, pattern, tagN, spec->line);
586 ec = RPMRC_FAIL;
587 }
588
589 mire = mireFree(mire);
590 }
591
592 pattern = _free(pattern);
593
594 return ec;
595 }
596
599 static rpmRC handlePreambleTag(Spec spec, Package pkg, rpmTag tag,
600 const char *macro, const char *lang)
601 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
602 /*@modifies spec->macros, spec->st,
603 spec->sources, spec->numSources, spec->noSource,
604 spec->sourceHeader, spec->BANames, spec->BACount,
605 spec->line,
606 pkg->header, pkg->autoProv, pkg->autoReq, pkg->noarch,
607 rpmGlobalMacroContext, fileSystem, internalState @*/
608 {
609 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
610 char * field = spec->line;
611 char * end;
612 int multiToken = 0;
613 rpmsenseFlags tagflags;
614 int len;
615 rpmuint32_t num;
616 int rc;
617 int xx;
618 #if defined(RPM_VENDOR_MANDRIVA) /* build-expand-field-for-single-token */
619 char * expand_field = NULL;
620 #endif
621
622 if (field == NULL) return RPMRC_FAIL; /* XXX can't happen */
623 /* Find the start of the "field" and strip trailing space */
624 while ((*field) && (*field != ':'))
625 field++;
626 if (*field != ':') {
627 rpmlog(RPMLOG_ERR, _("line %d: Malformed tag: %s\n"),
628 spec->lineNum, spec->line);
629 return RPMRC_FAIL;
630 }
631 field++;
632 SKIPSPACE(field);
633 if (!*field) {
634 /* Empty field */
635 rpmlog(RPMLOG_ERR, _("line %d: Empty tag: %s\n"),
636 spec->lineNum, spec->line);
637 return RPMRC_FAIL;
638 }
639 #if defined(RPM_VENDOR_MANDRIVA) /* build-expand-field-for-single-token */
640 expand_field = rpmExpand(field, NULL);
641 #else
642 end = findLastChar(field);
643 #endif
644
645 /* Validate tag data content. */
646 if (tagValidate(spec, tag, field) != RPMRC_OK)
647 return RPMRC_FAIL;
648
649 /* See if this is multi-token */
650 #if defined(RPM_VENDOR_MANDRIVA) /* build-expand-field-for-single-token */
651 end = expand_field;
652 #else
653 end = field;
654 #endif
655 SKIPNONSPACE(end);
656 if (*end != '\0')
657 multiToken = 1;
658 #if defined(RPM_VENDOR_MANDRIVA) /* build-expand-field-for-single-token */
659 _free(expand_field);
660 #endif
661
662 switch (tag) {
663 case RPMTAG_NAME:
664 case RPMTAG_VERSION:
665 case RPMTAG_RELEASE:
666 case RPMTAG_DISTEPOCH:
667 case RPMTAG_URL:
668 case RPMTAG_DISTTAG:
669 case RPMTAG_REPOTAG:
670 case RPMTAG_CVSID:
671 SINGLE_TOKEN_ONLY;
672 /* These macros are for backward compatibility */
673 if (tag == RPMTAG_VERSION) {
674 if (strchr(field, '-') != NULL) {
675 rpmlog(RPMLOG_ERR, _("line %d: Illegal char '-' in %s: %s\n"),
676 spec->lineNum, "version", spec->line);
677 return RPMRC_FAIL;
678 }
679 addMacro(spec->macros, "PACKAGE_VERSION", NULL, field, RMIL_OLDSPEC);
680 } else if (tag == RPMTAG_RELEASE) {
681 if (strchr(field, '-') != NULL) {
682 rpmlog(RPMLOG_ERR, _("line %d: Illegal char '-' in %s: %s\n"),
683 spec->lineNum, "release", spec->line);
684 return RPMRC_FAIL;
685 }
686 addMacro(spec->macros, "PACKAGE_RELEASE", NULL, field, RMIL_OLDSPEC-1);
687 }
688 he->tag = tag;
689 he->t = RPM_STRING_TYPE;
690 he->p.str = field;
691 he->c = 1;
692 xx = headerPut(pkg->header, he, 0);
693 break;
694 case RPMTAG_GROUP:
695 case RPMTAG_SUMMARY:
696 #if defined(RPM_VENDOR_OPENPKG) /* make-class-available-as-macro */
697 case RPMTAG_CLASS:
698 #endif
699 (void) stashSt(spec, pkg->header, tag, lang);
700 /*@fallthrough@*/
701 case RPMTAG_DISTRIBUTION:
702 case RPMTAG_VENDOR:
703 case RPMTAG_LICENSE:
704 case RPMTAG_PACKAGER:
705 if (!*lang) {
706 he->tag = tag;
707 he->t = RPM_STRING_TYPE;
708 he->p.str = field;
709 he->c = 1;
710 xx = headerPut(pkg->header, he, 0);
711 } else if (!(noLang && strcmp(lang, RPMBUILD_DEFAULT_LANG))) {
712 (void) headerAddI18NString(pkg->header, tag, field, lang);
713 }
714 break;
715 /* XXX silently ignore BuildRoot: */
716 case RPMTAG_BUILDROOT:
717 SINGLE_TOKEN_ONLY;
718 macro = NULL;
719 #ifdef DYING
720 buildRootURL = rpmGenPath(spec->rootURL, "%{?buildroot}", NULL);
721 (void) urlPath(buildRootURL, &buildRoot);
722 if (*buildRoot == '\0') buildRoot = "/";
723 if (!strcmp(buildRoot, "/")) {
724 rpmlog(RPMLOG_ERR,
725 _("BuildRoot can not be \"/\": %s\n"), spec->buildRootURL);
726 buildRootURL = _free(buildRootURL);
727 return RPMRC_FAIL;
728 }
729 buildRootURL = _free(buildRootURL);
730 #endif
731 break;
732 case RPMTAG_KEYWORDS:
733 case RPMTAG_VARIANTS:
734 case RPMTAG_PREFIXES:
735 addOrAppendListEntry(pkg->header, tag, field);
736 he->tag = tag;
737 xx = headerGet(pkg->header, he, 0);
738 if (tag == RPMTAG_PREFIXES)
739 while (he->c--) {
740 if (he->p.argv[he->c][0] != '/') {
741 rpmlog(RPMLOG_ERR,
742 _("line %d: Prefixes must begin with \"/\": %s\n"),
743 spec->lineNum, spec->line);
744 he->p.ptr = _free(he->p.ptr);
745 return RPMRC_FAIL;
746 }
747 len = (int)strlen(he->p.argv[he->c]);
748 if (he->p.argv[he->c][len - 1] == '/' && len > 1) {
749 rpmlog(RPMLOG_ERR,
750 _("line %d: Prefixes must not end with \"/\": %s\n"),
751 spec->lineNum, spec->line);
752 he->p.ptr = _free(he->p.ptr);
753 return RPMRC_FAIL;
754 }
755 }
756 he->p.ptr = _free(he->p.ptr);
757 break;
758 case RPMTAG_DOCDIR:
759 SINGLE_TOKEN_ONLY;
760 if (field[0] != '/') {
761 rpmlog(RPMLOG_ERR,
762 _("line %d: Docdir must begin with '/': %s\n"),
763 spec->lineNum, spec->line);
764 return RPMRC_FAIL;
765 }
766 macro = NULL;
767 delMacro(NULL, "_docdir");
768 addMacro(NULL, "_docdir", NULL, field, RMIL_SPEC);
769 break;
770 case RPMTAG_XMAJOR:
771 case RPMTAG_XMINOR:
772 case RPMTAG_EPOCH:
773 SINGLE_TOKEN_ONLY;
774 if (parseNum(field, &num)) {
775 rpmlog(RPMLOG_ERR,
776 _("line %d: %s takes an integer value: %s\n"),
777 spec->lineNum, tagName(tag), spec->line);
778 return RPMRC_FAIL;
779 }
780 he->tag = tag;
781 he->t = RPM_UINT32_TYPE;
782 he->p.ui32p = &num;
783 he->c = 1;
784 xx = headerPut(pkg->header, he, 0);
785 break;
786 case RPMTAG_AUTOREQPROV:
787 pkg->autoReq = parseYesNo(field);
788 pkg->autoProv = pkg->autoReq;
789 break;
790 case RPMTAG_AUTOREQ:
791 pkg->autoReq = parseYesNo(field);
792 break;
793 case RPMTAG_AUTOPROV:
794 pkg->autoProv = parseYesNo(field);
795 break;
796 case RPMTAG_SOURCE:
797 case RPMTAG_PATCH:
798 SINGLE_TOKEN_ONLY;
799 macro = NULL;
800 if ((rc = addSource(spec, pkg, field, tag)))
801 return rc;
802 break;
803 case RPMTAG_ICON:
804 SINGLE_TOKEN_ONLY;
805 macro = NULL;
806 if ((rc = addSource(spec, pkg, field, tag)))
807 return rc;
808 /* XXX the fetch/load of icon needs to be elsewhere. */
809 if ((rc = doIcon(spec, pkg->header)))
810 return rc;
811 break;
812 case RPMTAG_NOSOURCE:
813 case RPMTAG_NOPATCH:
814 spec->noSource = 1;
815 if ((rc = parseNoSource(spec, field, tag)))
816 return rc;
817 break;
818 case RPMTAG_BUILDPREREQ:
819 case RPMTAG_BUILDREQUIRES:
820 if ((rc = parseBits(lang, buildScriptBits, &tagflags))) {
821 rpmlog(RPMLOG_ERR,
822 _("line %d: Bad %s: qualifiers: %s\n"),
823 spec->lineNum, tagName(tag), spec->line);
824 return rc;
825 }
826 if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
827 return rc;
828 break;
829 case RPMTAG_PREREQ:
830 case RPMTAG_REQUIREFLAGS:
831 if ((rc = parseBits(lang, installScriptBits, &tagflags))) {
832 rpmlog(RPMLOG_ERR,
833 _("line %d: Bad %s: qualifiers: %s\n"),
834 spec->lineNum, tagName(tag), spec->line);
835 return rc;
836 }
837 if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
838 return rc;
839 break;
840 /* Aliases for BuildRequires(hint): */
841 case RPMTAG_BUILDSUGGESTS:
842 case RPMTAG_BUILDENHANCES:
843 tagflags = RPMSENSE_MISSINGOK;
844 if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
845 return rc;
846 break;
847 /* Aliases for Requires(hint): */
848 case RPMTAG_SUGGESTSFLAGS:
849 case RPMTAG_ENHANCESFLAGS:
850 tag = RPMTAG_REQUIREFLAGS;
851 tagflags = RPMSENSE_MISSINGOK;
852 if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
853 return rc;
854 break;
855 case RPMTAG_BUILDOBSOLETES:
856 case RPMTAG_BUILDPROVIDES:
857 case RPMTAG_BUILDCONFLICTS:
858 case RPMTAG_CONFLICTFLAGS:
859 case RPMTAG_OBSOLETEFLAGS:
860 case RPMTAG_PROVIDEFLAGS:
861 tagflags = RPMSENSE_ANY;
862 if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
863 return rc;
864 break;
865 case RPMTAG_BUILDPLATFORMS: /* XXX needs pattern parsing */
866 case RPMTAG_EXCLUDEARCH:
867 case RPMTAG_EXCLUSIVEARCH:
868 case RPMTAG_EXCLUDEOS:
869 case RPMTAG_EXCLUSIVEOS:
870 addOrAppendListEntry(spec->sourceHeader, tag, field);
871 break;
872
873 case RPMTAG_BUILDARCHS:
874 { const char ** BANames = NULL;
875 int BACount = 0;
876 if ((rc = poptParseArgvString(field, &BACount, &BANames))) {
877 rpmlog(RPMLOG_ERR,
878 _("line %d: Bad BuildArchitecture format: %s\n"),
879 spec->lineNum, spec->line);
880 return RPMRC_FAIL;
881 }
882 if (spec->toplevel) {
883 if (BACount > 0 && BANames != NULL) {
884 spec->BACount = BACount;
885 spec->BANames = BANames;
886 BANames = NULL; /* XXX don't free. */
887 }
888 } else {
889 if (BACount != 1 || strcmp(BANames[0], "noarch")) {
890 rpmlog(RPMLOG_ERR,
891 _("line %d: Only \"noarch\" sub-packages are supported: %s\n"),
892 spec->lineNum, spec->line);
893 BANames = _free(BANames);
894 return RPMRC_FAIL;
895 }
896 pkg->noarch = 1;
897 }
898 BANames = _free(BANames);
899 } break;
900
901 default:
902 macro = NULL;
903 he->tag = tag;
904 he->t = RPM_STRING_ARRAY_TYPE;
905 he->p.argv= (const char **) &field; /* XXX NOCAST */
906 he->c = 1;
907 he->append = 1;
908 xx = headerPut(pkg->header, he, 0);
909 he->append = 0;
910 break;
911 }
912
913 /*@-usereleased@*/
914 if (macro)
915 addMacro(spec->macros, macro, NULL, field, RMIL_SPEC);
916 /*@=usereleased@*/
917
918 return RPMRC_OK;
919 }
920
921 /* This table has to be in a peculiar order. If one tag is the */
922 /* same as another, plus a few letters, it must come first. */
923
926 typedef struct PreambleRec_s {
927 rpmTag tag;
928 int multiLang;
929 int obsolete;
930 /*@observer@*/ /*@null@*/
931 const char * token;
932 } * PreambleRec;
933
934 /*@unchecked@*/
935 static struct PreambleRec_s preambleList[] = {
936 {RPMTAG_NAME, 0, 0, "name"},
937 {RPMTAG_VERSION, 0, 0, "version"},
938 {RPMTAG_RELEASE, 0, 0, "release"},
939 {RPMTAG_DISTEPOCH, 0, 0, "distepoch"},
940 {RPMTAG_EPOCH, 0, 0, "epoch"},
941 {RPMTAG_EPOCH, 0, 1, "serial"},
942 {RPMTAG_SUMMARY, 1, 0, "summary"},
943 {RPMTAG_LICENSE, 0, 0, "copyright"},
944 {RPMTAG_LICENSE, 0, 0, "license"},
945 {RPMTAG_DISTRIBUTION, 0, 0, "distribution"},
946 {RPMTAG_DISTURL, 0, 0, "disturl"},
947 {RPMTAG_VENDOR, 0, 0, "vendor"},
948 {RPMTAG_GROUP, 1, 0, "group"},
949 {RPMTAG_PACKAGER, 0, 0, "packager"},
950 {RPMTAG_URL, 0, 0, "url"},
951 {RPMTAG_SOURCE, 0, 0, "source"},
952 {RPMTAG_PATCH, 0, 0, "patch"},
953 {RPMTAG_NOSOURCE, 0, 0, "nosource"},
954 {RPMTAG_NOPATCH, 0, 0, "nopatch"},
955 {RPMTAG_EXCLUDEARCH, 0, 0, "excludearch"},
956 {RPMTAG_EXCLUSIVEARCH, 0, 0, "exclusivearch"},
957 {RPMTAG_EXCLUDEOS, 0, 0, "excludeos"},
958 {RPMTAG_EXCLUSIVEOS, 0, 0, "exclusiveos"},
959 {RPMTAG_ICON, 0, 0, "icon"},
960 {RPMTAG_PROVIDEFLAGS, 0, 0, "provides"},
961 {RPMTAG_REQUIREFLAGS, 1, 0, "requires"},
962 {RPMTAG_PREREQ, 1, 0, "prereq"},
963 {RPMTAG_CONFLICTFLAGS, 0, 0, "conflicts"},
964 {RPMTAG_OBSOLETEFLAGS, 0, 0, "obsoletes"},
965 {RPMTAG_PREFIXES, 0, 0, "prefixes"},
966 {RPMTAG_PREFIXES, 0, 0, "prefix"},
967 {RPMTAG_BUILDROOT, 0, 0, "buildroot"},
968 {RPMTAG_BUILDARCHS, 0, 0, "buildarchitectures"},
969 {RPMTAG_BUILDARCHS, 0, 0, "buildarch"},
970 {RPMTAG_BUILDCONFLICTS, 0, 0, "buildconflicts"},
971 {RPMTAG_BUILDOBSOLETES, 0, 0, "buildobsoletes"},
972 {RPMTAG_BUILDPREREQ, 1, 0, "buildprereq"},
973 {RPMTAG_BUILDPROVIDES, 0, 0, "buildprovides"},
974 {RPMTAG_BUILDREQUIRES, 1, 0, "buildrequires"},
975 {RPMTAG_AUTOREQPROV, 0, 0, "autoreqprov"},
976 {RPMTAG_AUTOREQ, 0, 0, "autoreq"},
977 {RPMTAG_AUTOPROV, 0, 0, "autoprov"},
978 {RPMTAG_DOCDIR, 0, 0, "docdir"},
979 {RPMTAG_DISTTAG, 0, 0, "disttag"},
980 {RPMTAG_CVSID, 0, 0, "cvsid"},
981 {RPMTAG_SVNID, 0, 0, "svnid"},
982 {RPMTAG_SUGGESTSFLAGS, 0, 0, "suggests"},
983 {RPMTAG_ENHANCESFLAGS, 0, 0, "enhances"},
984 {RPMTAG_BUILDSUGGESTS, 0, 0, "buildsuggests"},
985 {RPMTAG_BUILDENHANCES, 0, 0, "buildenhances"},
986 {RPMTAG_VARIANTS, 0, 0, "variants"},
987 {RPMTAG_VARIANTS, 0, 0, "variant"},
988 {RPMTAG_XMAJOR, 0, 0, "xmajor"},
989 {RPMTAG_XMINOR, 0, 0, "xminor"},
990 {RPMTAG_REPOTAG, 0, 0, "repotag"},
991 {RPMTAG_KEYWORDS, 0, 0, "keywords"},
992 {RPMTAG_KEYWORDS, 0, 0, "keyword"},
993 {RPMTAG_BUILDPLATFORMS, 0, 0, "buildplatforms"},
994 #if defined(RPM_VENDOR_OPENPKG) /* make-class-available-as-macro */
995 {RPMTAG_CLASS, 0, 0, "class"},
996 #endif
997 /*@-nullassign@*/ /* LCL: can't add null annotation */
998 {0, 0, 0, 0}
999 /*@=nullassign@*/
1000 };
1001
1004 static int findPreambleTag(Spec spec, /*@out@*/rpmTag * tagp,
1005 /*@null@*/ /*@out@*/ const char ** macro, /*@out@*/ char * lang)
1006 /*@modifies *tagp, *macro, *lang @*/
1007 {
1008 PreambleRec p;
1009 char *s;
1010 size_t len = 0;
1011
1012 /* Search for defined tags. */
1013 for (p = preambleList; p->token != NULL; p++) {
1014 len = strlen(p->token);
1015 if (!(p->token && !xstrncasecmp(spec->line, p->token, len)))
1016 continue;
1017 if (p->obsolete) {
1018 rpmlog(RPMLOG_ERR, _("Legacy syntax is unsupported: %s\n"),
1019 p->token);
1020 p = NULL;
1021 }
1022 break;
1023 }
1024 if (p == NULL)
1025 return 1;
1026
1027 /* Search for arbitrary tags. */
1028 if (tagp && p->token == NULL) {
1029 ARGV_t aTags = NULL;
1030 int rc = 1; /* assume failure */
1031
1032 /*@-noeffect@*/
1033 (void) tagName(0); /* XXX force arbitrary tags to be initialized. */
1034 /*@=noeffect@*/
1035 aTags = rpmTags->aTags;
1036 if (aTags != NULL && aTags[0] != NULL) {
1037 ARGV_t av;
1038 s = tagCanonicalize(spec->line);
1039 #if defined(RPM_VENDOR_OPENPKG) /* wildcard-matching-arbitrary-tagnames */
1040 av = argvSearchLinear(aTags, s, argvFnmatchCasefold);
1041 #else
1042 av = argvSearch(aTags, s, argvStrcasecmp);
1043 #endif
1044 if (av != NULL) {
1045 *tagp = tagGenerate(s);
1046 rc = 0;
1047 }
1048 s = _free(s);
1049 }
1050 return rc;
1051 }
1052
1053 s = spec->line + len;
1054 SKIPSPACE(s);
1055
1056 switch (p->multiLang) {
1057 default:
1058 case 0:
1059 /* Unless this is a source or a patch, a ':' better be next */
1060 if (p->tag != RPMTAG_SOURCE && p->tag != RPMTAG_PATCH) {
1061 if (*s != ':') return 1;
1062 }
1063 *lang = '\0';
1064 break;
1065 case 1: /* Parse optional ( <token> ). */
1066 if (*s == ':') {
1067 strcpy(lang, RPMBUILD_DEFAULT_LANG);
1068 break;
1069 }
1070 if (*s != '(') return 1;
1071 s++;
1072 SKIPSPACE(s);
1073 while (!xisspace(*s) && *s != ')')
1074 *lang++ = *s++;
1075 *lang = '\0';
1076 SKIPSPACE(s);
1077 if (*s != ')') return 1;
1078 s++;
1079 SKIPSPACE(s);
1080 if (*s != ':') return 1;
1081 break;
1082 }
1083
1084 if (tagp)
1085 *tagp = p->tag;
1086 if (macro)
1087 /*@-onlytrans -observertrans -dependenttrans@*/ /* FIX: double indirection. */
1088 *macro = p->token;
1089 /*@=onlytrans =observertrans =dependenttrans@*/
1090 return 0;
1091 }
1092
1093 /* XXX should return rpmParseState, but RPMRC_FAIL forces int return. */
1094 int parsePreamble(Spec spec, int initialPackage)
1095 {
1096 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
1097 rpmParseState nextPart;
1098 int xx;
1099 char *linep;
1100 Package pkg;
1101 char NVR[BUFSIZ];
1102 char lang[BUFSIZ];
1103 rpmRC rc;
1104
1105 strcpy(NVR, "(main package)");
1106
1107 pkg = newPackage(spec);
1108 if (spec->packages == NULL) {
1109 spec->packages = pkg;
1110 assert(initialPackage);
1111 } else if (! initialPackage) {
1112 char *name = NULL;
1113 rpmParseState flag;
1114 Package lastpkg;
1115
1116 /* There is one option to %package: <pkg> or -n <pkg> */
1117 flag = PART_NONE;
1118 if (parseSimplePart(spec, &name, &flag)) {
1119 rpmlog(RPMLOG_ERR, _("Bad package specification: %s\n"),
1120 spec->line);
1121 return RPMRC_FAIL;
1122 }
1123
1124 lastpkg = NULL;
1125 if (lookupPackage(spec, name, flag, &lastpkg) == RPMRC_OK) {
1126 pkg->next = lastpkg->next;
1127 } else {
1128 /* Add package to end of list */
1129 for (lastpkg = spec->packages; lastpkg->next != NULL; lastpkg = lastpkg->next)
1130 {};
1131 }
1132 assert(lastpkg != NULL);
1133 lastpkg->next = pkg;
1134
1135 /* Construct the package */
1136 if (flag == PART_SUBNAME) {
1137 he->tag = RPMTAG_NAME;
1138 xx = headerGet(spec->packages->header, he, 0);
1139 sprintf(NVR, "%s-%s", he->p.str, name);
1140 he->p.ptr = _free(he->p.ptr);
1141 } else
1142 strcpy(NVR, name);
1143 name = _free(name);
1144 he->tag = RPMTAG_NAME;
1145 he->t = RPM_STRING_TYPE;
1146 he->p.str = NVR;
1147 he->c = 1;
1148 xx = headerPut(pkg->header, he, 0);
1149 }
1150
1151 if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
1152 nextPart = PART_NONE;
1153 } else {
1154 if (rc)
1155 return rc;
1156 while ((nextPart = isPart(spec)) == PART_NONE) {
1157 const char * macro = NULL;
1158 rpmTag tag;
1159
1160 /* Skip blank lines */
1161 linep = spec->line;
1162 SKIPSPACE(linep);
1163 if (*linep != '\0') {
1164 if (findPreambleTag(spec, &tag, &macro, lang)) {
1165 rpmlog(RPMLOG_ERR, _("line %d: Unknown tag: %s\n"),
1166 spec->lineNum, spec->line);
1167 return RPMRC_FAIL;
1168 }
1169 if (handlePreambleTag(spec, pkg, tag, macro, lang))
1170 return RPMRC_FAIL;
1171 if (spec->BANames && !spec->recursing && spec->toplevel)
1172 return PART_BUILDARCHITECTURES;
1173 }
1174 if ((rc =
1175 readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
1176 nextPart = PART_NONE;
1177 break;
1178 }
1179 if (rc)
1180 return rc;
1181 }
1182 }
1183
1184 /* Do some final processing on the header */
1185
1186 /*
1187 * Expand buildroot one more time to get %{version} and the like
1188 * from the main package.
1189 */
1190 if (initialPackage) {
1191 const char *s = rpmExpand("%{?buildroot}", NULL);
1192 if (s && *s)
1193 (void) addMacro(NULL, "buildroot", NULL, s, -1);
1194 s = _free(s);
1195 }
1196
1197 /* XXX Skip valid arch check if not building binary package */
1198 if (!spec->anyarch && checkForValidArchitectures(spec))
1199 return RPMRC_FAIL;
1200
1201 if (pkg == spec->packages)
1202 fillOutMainPackage(pkg->header);
1203
1204 if (checkForDuplicates(pkg->header, NVR) != RPMRC_OK)
1205 return RPMRC_FAIL;
1206
1207 if (pkg != spec->packages)
1208 headerCopyTags(spec->packages->header, pkg->header,
1209 (rpmuint32_t *)copyTagsDuringParse);
1210
1211 #ifdef RPM_VENDOR_PLD /* rpm-epoch0 */
1212 /* Add Epoch: 0 to package header if it was not set by spec */
1213 he->tag = RPMTAG_NAME;
1214 if (headerGet(spec->packages->header, he, 0) == 0) {
1215 rpmuint32_t num = 0;
1216
1217 he->tag = RPMTAG_EPOCH;
1218 he->t = RPM_UINT32_TYPE;
1219 he->p.ui32p = &num;
1220 he->c = 1;
1221 xx = headerPut(pkg->header, he, 0);
1222
1223 /* also declare %{epoch} to be same */
1224 addMacro(spec->macros, "epoch", NULL, "0", RMIL_SPEC);
1225 }
1226 #endif /* RPM_VENDOR_PLD rpm-epoch0 */
1227
1228 if (checkForRequired(pkg->header, NVR) != RPMRC_OK)
1229 return RPMRC_FAIL;
1230
1231 return nextPart;
1232 }