upgrade rpm version to 4.14.1
[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 = 1;
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         rpmPushMacro(spec->macros, buf, NULL, body, RMIL_SPEC);
303         free(buf);
304         rasprintf(&buf, "%sURL%d",
305                 (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
306         rpmPushMacro(spec->macros, buf, NULL, p->fullSource, RMIL_SPEC);
307         free(buf);
308 #ifdef WITH_LUA
309         {
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 (!strcmp(arch, "noarch")) {
433         free(arch);
434         arch = rpmExpand("%{_build_cpu}", NULL);
435     }
436     
437     if (isMemberInEntry(spec->buildRestrictions,
438                         arch, RPMTAG_EXCLUDEARCH) == 1) {
439         rpmlog(RPMLOG_ERR, _("Architecture is excluded: %s\n"), arch);
440         goto exit;
441     }
442     if (isMemberInEntry(spec->buildRestrictions,
443                         arch, RPMTAG_EXCLUSIVEARCH) == 0) {
444         rpmlog(RPMLOG_ERR, _("Architecture is not included: %s\n"), arch);
445         goto exit;
446     }
447     if (isMemberInEntry(spec->buildRestrictions,
448                         os, RPMTAG_EXCLUDEOS) == 1) {
449         rpmlog(RPMLOG_ERR, _("OS is excluded: %s\n"), os);
450         goto exit;
451     }
452     if (isMemberInEntry(spec->buildRestrictions,
453                         os, RPMTAG_EXCLUSIVEOS) == 0) {
454         rpmlog(RPMLOG_ERR, _("OS is not included: %s\n"), os);
455         goto exit;
456     }
457     rc = RPMRC_OK;
458
459 exit:
460     free(arch);
461     free(os);
462
463     return rc;
464 }
465
466 /**
467  * Check that required tags are present in header.
468  * @param h             header
469  * @param NVR           package name-version-release
470  * @return              RPMRC_OK if OK
471  */
472 static int checkForRequired(Header h, const char * NVR)
473 {
474     int res = RPMRC_OK;
475     const rpmTagVal * p;
476
477     for (p = requiredTags; *p != 0; p++) {
478         if (!headerIsEntry(h, *p)) {
479             rpmlog(RPMLOG_ERR,
480                         _("%s field must be present in package: %s\n"),
481                         rpmTagGetName(*p), NVR);
482             res = RPMRC_FAIL;
483         }
484     }
485
486     return res;
487 }
488
489 /**
490  * Check that no duplicate tags are present in header.
491  * @param h             header
492  * @param NVR           package name-version-release
493  * @return              RPMRC_OK if OK
494  */
495 static int checkForDuplicates(Header h, const char * NVR)
496 {
497     int res = RPMRC_OK;
498     rpmTagVal tag, lastTag = RPMTAG_NOT_FOUND;
499     HeaderIterator hi = headerInitIterator(h);
500
501     while ((tag = headerNextTag(hi)) != RPMTAG_NOT_FOUND) {
502         if (tag == lastTag) {
503             rpmlog(RPMLOG_ERR, _("Duplicate %s entries in package: %s\n"),
504                      rpmTagGetName(tag), NVR);
505             res = RPMRC_FAIL;
506         }
507         lastTag = tag;
508     }
509     headerFreeIterator(hi);
510
511     return res;
512 }
513
514 /**
515  */
516 static struct optionalTag {
517     rpmTagVal   ot_tag;
518     const char * ot_mac;
519 } const optionalTags[] = {
520     { RPMTAG_VENDOR,            "%{vendor}" },
521     { RPMTAG_PACKAGER,          "%{packager}" },
522     { RPMTAG_DISTRIBUTION,      "%{distribution}" },
523     { RPMTAG_DISTURL,           "%{disturl}" },
524     { RPMTAG_BUGURL,            "%{bugurl}" },
525     { -1, NULL }
526 };
527
528 /**
529  */
530 static void fillOutMainPackage(Header h)
531 {
532     const struct optionalTag *ot;
533
534     for (ot = optionalTags; ot->ot_mac != NULL; ot++) {
535         if (!headerIsEntry(h, ot->ot_tag)) {
536             char *val = rpmExpand(ot->ot_mac, NULL);
537             if (val && *val != '%') {
538                 headerPutString(h, ot->ot_tag, val);
539             }
540             free(val);
541         }
542     }
543 }
544
545 /**
546  */
547 void copyInheritedTags(Header h, Header fromh)
548 {
549     headerCopyTags(fromh, h, (rpmTagVal *)copyTagsDuringParse);
550 }
551
552 /**
553  */
554 static rpmRC readIcon(Header h, const char * file)
555 {
556     char *fn = NULL;
557     uint8_t *icon = NULL;
558     FD_t fd = NULL;
559     rpmRC rc = RPMRC_FAIL; /* assume failure */
560     off_t size;
561     size_t nb, iconsize;
562
563     /* XXX use rpmGenPath(rootdir, "%{_sourcedir}/", file) for icon path. */
564     fn = rpmGetPath("%{_sourcedir}/", file, NULL);
565
566     fd = Fopen(fn, "r.ufdio");
567     if (fd == NULL) {
568         rpmlog(RPMLOG_ERR, _("Unable to open icon %s: %s\n"),
569                 fn, Fstrerror(fd));
570         goto exit;
571     }
572     size = fdSize(fd);
573     iconsize = (size >= 0 ? size : (8 * BUFSIZ));
574     if (iconsize == 0) {
575         rc = RPMRC_OK; /* XXX Eh? */
576         goto exit;
577     }
578
579     icon = xmalloc(iconsize + 1);
580     *icon = '\0';
581
582     nb = Fread(icon, sizeof(icon[0]), iconsize, fd);
583     if (Ferror(fd) || (size >= 0 && nb != size)) {
584         rpmlog(RPMLOG_ERR, _("Unable to read icon %s: %s\n"),
585                 fn, Fstrerror(fd));
586         goto exit;
587     }
588
589     if (rstreqn((char*)icon, "GIF", sizeof("GIF")-1)) {
590         headerPutBin(h, RPMTAG_GIF, icon, iconsize);
591     } else if (rstreqn((char*)icon, "/* XPM", sizeof("/* XPM")-1)) {
592         headerPutBin(h, RPMTAG_XPM, icon, iconsize);
593     } else {
594         rpmlog(RPMLOG_ERR, _("Unknown icon type: %s\n"), file);
595         goto exit;
596     }
597     rc = RPMRC_OK;
598     
599 exit:
600     Fclose(fd);
601     free(fn);
602     free(icon);
603     return rc;
604 }
605
606 #define SINGLE_TOKEN_ONLY \
607 if (multiToken) { \
608     rpmlog(RPMLOG_ERR, _("line %d: Tag takes single token only: %s\n"), \
609              spec->lineNum, spec->line); \
610     return RPMRC_FAIL; \
611 }
612
613 static void specLog(rpmSpec spec, int lvl, const char *line, const char *msg)
614 {
615     if (spec) {
616         rpmlog(lvl, _("line %d: %s in: %s\n"), spec->lineNum, msg, spec->line);
617     } else {
618         rpmlog(lvl, _("%s in: %s\n"), msg, line);
619     }
620 }
621
622 /**
623  * Check for inappropriate characters. All alphanums are considered sane.
624  * @param spec          spec (or NULL)
625  * @param field         string to check
626  * @param whitelist     string of permitted characters
627  * @return              RPMRC_OK if OK
628  */
629 rpmRC rpmCharCheck(rpmSpec spec, const char *field, const char *whitelist)
630 {
631     const char *ch;
632     char *err = NULL;
633     rpmRC rc = RPMRC_OK;
634
635     for (ch=field; *ch; ch++) {
636         if (risalnum(*ch) || strchr(whitelist, *ch)) continue;
637         rasprintf(&err, _("Illegal char '%c' (0x%x)"),
638                   isprint(*ch) ? *ch : '?', *ch);
639     }
640     for (ch=field; *ch; ch++) {
641         if (strchr("%{}", *ch)) {
642             specLog(spec, RPMLOG_WARNING, field,
643                     _("Possible unexpanded macro"));
644             break;
645         }
646     }
647
648     if (err == NULL && strstr(field, "..") != NULL) {
649         rasprintf(&err, _("Illegal sequence \"..\""));
650     }
651
652     if (err) {
653         specLog(spec, RPMLOG_ERR, field, err);
654         free(err);
655         rc = RPMRC_FAIL;
656     }
657     return rc;
658 }
659
660 static int haveLangTag(Header h, rpmTagVal tag, const char *lang)
661 {
662     int rc = 0; /* assume tag not present */
663     int langNum = -1;
664
665     if (lang && *lang) {
666         /* See if the language is in header i18n table */
667         struct rpmtd_s langtd;
668         const char *s = NULL;
669         headerGet(h, RPMTAG_HEADERI18NTABLE, &langtd, HEADERGET_MINMEM);
670         while ((s = rpmtdNextString(&langtd)) != NULL) {
671             if (rstreq(s, lang)) {
672                 langNum = rpmtdGetIndex(&langtd);
673                 break;
674             }
675         }
676         rpmtdFreeData(&langtd);
677     } else {
678         /* C locale */
679         langNum = 0;
680     }
681
682     /* If locale is present, check the actual tag content */
683     if (langNum >= 0) {
684         struct rpmtd_s td;
685         headerGet(h, tag, &td, HEADERGET_MINMEM|HEADERGET_RAW);
686         if (rpmtdSetIndex(&td, langNum) == langNum) {
687             const char *s = rpmtdGetString(&td);
688             /* non-empty string means a dupe */
689             if (s && *s)
690                 rc = 1;
691         }
692         rpmtdFreeData(&td);
693     };
694
695     return rc;
696 }
697
698 int addLangTag(rpmSpec spec, Header h, rpmTagVal tag,
699                       const char *field, const char *lang)
700 {
701     int skip = 0;
702
703     if (haveLangTag(h, tag, lang)) {
704         /* Turn this into an error eventually */
705         rpmlog(RPMLOG_WARNING, _("line %d: second %s\n"),
706                 spec->lineNum, rpmTagGetName(tag));
707     }
708
709     if (!*lang) {
710         headerPutString(h, tag, field);
711     } else {
712         skip = ((spec->flags & RPMSPEC_NOLANG) &&
713                 !rstreq(lang, RPMBUILD_DEFAULT_LANG));
714         if (skip)
715             return 0;
716         headerAddI18NString(h, tag, field, lang);
717     }
718
719     return 0;
720 }
721
722 static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag,
723                 const char *macro, const char *lang)
724 {
725     char * field = spec->line;
726     char * end;
727     int multiToken = 0;
728     rpmsenseFlags tagflags = RPMSENSE_ANY;
729     rpmRC rc = RPMRC_FAIL;
730     
731     if (field == NULL) /* XXX can't happen */
732         goto exit;
733     /* Find the start of the "field" and strip trailing space */
734     while ((*field) && (*field != ':'))
735         field++;
736     if (*field != ':') {
737         rpmlog(RPMLOG_ERR, _("line %d: Malformed tag: %s\n"),
738                  spec->lineNum, spec->line);
739         goto exit;
740     }
741     field++;
742     SKIPSPACE(field);
743     if (!*field) {
744         /* Empty field */
745         rpmlog(RPMLOG_ERR, _("line %d: Empty tag: %s\n"),
746                  spec->lineNum, spec->line);
747         goto exit;
748     }
749     end = findLastChar(field);
750     *(end+1) = '\0';
751
752     /* See if this is multi-token */
753     end = field;
754     SKIPNONSPACE(end);
755     if (*end != '\0')
756         multiToken = 1;
757
758     switch (tag) {
759     case RPMTAG_NAME:
760         SINGLE_TOKEN_ONLY;
761         if (rpmCharCheck(spec, field, WHITELIST_NAME))
762            goto exit;
763         headerPutString(pkg->header, tag, field);
764         /* Main pkg name is unknown at the start, populate as soon as we can */
765         if (pkg == spec->packages)
766             pkg->name = rpmstrPoolId(spec->pool, field, 1);
767         break;
768     case RPMTAG_VERSION:
769     case RPMTAG_RELEASE:
770         SINGLE_TOKEN_ONLY;
771         if (rpmCharCheck(spec, field, "._+%{}~"))
772            goto exit;
773         headerPutString(pkg->header, tag, field);
774         break;
775     case RPMTAG_URL:
776     case RPMTAG_DISTTAG:
777     case RPMTAG_BUGURL:
778     /* XXX TODO: validate format somehow */
779     case RPMTAG_VCS:
780         SINGLE_TOKEN_ONLY;
781         headerPutString(pkg->header, tag, field);
782         break;
783     case RPMTAG_GROUP:
784     case RPMTAG_SUMMARY:
785     case RPMTAG_DISTRIBUTION:
786     case RPMTAG_VENDOR:
787     case RPMTAG_LICENSE:
788     case RPMTAG_PACKAGER:
789         if (addLangTag(spec, pkg->header, tag, field, lang))
790             goto exit;
791         break;
792     case RPMTAG_BUILDROOT:
793         /* just silently ignore BuildRoot */
794         macro = NULL;
795         break;
796     case RPMTAG_PREFIXES: {
797         struct rpmtd_s td;
798         const char *str;
799         if (addOrAppendListEntry(pkg->header, tag, field))
800            goto exit;
801         headerGet(pkg->header, tag, &td, HEADERGET_MINMEM);
802         while ((str = rpmtdNextString(&td))) {
803             size_t len = strlen(str);
804             if (len > 1 && str[len-1] == '/') {
805                 rpmlog(RPMLOG_ERR,
806                          _("line %d: Prefixes must not end with \"/\": %s\n"),
807                          spec->lineNum, spec->line);
808                 rpmtdFreeData(&td);
809                 goto exit;
810             }
811         }
812         rpmtdFreeData(&td);
813         break;
814     }
815     case RPMTAG_DOCDIR:
816         SINGLE_TOKEN_ONLY;
817         if (field[0] != '/') {
818             rpmlog(RPMLOG_ERR, _("line %d: Docdir must begin with '/': %s\n"),
819                      spec->lineNum, spec->line);
820             goto exit;
821         }
822         macro = NULL;
823         rpmPopMacro(NULL, "_docdir");
824         rpmPushMacro(NULL, "_docdir", NULL, field, RMIL_SPEC);
825         break;
826     case RPMTAG_EPOCH: {
827         SINGLE_TOKEN_ONLY;
828         uint32_t epoch;
829         if (parseUnsignedNum(field, &epoch)) {
830             rpmlog(RPMLOG_ERR,
831                    _("line %d: Epoch field must be an unsigned number: %s\n"),
832                    spec->lineNum, spec->line);
833             goto exit;
834         }
835         headerPutUint32(pkg->header, tag, &epoch, 1);
836         break;
837     }
838     case RPMTAG_AUTOREQPROV:
839         pkg->autoReq = parseYesNo(field);
840         pkg->autoProv = pkg->autoReq;
841         break;
842     case RPMTAG_AUTOREQ:
843         pkg->autoReq = parseYesNo(field);
844         break;
845     case RPMTAG_AUTOPROV:
846         pkg->autoProv = parseYesNo(field);
847         break;
848     case RPMTAG_SOURCE:
849     case RPMTAG_PATCH:
850         macro = NULL;
851         if (addSource(spec, pkg, field, tag))
852             goto exit;
853         break;
854     case RPMTAG_ICON:
855         SINGLE_TOKEN_ONLY;
856         if (addSource(spec, pkg, field, tag) || readIcon(pkg->header, field))
857             goto exit;
858         break;
859     case RPMTAG_NOSOURCE:
860     case RPMTAG_NOPATCH:
861         spec->noSource = 1;
862         if (parseNoSource(spec, field, tag))
863             goto exit;
864         break;
865     case RPMTAG_ORDERNAME:
866     case RPMTAG_REQUIRENAME:
867         if (parseBits(lang, installScriptBits, &tagflags)) {
868             rpmlog(RPMLOG_ERR, _("line %d: Bad %s: qualifiers: %s\n"),
869                      spec->lineNum, rpmTagGetName(tag), spec->line);
870             goto exit;
871         }
872         /* fallthrough */
873     case RPMTAG_PREREQ:
874     case RPMTAG_RECOMMENDNAME:
875     case RPMTAG_SUGGESTNAME:
876     case RPMTAG_SUPPLEMENTNAME:
877     case RPMTAG_ENHANCENAME:
878     case RPMTAG_CONFLICTNAME:
879     case RPMTAG_OBSOLETENAME:
880     case RPMTAG_PROVIDENAME:
881         if (parseRCPOT(spec, pkg, field, tag, 0, tagflags, addReqProvPkg, NULL))
882             goto exit;
883         break;
884     case RPMTAG_BUILDPREREQ:
885     case RPMTAG_BUILDREQUIRES:
886     case RPMTAG_BUILDCONFLICTS:
887         if (parseRCPOT(spec, spec->sourcePackage, field, tag, 0, tagflags, addReqProvPkg, NULL))
888             goto exit;
889         break;
890     case RPMTAG_OLDSUGGESTSFLAGS:
891     case RPMTAG_OLDENHANCESFLAGS:
892     case RPMTAG_BUILDSUGGESTS:
893     case RPMTAG_BUILDENHANCES:
894         tagflags = RPMSENSE_MISSINGOK;
895         if (macro && (!strcmp(macro, "recommends") || !strcmp(macro, "buildrecommends")))
896             tagflags |= RPMSENSE_STRONG;
897         if (macro && (!strcmp(macro, "supplements") || !strcmp(macro, "buildsupplements")))
898             tagflags |= RPMSENSE_STRONG;
899         if (parseRCPOT(spec, pkg, field, tag, 0, tagflags, addReqProvPkg, NULL))
900             return rc;
901         break;
902     case RPMTAG_EXCLUDEARCH:
903     case RPMTAG_EXCLUSIVEARCH:
904     case RPMTAG_EXCLUDEOS:
905     case RPMTAG_EXCLUSIVEOS:
906         if (addOrAppendListEntry(spec->buildRestrictions, tag, field))
907            goto exit;
908         break;
909     case RPMTAG_BUILDARCHS: {
910         int BACount;
911         const char **BANames = NULL;
912         if (poptParseArgvString(field, &BACount, &BANames)) {
913             rpmlog(RPMLOG_ERR,
914                      _("line %d: Bad BuildArchitecture format: %s\n"),
915                      spec->lineNum, spec->line);
916             goto exit;
917         }
918         if (spec->packages == pkg) {
919             if (spec->BANames) {
920                 rpmlog(RPMLOG_ERR,
921                        _("line %d: Duplicate BuildArch entry: %s\n"),
922                        spec->lineNum, spec->line);
923                 BANames = _free(BANames);
924                 goto exit;
925             }
926             spec->BACount = BACount;
927             spec->BANames = BANames;
928         } else {
929             if (BACount != 1 || !rstreq(BANames[0], "noarch")) {
930                 rpmlog(RPMLOG_ERR,
931                      _("line %d: Only noarch subpackages are supported: %s\n"),
932                      spec->lineNum, spec->line);
933                 BANames = _free(BANames);
934                 goto exit;
935             }
936             headerPutString(pkg->header, RPMTAG_ARCH, "noarch");
937         }
938         if (!BACount)
939             spec->BANames = _free(spec->BANames);
940         break;
941     }
942     case RPMTAG_REMOVEPATHPOSTFIXES:
943         argvSplit(&pkg->removePostfixes, field, ":");
944         break;
945         case RPMTAG_BUILDINFO:
946         if (addOrAppendListEntry(pkg->header, tag, field))
947            goto exit;
948         break;
949     default:
950         rpmlog(RPMLOG_ERR, _("Internal error: Bogus tag %d\n"), tag);
951         goto exit;
952     }
953
954     if (macro) {
955         rpmPushMacro(spec->macros, macro, NULL, field, RMIL_SPEC);
956         /* Add a separate uppercase macro for tags from the main package */
957         if (pkg == spec->packages) {
958             char *m = xstrdup(macro);
959             for (char *p = m; *p; ++p)
960                 *p = rtoupper(*p);
961             rpmPushMacro(spec->macros, m, NULL, field, RMIL_SPEC);
962             free(m);
963         }
964     }
965     rc = RPMRC_OK;
966 exit:
967     return rc;  
968 }
969
970 /* This table has to be in a peculiar order.  If one tag is the */
971 /* same as another, plus a few letters, it must come first.     */
972
973 /**
974  */
975 typedef const struct PreambleRec_s {
976     rpmTagVal tag;
977     int type;
978     int deprecated;
979     size_t len;
980     const char * token;
981 } * PreambleRec;
982
983 #define LEN_AND_STR(_tag) (sizeof(_tag)-1), _tag
984
985 static struct PreambleRec_s const preambleList[] = {
986     {RPMTAG_NAME,               0, 0, LEN_AND_STR("name")},
987     {RPMTAG_VERSION,            0, 0, LEN_AND_STR("version")},
988     {RPMTAG_RELEASE,            0, 0, LEN_AND_STR("release")},
989     {RPMTAG_EPOCH,              0, 0, LEN_AND_STR("epoch")},
990     {RPMTAG_SUMMARY,            1, 0, LEN_AND_STR("summary")},
991     {RPMTAG_LICENSE,            0, 0, LEN_AND_STR("license")},
992     {RPMTAG_DISTRIBUTION,       0, 0, LEN_AND_STR("distribution")},
993     {RPMTAG_DISTURL,            0, 0, LEN_AND_STR("disturl")},
994     {RPMTAG_VENDOR,             0, 0, LEN_AND_STR("vendor")},
995     {RPMTAG_GROUP,              1, 0, LEN_AND_STR("group")},
996     {RPMTAG_PACKAGER,           0, 0, LEN_AND_STR("packager")},
997     {RPMTAG_URL,                0, 0, LEN_AND_STR("url")},
998     {RPMTAG_VCS,                0, 0, LEN_AND_STR("vcs")},
999     {RPMTAG_SOURCE,             0, 0, LEN_AND_STR("source")},
1000     {RPMTAG_PATCH,              0, 0, LEN_AND_STR("patch")},
1001     {RPMTAG_NOSOURCE,           0, 0, LEN_AND_STR("nosource")},
1002     {RPMTAG_NOPATCH,            0, 0, LEN_AND_STR("nopatch")},
1003     {RPMTAG_EXCLUDEARCH,        0, 0, LEN_AND_STR("excludearch")},
1004     {RPMTAG_EXCLUSIVEARCH,      0, 0, LEN_AND_STR("exclusivearch")},
1005     {RPMTAG_EXCLUDEOS,          0, 0, LEN_AND_STR("excludeos")},
1006     {RPMTAG_EXCLUSIVEOS,        0, 0, LEN_AND_STR("exclusiveos")},
1007     {RPMTAG_ICON,               0, 0, LEN_AND_STR("icon")},
1008     {RPMTAG_PROVIDENAME,        0, 0, LEN_AND_STR("provides")},
1009     {RPMTAG_REQUIRENAME,        2, 0, LEN_AND_STR("requires")},
1010     {RPMTAG_RECOMMENDNAME,      0, 0, LEN_AND_STR("recommends")},
1011     {RPMTAG_SUGGESTNAME,        0, 0, LEN_AND_STR("suggests")},
1012     {RPMTAG_SUPPLEMENTNAME,     0, 0, LEN_AND_STR("supplements")},
1013     {RPMTAG_ENHANCENAME,        0, 0, LEN_AND_STR("enhances")},
1014     {RPMTAG_PREREQ,             2, 1, LEN_AND_STR("prereq")},
1015     {RPMTAG_CONFLICTNAME,       0, 0, LEN_AND_STR("conflicts")},
1016     {RPMTAG_OBSOLETENAME,       0, 0, LEN_AND_STR("obsoletes")},
1017     {RPMTAG_PREFIXES,           0, 0, LEN_AND_STR("prefixes")},
1018     {RPMTAG_PREFIXES,           0, 0, LEN_AND_STR("prefix")},
1019     {RPMTAG_BUILDROOT,          0, 0, LEN_AND_STR("buildroot")},
1020     {RPMTAG_BUILDARCHS,         0, 0, LEN_AND_STR("buildarchitectures")},
1021     {RPMTAG_BUILDARCHS,         0, 0, LEN_AND_STR("buildarch")},
1022     {RPMTAG_BUILDCONFLICTS,     0, 0, LEN_AND_STR("buildconflicts")},
1023     {RPMTAG_BUILDPREREQ,        0, 1, LEN_AND_STR("buildprereq")},
1024     {RPMTAG_BUILDREQUIRES,      0, 0, LEN_AND_STR("buildrequires")},
1025     {RPMTAG_AUTOREQPROV,        0, 0, LEN_AND_STR("autoreqprov")},
1026     {RPMTAG_AUTOREQ,            0, 0, LEN_AND_STR("autoreq")},
1027     {RPMTAG_AUTOPROV,           0, 0, LEN_AND_STR("autoprov")},
1028     {RPMTAG_DOCDIR,             0, 0, LEN_AND_STR("docdir")},
1029     {RPMTAG_DISTTAG,            0, 0, LEN_AND_STR("disttag")},
1030     {RPMTAG_BUGURL,             0, 0, LEN_AND_STR("bugurl")},
1031     {RPMTAG_ORDERFLAGS,         2, 0, LEN_AND_STR("orderwithrequires")},
1032     {RPMTAG_OLDSUGGESTSFLAGS,   0, 0, LEN_AND_STR("recommends")},
1033     {RPMTAG_OLDSUGGESTSFLAGS,   0, 0, LEN_AND_STR("suggests")},
1034     {RPMTAG_OLDENHANCESFLAGS,   0, 0, LEN_AND_STR("supplements")},
1035     {RPMTAG_OLDENHANCESFLAGS,   0, 0, LEN_AND_STR("enhances")},
1036     {RPMTAG_BUILDSUGGESTS,      0, 0, LEN_AND_STR("buildrecommends")},
1037     {RPMTAG_BUILDSUGGESTS,      0, 0, LEN_AND_STR("buildsuggests")},
1038     {RPMTAG_BUILDENHANCES,      0, 0, LEN_AND_STR("buildsupplements")},
1039     {RPMTAG_BUILDENHANCES,      0, 0, LEN_AND_STR("buildenhances")},
1040     {RPMTAG_SECMANIFEST,        0, 0, LEN_AND_STR("manifest")},
1041     {RPMTAG_ORDERNAME,          2, 0, LEN_AND_STR("orderwithrequires")},
1042     {RPMTAG_REMOVEPATHPOSTFIXES,0, 0, LEN_AND_STR("removepathpostfixes")},
1043     {RPMTAG_BUILDINFO,         0, 0, LEN_AND_STR("buildinfo")},
1044     {0, 0, 0, 0}
1045 };
1046
1047 /**
1048  */
1049 static int findPreambleTag(rpmSpec spec,rpmTagVal * tag,
1050                 const char ** macro, char * lang)
1051 {
1052     PreambleRec p;
1053     char *s;
1054
1055     for (p = preambleList; p->token != NULL; p++) {
1056         if (!(p->token && !rstrncasecmp(spec->line, p->token, p->len)))
1057             continue;
1058         if (p->deprecated) {
1059             rpmlog(RPMLOG_WARNING, _("line %d: %s is deprecated: %s\n"),
1060                         spec->lineNum, p->token, spec->line);
1061         }
1062         break;
1063     }
1064     if (p == NULL || p->token == NULL)
1065         return 1;
1066
1067     s = spec->line + p->len;
1068     SKIPSPACE(s);
1069
1070     switch (p->type) {
1071     default:
1072     case 0:
1073         /* Unless this is a source or a patch, a ':' better be next */
1074         if (p->tag != RPMTAG_SOURCE && p->tag != RPMTAG_PATCH) {
1075             if (*s != ':') return 1;
1076         }
1077         *lang = '\0';
1078         break;
1079     case 1:     /* Parse optional ( <token> ). */
1080     case 2:
1081         if (*s == ':') {
1082             /* Type 1 is multilang, 2 is qualifiers with no defaults */
1083             strcpy(lang, (p->type == 1) ? RPMBUILD_DEFAULT_LANG : "");
1084             break;
1085         }
1086         if (*s != '(') return 1;
1087         s++;
1088         SKIPSPACE(s);
1089         while (!risspace(*s) && *s != ')')
1090             *lang++ = *s++;
1091         *lang = '\0';
1092         SKIPSPACE(s);
1093         if (*s != ')') return 1;
1094         s++;
1095         SKIPSPACE(s);
1096         if (*s != ':') return 1;
1097         break;
1098     }
1099
1100     *tag = p->tag;
1101     if (macro)
1102         *macro = p->token;
1103     return 0;
1104 }
1105
1106 int parsePreamble(rpmSpec spec, int initialPackage)
1107 {
1108     int nextPart = PART_ERROR;
1109     int res = PART_ERROR; /* assume failure */
1110     int rc;
1111     char *name, *linep;
1112     int flag = 0;
1113     Package pkg;
1114     char *NVR = NULL;
1115     char lang[BUFSIZ];
1116
1117     if (! initialPackage) {
1118         /* There is one option to %package: <pkg> or -n <pkg> */
1119         if (parseSimplePart(spec->line, &name, &flag)) {
1120             rpmlog(RPMLOG_ERR, _("Bad package specification: %s\n"),
1121                         spec->line);
1122             goto exit;
1123         }
1124
1125         //if (rpmCharCheck(spec, name, WHITELIST_NAME))
1126         //    goto exit;
1127         
1128         if (!lookupPackage(spec, name, flag, NULL)) {
1129             free(name);
1130             goto exit;
1131         }
1132         
1133         /* Construct the package */
1134         if (flag == PART_SUBNAME) {
1135             rasprintf(&NVR, "%s-%s", 
1136                     headerGetString(spec->packages->header, RPMTAG_NAME), name);
1137         } else
1138             NVR = xstrdup(name);
1139         free(name);
1140         pkg = newPackage(NVR, spec->pool, &spec->packages);
1141         headerPutString(pkg->header, RPMTAG_NAME, NVR);
1142     } else {
1143         NVR = xstrdup("(main package)");
1144         pkg = newPackage(NULL, spec->pool, &spec->packages);
1145         spec->sourcePackage = newPackage(NULL, spec->pool, NULL);
1146         
1147     }
1148
1149     if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
1150         nextPart = PART_NONE;
1151     } else if (rc < 0) {
1152         goto exit;
1153     } else {
1154         while (! (nextPart = isPart(spec->line))) {
1155             const char * macro;
1156             rpmTagVal tag;
1157
1158             /* Skip blank lines */
1159             linep = spec->line;
1160             SKIPSPACE(linep);
1161             if (*linep != '\0') {
1162                 if (findPreambleTag(spec, &tag, &macro, lang)) {
1163                     if (spec->lineNum == 1 &&
1164                         (unsigned char)(spec->line[0]) == 0xed &&
1165                         (unsigned char)(spec->line[1]) == 0xab &&
1166                         (unsigned char)(spec->line[2]) == 0xee &&
1167                         (unsigned char)(spec->line[3]) == 0xdb) {
1168                         rpmlog(RPMLOG_ERR, _("Binary rpm package found. Expected spec file!\n"));
1169                         goto exit;
1170                     }
1171                     rpmlog(RPMLOG_ERR, _("line %d: Unknown tag: %s\n"),
1172                                 spec->lineNum, spec->line);
1173                     goto exit;
1174                 }
1175                 if (handlePreambleTag(spec, pkg, tag, macro, lang)) {
1176                     goto exit;
1177                 }
1178                 if (spec->BANames && !spec->recursing) {
1179                     res = PART_BUILDARCHITECTURES;
1180                     goto exit;
1181                 }
1182             }
1183             if ((rc =
1184                  readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
1185                 nextPart = PART_NONE;
1186                 break;
1187             }
1188             if (rc) {
1189                 goto exit;
1190             }
1191         }
1192     }
1193
1194     /* 
1195      * Expand buildroot one more time to get %{version} and the like
1196      * from the main package, validate sanity. The spec->buildRoot could
1197      * still contain unexpanded macros but it cannot be empty or '/', and it
1198      * can't be messed with by anything spec does beyond this point.
1199      */
1200     if (initialPackage) {
1201         char *buildRoot = rpmGetPath(spec->buildRoot, NULL);
1202         if (*buildRoot == '\0') {
1203             rpmlog(RPMLOG_ERR, _("%%{buildroot} couldn't be empty\n"));
1204             goto exit;
1205         }
1206         if (rstreq(buildRoot, "/")) {
1207             rpmlog(RPMLOG_ERR, _("%%{buildroot} can not be \"/\"\n"));
1208             goto exit;
1209         }
1210         free(spec->buildRoot);
1211         spec->buildRoot = buildRoot;
1212         rpmPushMacro(spec->macros, "buildroot", NULL, spec->buildRoot, RMIL_SPEC);
1213     }
1214
1215     /* XXX Skip valid arch check if not building binary package */
1216     if (!(spec->flags & RPMSPEC_ANYARCH) && checkForValidArchitectures(spec)) {
1217         goto exit;
1218     }
1219
1220     /* It is the main package */
1221     if (pkg == spec->packages) {
1222         fillOutMainPackage(pkg->header);
1223         /* Define group tag to something when group is undefined in main package*/
1224         if (!headerIsEntry(pkg->header, RPMTAG_GROUP)) {
1225             headerPutString(pkg->header, RPMTAG_GROUP, "Unspecified");
1226         }
1227     }
1228
1229     if (checkForDuplicates(pkg->header, NVR)) {
1230         goto exit;
1231     }
1232
1233     if (pkg != spec->packages) {
1234         copyInheritedTags(pkg->header, spec->packages->header);
1235     }
1236
1237     if (checkForRequired(pkg->header, NVR)) {
1238         goto exit;
1239     }
1240
1241     /* if we get down here nextPart has been set to non-error */
1242     res = nextPart;
1243
1244 exit:
1245     free(NVR);
1246     return res;
1247 }