Add macro %isu_package to generate ISU Package
[platform/upstream/rpm.git] / build / parsePreamble.c
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     0
47 };
48
49 /**
50  */
51 static const rpmTagVal requiredTags[] = {
52     RPMTAG_NAME,
53     RPMTAG_VERSION,
54     RPMTAG_RELEASE,
55     RPMTAG_SUMMARY,
56     RPMTAG_LICENSE,
57     0
58 };
59
60 /**
61  */
62 static rpmRC addOrAppendListEntry(Header h, rpmTagVal tag, const char * line)
63 {
64     int xx;
65     int argc;
66     const char **argv;
67
68     if ((xx = poptParseArgvString(line, &argc, &argv))) {
69         rpmlog(RPMLOG_ERR, _("Error parsing tag field: %s\n"), poptStrerror(xx));
70         return RPMRC_FAIL;
71     }
72     if (argc) 
73         headerPutStringArray(h, tag, argv, argc);
74     argv = _free(argv);
75
76     return RPMRC_OK;
77 }
78
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 */
81
82 /**
83  */
84 static int parseSimplePart(const char *line, char **name, int *flag)
85 {
86     char *tok;
87     char *linebuf = xstrdup(line);
88     int rc;
89
90     /* Throw away the first token (the %xxxx) */
91     (void)strtok(linebuf, " \t\n");
92     *name = NULL;
93
94     if (!(tok = strtok(NULL, " \t\n"))) {
95         rc = 0;
96         goto exit;
97     }
98     
99     if (rstreq(tok, "-n")) {
100         if (!(tok = strtok(NULL, " \t\n"))) {
101             rc = 1;
102             goto exit;
103         }
104         *flag = PART_NAME;
105     } else {
106         *flag = PART_SUBNAME;
107     }
108     *name = xstrdup(tok);
109     rc = strtok(NULL, " \t\n") ? 1 : 0;
110
111 exit:
112     free(linebuf);
113     return rc;
114 }
115
116 /**
117  */
118 static inline int parseYesNo(const char * s)
119 {
120     return ((!s || (s[0] == 'n' || s[0] == 'N' || s[0] == '0') ||
121         !rstrcasecmp(s, "false") || !rstrcasecmp(s, "off"))
122             ? 0 : 1);
123 }
124
125 static struct Source *findSource(rpmSpec spec, uint32_t num, int flag)
126 {
127     struct Source *p;
128
129     for (p = spec->sources; p != NULL; p = p->next)
130         if ((num == p->num) && (p->flags & flag)) return p;
131
132     return NULL;
133 }
134
135 static int parseNoSource(rpmSpec spec, const char * field, rpmTagVal tag)
136 {
137     const char *f, *fe;
138     const char *name;
139     int flag;
140     uint32_t num;
141
142     if (tag == RPMTAG_NOSOURCE) {
143         flag = RPMBUILD_ISSOURCE;
144         name = "source";
145     } else {
146         flag = RPMBUILD_ISPATCH;
147         name = "patch";
148     }
149     
150     fe = field;
151     for (f = fe; *f != '\0'; f = fe) {
152         struct Source *p;
153
154         SKIPWHITE(f);
155         if (*f == '\0')
156             break;
157         fe = f;
158         SKIPNONWHITE(fe);
159         if (*fe != '\0') fe++;
160
161         if (parseUnsignedNum(f, &num)) {
162             rpmlog(RPMLOG_ERR, _("line %d: Bad number: %s\n"),
163                      spec->lineNum, f);
164             return RPMRC_FAIL;
165         }
166
167         if (! (p = findSource(spec, num, flag))) {
168             rpmlog(RPMLOG_ERR, _("line %d: Bad no%s number: %u\n"),
169                      spec->lineNum, name, num);
170             return RPMRC_FAIL;
171         }
172
173         p->flags |= RPMBUILD_ISNO;
174
175     }
176
177     return 0;
178 }
179
180 static int addSource(rpmSpec spec, Package pkg, const char *field, rpmTagVal tag)
181 {
182     struct Source *p;
183     int flag = 0;
184     const char *name = NULL;
185     char *nump;
186     char *fieldp = NULL;
187     char *buf = NULL;
188     uint32_t num = 0;
189
190     switch (tag) {
191       case RPMTAG_SOURCE:
192         flag = RPMBUILD_ISSOURCE;
193         name = "source";
194         fieldp = spec->line + 6;
195         break;
196       case RPMTAG_PATCH:
197         flag = RPMBUILD_ISPATCH;
198         name = "patch";
199         fieldp = spec->line + 5;
200         break;
201       case RPMTAG_ICON:
202         flag = RPMBUILD_ISICON;
203         fieldp = NULL;
204         break;
205       default:
206         return -1;
207         break;
208     }
209
210     /* Get the number */
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 ':'                            */
216         char ch;
217         char *fieldp_backup = fieldp;
218
219         while ((*fieldp != ':') && (*fieldp != ' ') && (*fieldp != '\t')) {
220             fieldp++;
221         }
222         ch = *fieldp;
223         *fieldp = '\0';
224
225         nump = fieldp_backup;
226         SKIPSPACE(nump);
227         if (nump == NULL || *nump == '\0') {
228             num = flag == RPMBUILD_ISSOURCE ? 0 : INT_MAX;
229         } else {
230             if (parseUnsignedNum(fieldp_backup, &num)) {
231                 rpmlog(RPMLOG_ERR, _("line %d: Bad %s number: %s\n"),
232                          spec->lineNum, name, spec->line);
233                 *fieldp = ch;
234                 return RPMRC_FAIL;
235             }
236         }
237         *fieldp = ch;
238     }
239
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);
246                 return RPMRC_FAIL;
247             }
248     }
249
250     /* Create the entry and link it in */
251     p = xmalloc(sizeof(*p));
252     p->num = num;
253     p->fullSource = xstrdup(field);
254     p->flags = flag;
255     p->source = strrchr(p->fullSource, '/');
256     if (p->source) {
257         if ((buf = strrchr(p->source,'='))) p->source = buf;
258         p->source++;
259     } else {
260         p->source = p->fullSource;
261     }
262
263     if (tag != RPMTAG_ICON) {
264         p->next = spec->sources;
265         spec->sources = p;
266     } else {
267         p->next = pkg->icon;
268         pkg->icon = p;
269     }
270
271     spec->numSources++;
272
273     if (tag != RPMTAG_ICON) {
274         char *body = rpmGetPath("%{_sourcedir}/", p->source, NULL);
275         struct stat st;
276         int nofetch = (spec->flags & RPMSPEC_FORCE) ||
277                       rpmExpandNumeric("%{_disable_source_fetch}");
278
279         /* try to download source/patch if it's missing */
280         if (lstat(body, &st) != 0 && errno == ENOENT && !nofetch) {
281             char *url = NULL;
282             if (urlIsURL(p->fullSource) != URL_IS_UNKNOWN) {
283                 url = rstrdup(p->fullSource);
284             } else {
285                 url = rpmExpand("%{_default_source_url}", NULL);
286                 rstrcat(&url, p->source);
287                 if (*url == '%') url = _free(url);
288             }
289             if (url) {
290                 rpmlog(RPMLOG_WARNING, _("Downloading %s to %s\n"), url, body);
291                 if (urlGetFile(url, body) != 0) {
292                     free(url);
293                     rpmlog(RPMLOG_ERR, _("Couldn't download %s\n"), p->fullSource);
294                     return RPMRC_FAIL;
295                 }
296                 free(url);
297             }
298         }
299
300         rasprintf(&buf, "%s%d",
301                 (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
302         addMacro(spec->macros, buf, NULL, body, RMIL_SPEC);
303         free(buf);
304         rasprintf(&buf, "%sURL%d",
305                 (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
306         addMacro(spec->macros, buf, NULL, p->fullSource, RMIL_SPEC);
307         free(buf);
308 #ifdef WITH_LUA
309         if (!spec->recursing) {
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);
317             rpmluavFree(var);
318             rpmluaPop(lua);
319         }
320 #endif
321         free(body);
322     }
323     
324     return 0;
325 }
326
327 typedef const struct tokenBits_s {
328     const char * name;
329     rpmsenseFlags bits;
330 } * tokenBits;
331
332 /**
333  */
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 },
346     { NULL, 0 }
347 };
348
349 /**
350  */
351 static int parseBits(const char * s, const tokenBits tokbits,
352                 rpmsenseFlags * bp)
353 {
354     tokenBits tb;
355     const char * se;
356     rpmsenseFlags bits = RPMSENSE_ANY;
357     int c = 0;
358     int rc = RPMRC_OK;
359
360     if (s) {
361         while (*s != '\0') {
362             while ((c = *s) && risspace(c)) s++;
363             se = s;
364             while ((c = *se) && risalpha(c)) se++;
365             if (s == se)
366                 break;
367             for (tb = tokbits; tb->name; tb++) {
368                 if (tb->name != NULL &&
369                     strlen(tb->name) == (se-s) && rstreqn(tb->name, s, (se-s)))
370                     break;
371             }
372             if (tb->name == NULL) {
373                 rc = RPMRC_FAIL;
374                 break;
375             }
376             bits |= tb->bits;
377             while ((c = *se) && risspace(c)) se++;
378             if (c != ',')
379                 break;
380             s = ++se;
381         }
382     }
383     *bp |= bits;
384     return rc;
385 }
386
387 /**
388  */
389 static inline char * findLastChar(char * s)
390 {
391     char *res = s;
392
393     while (*s != '\0') {
394         if (! risspace(*s))
395             res = s;
396         s++;
397     }
398
399     return res;
400 }
401
402 /**
403  */
404 static int isMemberInEntry(Header h, const char *name, rpmTagVal tag)
405 {
406     struct rpmtd_s td;
407     int found = 0;
408     const char *str;
409
410     if (!headerGet(h, tag, &td, HEADERGET_MINMEM))
411         return -1;
412
413     while ((str = rpmtdNextString(&td))) {
414         if (!rstrcasecmp(str, name)) {
415             found = 1;
416             break;
417         }
418     }
419     rpmtdFreeData(&td);
420
421     return found;
422 }
423
424 /**
425  */
426 static rpmRC checkForValidArchitectures(rpmSpec spec)
427 {
428     char *arch = rpmExpand("%{_target_cpu}", NULL);
429     char *os = rpmExpand("%{_target_os}", NULL);
430     rpmRC rc = RPMRC_FAIL; /* assume failure */
431     
432     if (isMemberInEntry(spec->buildRestrictions,
433                         arch, RPMTAG_EXCLUDEARCH) == 1) {
434         rpmlog(RPMLOG_ERR, _("Architecture is excluded: %s\n"), arch);
435         goto exit;
436     }
437     if (isMemberInEntry(spec->buildRestrictions,
438                         arch, RPMTAG_EXCLUSIVEARCH) == 0) {
439         rpmlog(RPMLOG_ERR, _("Architecture is not included: %s\n"), arch);
440         goto exit;
441     }
442     if (isMemberInEntry(spec->buildRestrictions,
443                         os, RPMTAG_EXCLUDEOS) == 1) {
444         rpmlog(RPMLOG_ERR, _("OS is excluded: %s\n"), os);
445         goto exit;
446     }
447     if (isMemberInEntry(spec->buildRestrictions,
448                         os, RPMTAG_EXCLUSIVEOS) == 0) {
449         rpmlog(RPMLOG_ERR, _("OS is not included: %s\n"), os);
450         goto exit;
451     }
452     rc = RPMRC_OK;
453
454 exit:
455     free(arch);
456     free(os);
457
458     return rc;
459 }
460
461 /**
462  * Check that required tags are present in header.
463  * @param h             header
464  * @param NVR           package name-version-release
465  * @return              RPMRC_OK if OK
466  */
467 static int checkForRequired(Header h, const char * NVR)
468 {
469     int res = RPMRC_OK;
470     const rpmTagVal * p;
471
472     for (p = requiredTags; *p != 0; p++) {
473         if (!headerIsEntry(h, *p)) {
474             rpmlog(RPMLOG_ERR,
475                         _("%s field must be present in package: %s\n"),
476                         rpmTagGetName(*p), NVR);
477             res = RPMRC_FAIL;
478         }
479     }
480
481     return res;
482 }
483
484 /**
485  * Check that no duplicate tags are present in header.
486  * @param h             header
487  * @param NVR           package name-version-release
488  * @return              RPMRC_OK if OK
489  */
490 static int checkForDuplicates(Header h, const char * NVR)
491 {
492     int res = RPMRC_OK;
493     rpmTagVal tag, lastTag = RPMTAG_NOT_FOUND;
494     HeaderIterator hi = headerInitIterator(h);
495
496     while ((tag = headerNextTag(hi)) != RPMTAG_NOT_FOUND) {
497         if (tag == lastTag) {
498             rpmlog(RPMLOG_ERR, _("Duplicate %s entries in package: %s\n"),
499                      rpmTagGetName(tag), NVR);
500             res = RPMRC_FAIL;
501         }
502         lastTag = tag;
503     }
504     headerFreeIterator(hi);
505
506     return res;
507 }
508
509 /**
510  */
511 static struct optionalTag {
512     rpmTagVal   ot_tag;
513     const char * ot_mac;
514 } const optionalTags[] = {
515     { RPMTAG_VENDOR,            "%{vendor}" },
516     { RPMTAG_PACKAGER,          "%{packager}" },
517     { RPMTAG_DISTRIBUTION,      "%{distribution}" },
518     { RPMTAG_DISTURL,           "%{disturl}" },
519     { RPMTAG_BUGURL,            "%{bugurl}" },
520     { -1, NULL }
521 };
522
523 /**
524  */
525 static void fillOutMainPackage(Header h)
526 {
527     const struct optionalTag *ot;
528
529     for (ot = optionalTags; ot->ot_mac != NULL; ot++) {
530         if (!headerIsEntry(h, ot->ot_tag)) {
531             char *val = rpmExpand(ot->ot_mac, NULL);
532             if (val && *val != '%') {
533                 headerPutString(h, ot->ot_tag, val);
534             }
535             free(val);
536         }
537     }
538 }
539
540 /**
541  */
542 static rpmRC readIcon(Header h, const char * file)
543 {
544     char *fn = NULL;
545     uint8_t *icon = NULL;
546     FD_t fd = NULL;
547     rpmRC rc = RPMRC_FAIL; /* assume failure */
548     off_t size;
549     size_t nb, iconsize;
550
551     /* XXX use rpmGenPath(rootdir, "%{_sourcedir}/", file) for icon path. */
552     fn = rpmGetPath("%{_sourcedir}/", file, NULL);
553
554     fd = Fopen(fn, "r.ufdio");
555     if (fd == NULL) {
556         rpmlog(RPMLOG_ERR, _("Unable to open icon %s: %s\n"),
557                 fn, Fstrerror(fd));
558         goto exit;
559     }
560     size = fdSize(fd);
561     iconsize = (size >= 0 ? size : (8 * BUFSIZ));
562     if (iconsize == 0) {
563         rc = RPMRC_OK; /* XXX Eh? */
564         goto exit;
565     }
566
567     icon = xmalloc(iconsize + 1);
568     *icon = '\0';
569
570     nb = Fread(icon, sizeof(icon[0]), iconsize, fd);
571     if (Ferror(fd) || (size >= 0 && nb != size)) {
572         rpmlog(RPMLOG_ERR, _("Unable to read icon %s: %s\n"),
573                 fn, Fstrerror(fd));
574         goto exit;
575     }
576
577     if (rstreqn((char*)icon, "GIF", sizeof("GIF")-1)) {
578         headerPutBin(h, RPMTAG_GIF, icon, iconsize);
579     } else if (rstreqn((char*)icon, "/* XPM", sizeof("/* XPM")-1)) {
580         headerPutBin(h, RPMTAG_XPM, icon, iconsize);
581     } else {
582         rpmlog(RPMLOG_ERR, _("Unknown icon type: %s\n"), file);
583         goto exit;
584     }
585     rc = RPMRC_OK;
586     
587 exit:
588     Fclose(fd);
589     free(fn);
590     free(icon);
591     return rc;
592 }
593
594 #define SINGLE_TOKEN_ONLY \
595 if (multiToken) { \
596     rpmlog(RPMLOG_ERR, _("line %d: Tag takes single token only: %s\n"), \
597              spec->lineNum, spec->line); \
598     return RPMRC_FAIL; \
599 }
600
601 /**
602  * Check for inappropriate characters. All alphanums are considered sane.
603  * @param spec          spec
604  * @param field         string to check
605  * @param fsize         size of string to check
606  * @param whitelist     string of permitted characters
607  * @return              RPMRC_OK if OK
608  */
609 rpmRC rpmCharCheck(rpmSpec spec, const char *field, size_t fsize, const char *whitelist)
610 {
611     const char *ch, *stop = &field[fsize];
612
613     for (ch=field; *ch && ch < stop; ch++) {
614         if (risalnum(*ch) || strchr(whitelist, *ch)) continue;
615         if (isprint(*ch)) {
616             rpmlog(RPMLOG_ERR, _("line %d: Illegal char '%c' in: %s\n"),
617                 spec->lineNum, *ch, spec->line);
618         } else {
619             rpmlog(RPMLOG_ERR, _("line %d: Illegal char in: %s\n"),
620                 spec->lineNum, spec->line);
621         }
622         return RPMRC_FAIL;
623     }
624     if (strstr(field, "..") != NULL) {
625         rpmlog(RPMLOG_ERR, _("line %d: Illegal sequence \"..\" in: %s\n"),
626             spec->lineNum, spec->line);
627         return RPMRC_FAIL;
628     }
629     
630     return RPMRC_OK;
631 }
632
633 static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag,
634                 const char *macro, const char *lang)
635 {
636     char * field = spec->line;
637     char * end;
638     int multiToken = 0;
639     rpmsenseFlags tagflags = RPMSENSE_ANY;
640     rpmRC rc = RPMRC_FAIL;
641     
642     if (field == NULL) /* XXX can't happen */
643         goto exit;
644     /* Find the start of the "field" and strip trailing space */
645     while ((*field) && (*field != ':'))
646         field++;
647     if (*field != ':') {
648         rpmlog(RPMLOG_ERR, _("line %d: Malformed tag: %s\n"),
649                  spec->lineNum, spec->line);
650         goto exit;
651     }
652     field++;
653     SKIPSPACE(field);
654     if (!*field) {
655         /* Empty field */
656         rpmlog(RPMLOG_ERR, _("line %d: Empty tag: %s\n"),
657                  spec->lineNum, spec->line);
658         goto exit;
659     }
660     end = findLastChar(field);
661     *(end+1) = '\0';
662
663     /* See if this is multi-token */
664     end = field;
665     SKIPNONSPACE(end);
666     if (*end != '\0')
667         multiToken = 1;
668
669     switch (tag) {
670     case RPMTAG_NAME:
671         SINGLE_TOKEN_ONLY;
672         if (rpmCharCheck(spec, field, strlen(field), ".-_+%{}"))
673            goto exit;
674         headerPutString(pkg->header, tag, field);
675         break;
676     case RPMTAG_VERSION:
677     case RPMTAG_RELEASE:
678         SINGLE_TOKEN_ONLY;
679         if (rpmCharCheck(spec, field, strlen(field), "._+%{}~"))
680            goto exit;
681         headerPutString(pkg->header, tag, field);
682         break;
683     case RPMTAG_URL:
684     case RPMTAG_DISTTAG:
685     case RPMTAG_BUGURL:
686     /* XXX TODO: validate format somehow */
687     case RPMTAG_VCS:
688         SINGLE_TOKEN_ONLY;
689         headerPutString(pkg->header, tag, field);
690         break;
691     case RPMTAG_GROUP:
692     case RPMTAG_SUMMARY:
693     case RPMTAG_DISTRIBUTION:
694     case RPMTAG_VENDOR:
695     case RPMTAG_LICENSE:
696     case RPMTAG_PACKAGER:
697         if (!*lang) {
698             headerPutString(pkg->header, tag, field);
699         } else if (!((spec->flags & RPMSPEC_NOLANG) &&
700                    !rstreq(lang, RPMBUILD_DEFAULT_LANG)))
701             headerAddI18NString(pkg->header, tag, field, lang);
702         break;
703     case RPMTAG_BUILDROOT:
704         /* just silently ignore BuildRoot */
705         macro = NULL;
706         break;
707     case RPMTAG_PREFIXES: {
708         struct rpmtd_s td;
709         const char *str;
710         if (addOrAppendListEntry(pkg->header, tag, field))
711            goto exit;
712         headerGet(pkg->header, tag, &td, HEADERGET_MINMEM);
713         while ((str = rpmtdNextString(&td))) {
714             size_t len = strlen(str);
715             if (len > 1 && str[len-1] == '/') {
716                 rpmlog(RPMLOG_ERR,
717                          _("line %d: Prefixes must not end with \"/\": %s\n"),
718                          spec->lineNum, spec->line);
719                 rpmtdFreeData(&td);
720                 goto exit;
721             }
722         }
723         rpmtdFreeData(&td);
724         break;
725     }
726     case RPMTAG_DOCDIR:
727         SINGLE_TOKEN_ONLY;
728         if (field[0] != '/') {
729             rpmlog(RPMLOG_ERR, _("line %d: Docdir must begin with '/': %s\n"),
730                      spec->lineNum, spec->line);
731             goto exit;
732         }
733         macro = NULL;
734         delMacro(NULL, "_docdir");
735         addMacro(NULL, "_docdir", NULL, field, RMIL_SPEC);
736         break;
737     case RPMTAG_EPOCH: {
738         SINGLE_TOKEN_ONLY;
739         uint32_t epoch;
740         if (parseUnsignedNum(field, &epoch)) {
741             rpmlog(RPMLOG_ERR,
742                    _("line %d: Epoch field must be an unsigned number: %s\n"),
743                    spec->lineNum, spec->line);
744             goto exit;
745         }
746         headerPutUint32(pkg->header, tag, &epoch, 1);
747         break;
748     }
749     case RPMTAG_AUTOREQPROV:
750         pkg->autoReq = parseYesNo(field);
751         pkg->autoProv = pkg->autoReq;
752         break;
753     case RPMTAG_AUTOREQ:
754         pkg->autoReq = parseYesNo(field);
755         break;
756     case RPMTAG_AUTOPROV:
757         pkg->autoProv = parseYesNo(field);
758         break;
759     case RPMTAG_SOURCE:
760     case RPMTAG_PATCH:
761         macro = NULL;
762         if (addSource(spec, pkg, field, tag))
763             goto exit;
764         break;
765     case RPMTAG_ICON:
766         SINGLE_TOKEN_ONLY;
767         if (addSource(spec, pkg, field, tag) || readIcon(pkg->header, field))
768             goto exit;
769         break;
770     case RPMTAG_NOSOURCE:
771     case RPMTAG_NOPATCH:
772         spec->noSource = 1;
773         if (parseNoSource(spec, field, tag))
774             goto exit;
775         break;
776     case RPMTAG_ORDERFLAGS:
777     case RPMTAG_REQUIREFLAGS:
778         if (parseBits(lang, installScriptBits, &tagflags)) {
779             rpmlog(RPMLOG_ERR, _("line %d: Bad %s: qualifiers: %s\n"),
780                      spec->lineNum, rpmTagGetName(tag), spec->line);
781             goto exit;
782         }
783         /* fallthrough */
784     case RPMTAG_PREREQ:
785     case RPMTAG_BUILDPREREQ:
786     case RPMTAG_BUILDREQUIRES:
787     case RPMTAG_BUILDCONFLICTS:
788     case RPMTAG_CONFLICTFLAGS:
789     case RPMTAG_OBSOLETEFLAGS:
790     case RPMTAG_PROVIDEFLAGS:
791         if (parseRCPOT(spec, pkg, field, tag, 0, tagflags))
792             goto exit;
793         break;
794     case RPMTAG_SUGGESTSFLAGS:
795     case RPMTAG_ENHANCESFLAGS:
796     case RPMTAG_BUILDSUGGESTS:
797     case RPMTAG_BUILDENHANCES:
798         tagflags = RPMSENSE_MISSINGOK;
799         if (macro && (!strcmp(macro, "recommends") || !strcmp(macro, "buildrecommends")))
800             tagflags |= RPMSENSE_STRONG;
801         if (macro && (!strcmp(macro, "supplements") || !strcmp(macro, "buildsupplements")))
802             tagflags |= RPMSENSE_STRONG;
803         if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
804             return rc;
805         break;
806     case RPMTAG_EXCLUDEARCH:
807     case RPMTAG_EXCLUSIVEARCH:
808     case RPMTAG_EXCLUDEOS:
809     case RPMTAG_EXCLUSIVEOS:
810         if (addOrAppendListEntry(spec->buildRestrictions, tag, field))
811            goto exit;
812         break;
813     case RPMTAG_BUILDARCHS: {
814         int BACount;
815         const char **BANames = NULL;
816         if (poptParseArgvString(field, &BACount, &BANames)) {
817             rpmlog(RPMLOG_ERR,
818                      _("line %d: Bad BuildArchitecture format: %s\n"),
819                      spec->lineNum, spec->line);
820             goto exit;
821         }
822         if (spec->packages == pkg) {
823             spec->BACount = BACount;
824             spec->BANames = BANames;
825         } else {
826             if (BACount != 1 || !rstreq(BANames[0], "noarch")) {
827                 rpmlog(RPMLOG_ERR,
828                      _("line %d: Only noarch subpackages are supported: %s\n"),
829                      spec->lineNum, spec->line);
830                 BANames = _free(BANames);
831                 goto exit;
832             }
833             headerPutString(pkg->header, RPMTAG_ARCH, "noarch");
834         }
835         if (!BACount)
836             spec->BANames = _free(spec->BANames);
837         break;
838     }
839     case RPMTAG_COLLECTIONS:
840     case RPMTAG_BUILDINFO:
841         if (addOrAppendListEntry(pkg->header, tag, field))
842            goto exit;
843         break;
844     default:
845         rpmlog(RPMLOG_ERR, _("Internal error: Bogus tag %d\n"), tag);
846         goto exit;
847     }
848
849     if (macro)
850         addMacro(spec->macros, macro, NULL, field, RMIL_SPEC);
851     rc = RPMRC_OK;
852 exit:
853     return rc;  
854 }
855
856 /* This table has to be in a peculiar order.  If one tag is the */
857 /* same as another, plus a few letters, it must come first.     */
858
859 /**
860  */
861 typedef const struct PreambleRec_s {
862     rpmTagVal tag;
863     int type;
864     int deprecated;
865     size_t len;
866     const char * token;
867 } * PreambleRec;
868
869 #define LEN_AND_STR(_tag) (sizeof(_tag)-1), _tag
870
871 static struct PreambleRec_s const preambleList[] = {
872     {RPMTAG_NAME,               0, 0, LEN_AND_STR("name")},
873     {RPMTAG_VERSION,            0, 0, LEN_AND_STR("version")},
874     {RPMTAG_RELEASE,            0, 0, LEN_AND_STR("release")},
875     {RPMTAG_EPOCH,              0, 0, LEN_AND_STR("epoch")},
876     {RPMTAG_SUMMARY,            1, 0, LEN_AND_STR("summary")},
877     {RPMTAG_LICENSE,            0, 0, LEN_AND_STR("license")},
878     {RPMTAG_DISTRIBUTION,       0, 0, LEN_AND_STR("distribution")},
879     {RPMTAG_DISTURL,            0, 0, LEN_AND_STR("disturl")},
880     {RPMTAG_VENDOR,             0, 0, LEN_AND_STR("vendor")},
881     {RPMTAG_GROUP,              1, 0, LEN_AND_STR("group")},
882     {RPMTAG_PACKAGER,           0, 0, LEN_AND_STR("packager")},
883     {RPMTAG_URL,                0, 0, LEN_AND_STR("url")},
884     {RPMTAG_VCS,        0, 0, LEN_AND_STR("vcs")},
885     {RPMTAG_SOURCE,             0, 0, LEN_AND_STR("source")},
886     {RPMTAG_PATCH,              0, 0, LEN_AND_STR("patch")},
887     {RPMTAG_NOSOURCE,           0, 0, LEN_AND_STR("nosource")},
888     {RPMTAG_NOPATCH,            0, 0, LEN_AND_STR("nopatch")},
889     {RPMTAG_EXCLUDEARCH,        0, 0, LEN_AND_STR("excludearch")},
890     {RPMTAG_EXCLUSIVEARCH,      0, 0, LEN_AND_STR("exclusivearch")},
891     {RPMTAG_EXCLUDEOS,          0, 0, LEN_AND_STR("excludeos")},
892     {RPMTAG_EXCLUSIVEOS,        0, 0, LEN_AND_STR("exclusiveos")},
893     {RPMTAG_ICON,               0, 0, LEN_AND_STR("icon")},
894     {RPMTAG_PROVIDEFLAGS,       0, 0, LEN_AND_STR("provides")},
895     {RPMTAG_REQUIREFLAGS,       2, 0, LEN_AND_STR("requires")},
896     {RPMTAG_PREREQ,             2, 1, LEN_AND_STR("prereq")},
897     {RPMTAG_CONFLICTFLAGS,      0, 0, LEN_AND_STR("conflicts")},
898     {RPMTAG_OBSOLETEFLAGS,      0, 0, LEN_AND_STR("obsoletes")},
899     {RPMTAG_PREFIXES,           0, 0, LEN_AND_STR("prefixes")},
900     {RPMTAG_PREFIXES,           0, 0, LEN_AND_STR("prefix")},
901     {RPMTAG_BUILDROOT,          0, 0, LEN_AND_STR("buildroot")},
902     {RPMTAG_BUILDARCHS,         0, 0, LEN_AND_STR("buildarchitectures")},
903     {RPMTAG_BUILDARCHS,         0, 0, LEN_AND_STR("buildarch")},
904     {RPMTAG_BUILDCONFLICTS,     0, 0, LEN_AND_STR("buildconflicts")},
905     {RPMTAG_BUILDPREREQ,        0, 1, LEN_AND_STR("buildprereq")},
906     {RPMTAG_BUILDREQUIRES,      0, 0, LEN_AND_STR("buildrequires")},
907     {RPMTAG_AUTOREQPROV,        0, 0, LEN_AND_STR("autoreqprov")},
908     {RPMTAG_AUTOREQ,            0, 0, LEN_AND_STR("autoreq")},
909     {RPMTAG_AUTOPROV,           0, 0, LEN_AND_STR("autoprov")},
910     {RPMTAG_DOCDIR,             0, 0, LEN_AND_STR("docdir")},
911     {RPMTAG_DISTTAG,            0, 0, LEN_AND_STR("disttag")},
912     {RPMTAG_BUGURL,             0, 0, LEN_AND_STR("bugurl")},
913     {RPMTAG_COLLECTIONS,        0, 0, LEN_AND_STR("collections")},
914     {RPMTAG_ORDERFLAGS,         2, 0, LEN_AND_STR("orderwithrequires")},
915     {RPMTAG_SUGGESTSFLAGS,      0, 0, LEN_AND_STR("recommends")},
916     {RPMTAG_SUGGESTSFLAGS,      0, 0, LEN_AND_STR("suggests")},
917     {RPMTAG_ENHANCESFLAGS,      0, 0, LEN_AND_STR("supplements")},
918     {RPMTAG_ENHANCESFLAGS,      0, 0, LEN_AND_STR("enhances")},
919     {RPMTAG_BUILDSUGGESTS,      0, 0, LEN_AND_STR("buildrecommends")},
920     {RPMTAG_BUILDSUGGESTS,      0, 0, LEN_AND_STR("buildsuggests")},
921     {RPMTAG_BUILDENHANCES,      0, 0, LEN_AND_STR("buildsupplements")},
922     {RPMTAG_BUILDENHANCES,      0, 0, LEN_AND_STR("buildenhances")},
923     {RPMTAG_SECMANIFEST,        0, 0, LEN_AND_STR("manifest")},
924     {RPMTAG_BUILDINFO,          0, 0, LEN_AND_STR("buildinfo")},
925     {0, 0, 0, 0}
926 };
927
928 /**
929  */
930 static int findPreambleTag(rpmSpec spec,rpmTagVal * tag,
931                 const char ** macro, char * lang)
932 {
933     PreambleRec p;
934     char *s;
935
936     for (p = preambleList; p->token != NULL; p++) {
937         if (!(p->token && !rstrncasecmp(spec->line, p->token, p->len)))
938             continue;
939         if (p->deprecated) {
940             rpmlog(RPMLOG_WARNING, _("line %d: %s is deprecated: %s\n"),
941                         spec->lineNum, p->token, spec->line);
942         }
943         break;
944     }
945     if (p == NULL || p->token == NULL)
946         return 1;
947
948     s = spec->line + p->len;
949     SKIPSPACE(s);
950
951     switch (p->type) {
952     default:
953     case 0:
954         /* Unless this is a source or a patch, a ':' better be next */
955         if (p->tag != RPMTAG_SOURCE && p->tag != RPMTAG_PATCH) {
956             if (*s != ':') return 1;
957         }
958         *lang = '\0';
959         break;
960     case 1:     /* Parse optional ( <token> ). */
961     case 2:
962         if (*s == ':') {
963             /* Type 1 is multilang, 2 is qualifiers with no defaults */
964             strcpy(lang, (p->type == 1) ? RPMBUILD_DEFAULT_LANG : "");
965             break;
966         }
967         if (*s != '(') return 1;
968         s++;
969         SKIPSPACE(s);
970         while (!risspace(*s) && *s != ')')
971             *lang++ = *s++;
972         *lang = '\0';
973         SKIPSPACE(s);
974         if (*s != ')') return 1;
975         s++;
976         SKIPSPACE(s);
977         if (*s != ':') return 1;
978         break;
979     }
980
981     *tag = p->tag;
982     if (macro)
983         *macro = p->token;
984     return 0;
985 }
986
987 int parsePreamble(rpmSpec spec, int initialPackage)
988 {
989     int nextPart = PART_ERROR;
990     int res = PART_ERROR; /* assume failure */
991     int rc;
992     char *name, *linep;
993     int flag = 0;
994     Package pkg;
995     char *NVR = NULL;
996     char lang[BUFSIZ];
997
998     pkg = newPackage(spec);
999         
1000     if (! initialPackage) {
1001         /* There is one option to %package: <pkg> or -n <pkg> */
1002         if (parseSimplePart(spec->line, &name, &flag)) {
1003             rpmlog(RPMLOG_ERR, _("Bad package specification: %s\n"),
1004                         spec->line);
1005             goto exit;
1006         }
1007         
1008         if (!lookupPackage(spec, name, flag, NULL)) {
1009             rpmlog(RPMLOG_ERR, _("Package already exists: %s\n"), spec->line);
1010             free(name);
1011             goto exit;
1012         }
1013         
1014         /* Construct the package */
1015         if (flag == PART_SUBNAME) {
1016             rasprintf(&NVR, "%s-%s", 
1017                     headerGetString(spec->packages->header, RPMTAG_NAME), name);
1018         } else
1019             NVR = xstrdup(name);
1020         free(name);
1021         headerPutString(pkg->header, RPMTAG_NAME, NVR);
1022     } else {
1023         NVR = xstrdup("(main package)");
1024     }
1025
1026     if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
1027         nextPart = PART_NONE;
1028     } else if (rc < 0) {
1029         goto exit;
1030     } else {
1031         while (! (nextPart = isPart(spec->line))) {
1032             const char * macro;
1033             rpmTagVal tag;
1034
1035             /* Skip blank lines */
1036             linep = spec->line;
1037             SKIPSPACE(linep);
1038             if (*linep != '\0') {
1039                 if (findPreambleTag(spec, &tag, &macro, lang)) {
1040                     rpmlog(RPMLOG_ERR, _("line %d: Unknown tag: %s\n"),
1041                                 spec->lineNum, spec->line);
1042                     goto exit;
1043                 }
1044                 if (handlePreambleTag(spec, pkg, tag, macro, lang)) {
1045                     goto exit;
1046                 }
1047                 if (spec->BANames && !spec->recursing) {
1048                     res = PART_BUILDARCHITECTURES;
1049                     goto exit;
1050                 }
1051             }
1052             if ((rc =
1053                  readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
1054                 nextPart = PART_NONE;
1055                 break;
1056             }
1057             if (rc) {
1058                 goto exit;
1059             }
1060         }
1061     }
1062
1063     /*
1064      * Expand buildroot one more time to get %{version} and the like
1065      * from the main package, validate sanity. The spec->buildRoot could
1066      * still contain unexpanded macros but it cannot be empty or '/', and it
1067      * can't be messed with by anything spec does beyond this point.
1068      */
1069     if (initialPackage) {
1070         char *buildRoot = rpmGetPath(spec->buildRoot, NULL);
1071         if (*buildRoot == '\0') {
1072             rpmlog(RPMLOG_ERR, _("%%{buildroot} couldn't be empty\n"));
1073             goto exit;
1074         }
1075         if (rstreq(buildRoot, "/")) {
1076             rpmlog(RPMLOG_ERR, _("%%{buildroot} can not be \"/\"\n"));
1077             goto exit;
1078         }
1079         free(spec->buildRoot);
1080         spec->buildRoot = buildRoot;
1081         addMacro(spec->macros, "buildroot", NULL, spec->buildRoot, RMIL_SPEC);
1082     }
1083
1084     /* XXX Skip valid arch check if not building binary package */
1085     if (!(spec->flags & RPMSPEC_ANYARCH) && checkForValidArchitectures(spec)) {
1086         goto exit;
1087     }
1088
1089     /* It is the main package */
1090     if (pkg == spec->packages) {
1091         fillOutMainPackage(pkg->header);
1092         /* Define group tag to something when group is undefined in main package*/
1093         if (!headerIsEntry(pkg->header, RPMTAG_GROUP)) {
1094             headerPutString(pkg->header, RPMTAG_GROUP, "Unspecified");
1095         }
1096     }
1097
1098     if (checkForDuplicates(pkg->header, NVR)) {
1099         goto exit;
1100     }
1101
1102     if (pkg != spec->packages) {
1103         headerCopyTags(spec->packages->header, pkg->header,
1104                         (rpmTagVal *)copyTagsDuringParse);
1105     }
1106
1107     if (checkForRequired(pkg->header, NVR)) {
1108         goto exit;
1109     }
1110
1111     /* if we get down here nextPart has been set to non-error */
1112     res = nextPart;
1113
1114 exit:
1115     free(NVR);
1116     return res;
1117 }