rpm  5.4.10
parseSpec.c
Go to the documentation of this file.
1 
6 #include "system.h"
7 
8 #include <rpmio_internal.h> /* XXX fdGetFp */
9 #include <rpmcb.h>
10 #include <argv.h>
11 
12 #define _RPMTAG_INTERNAL /* XXX rpmTags->aTags */
13 #include <rpmbuild.h>
14 #include "rpmds.h"
15 #include "rpmts.h"
16 #include "debug.h"
17 
18 /*@access headerTagIndices @*/
19 /*@access FD_t @*/ /* compared with NULL */
20 
23 /*@unchecked@*/
24 static struct PartRec {
26  size_t len;
27 /*@observer@*/ /*@null@*/
28  const char * token;
29 } partList[] = {
30  { PART_PREAMBLE, 0, "%package"},
31  { PART_PREP, 0, "%prep"},
32  { PART_BUILD, 0, "%build"},
33  { PART_INSTALL, 0, "%install"},
34  { PART_CHECK, 0, "%check"},
35  { PART_CLEAN, 0, "%clean"},
36  { PART_PREUN, 0, "%preun"},
37  { PART_POSTUN, 0, "%postun"},
38  { PART_PRETRANS, 0, "%pretrans"},
39  { PART_POSTTRANS, 0, "%posttrans"},
40  { PART_PRE, 0, "%pre"},
41  { PART_POST, 0, "%post"},
42  { PART_FILES, 0, "%files"},
43  { PART_CHANGELOG, 0, "%changelog"},
44  { PART_DESCRIPTION, 0, "%description"},
45  { PART_TRIGGERPOSTUN, 0, "%triggerpostun"},
46  { PART_TRIGGERPREIN, 0, "%triggerprein"},
47  { PART_TRIGGERUN, 0, "%triggerun"},
48  { PART_TRIGGERIN, 0, "%triggerin"},
49  { PART_TRIGGERIN, 0, "%trigger"},
50  { PART_TRIGGERPRETRANSIN,0, "%triggerpretransin"},
51  { PART_TRIGGERPRETRANSUN,0, "%triggerpretransun"},
52  { PART_TRIGGERPOSTTRANSIN,0, "%triggerposttransin"},
53  { PART_TRIGGERPOSTTRANSUN,0, "%triggerposttransun"},
54  { PART_VERIFYSCRIPT, 0, "%verifyscript"},
55  { PART_SANITYCHECK, 0, "%sanitycheck"}, /* support "%sanitycheck" scriptlet */
56  {0, 0, NULL}
57 };
58 
61 static inline void initParts(struct PartRec *p)
62  /*@modifies p->len @*/
63 {
64  for (; p->token != NULL; p++)
65  p->len = strlen(p->token);
66 }
67 
69 {
70  const char * line = spec->line;
71  struct PartRec *p;
72  rpmParseState nextPart = PART_NONE; /* assume plain text */
73 
74  if (partList[0].len == 0)
76 
77  for (p = partList; p->token != NULL; p++) {
78  char c;
79  if (xstrncasecmp(line, p->token, p->len))
80  continue;
81  c = *(line + p->len);
82  if (c == '\0' || xisspace(c)) {
83  nextPart = p->part;
84  goto exit;
85  }
86  }
87 
88  /* If %foo is not found explicitly, check for an arbitrary %foo tag. */
89  if (line[0] == '%') {
90  ARGV_t aTags = NULL;
91  const char * s;
92 /*@-noeffect@*/
93  (void) tagName(0); /* XXX force arbitrary tags to be initialized. */
94 /*@=noeffect@*/
95  aTags = rpmTags->aTags;
96  if (aTags != NULL && aTags[0] != NULL) {
97  ARGV_t av;
98  s = tagCanonicalize(line+1); /* XXX +1 to skip leading '%' */
99 #if defined(RPM_VENDOR_OPENPKG) /* wildcard-matching-arbitrary-tagnames */
100  av = argvSearchLinear(aTags, s, argvFnmatchCasefold);
101 #else
102  av = argvSearch(aTags, s, argvStrcasecmp);
103 #endif
104  if (av != NULL) {
105  spec->foo = xrealloc(spec->foo, (spec->nfoo + 1) * sizeof(*spec->foo));
106  spec->foo[spec->nfoo].str = xstrdup(s);
107  spec->foo[spec->nfoo].tag = tagGenerate(s);
108  spec->foo[spec->nfoo].iob = NULL;
109  spec->nfoo++;
110  nextPart = PART_ARBITRARY;
111  }
112  s = _free(s);
113  }
114  }
115 
116 exit:
117  return nextPart;
118 }
119 
122 static int matchTok(const char *token, const char *line)
123  /*@*/
124 {
125  const char *b, *be = line;
126  size_t toklen = strlen(token);
127  int rc = 0;
128 
129  while ( *(b = be) != '\0' ) {
130  SKIPSPACE(b);
131  be = b;
132  SKIPNONSPACE(be);
133  if (be == b)
134  break;
135  if (toklen != (size_t)(be-b) || xstrncasecmp(token, b, (be-b)))
136  continue;
137  rc = 1;
138  break;
139  }
140 
141  return rc;
142 }
143 
144 void handleComments(char *s)
145 {
146  SKIPSPACE(s);
147  if (*s == '#')
148  *s = '\0';
149 }
150 
153 static void forceIncludeFile(Spec spec, const char * fileName)
154  /*@modifies spec->fileStack @*/
155 {
156  OFI_t * ofi;
157 
158  ofi = newOpenFileInfo();
159  ofi->fileName = xstrdup(fileName);
160  ofi->next = spec->fileStack;
161  spec->fileStack = ofi;
162 }
163 
166 static int restoreFirstChar(Spec spec)
167  /*@modifies spec->nextline, spec->nextpeekc @*/
168 {
169  /* Restore 1st char in (possible) next line */
170  if (spec->nextline != NULL && spec->nextpeekc != '\0') {
171  *spec->nextline = spec->nextpeekc;
172  spec->nextpeekc = '\0';
173  return 1;
174  }
175  return 0;
176 }
177 
180 static int copyNextLineFromOFI(Spec spec, OFI_t * ofi, rpmStripFlags strip)
181  /*@globals rpmGlobalMacroContext, h_errno,
182  fileSystem, internalState @*/
183  /*@modifies spec->nextline, spec->lbuf, spec->lbufPtr,
184  ofi->readPtr,
185  rpmGlobalMacroContext, fileSystem, internalState @*/
186 {
187  char ch;
188 
189  /* Expand next line from file into line buffer */
190  if (!(spec->nextline && *spec->nextline)) {
191  int pc = 0, bc = 0, nc = 0;
192  char *from, *to, *p;
193  to = spec->lbufPtr ? spec->lbufPtr : spec->lbuf;
194  from = ofi->readPtr;
195  ch = ' ';
196  while (from && *from && ch != '\n')
197  ch = *to++ = *from++;
198 /*@-mods@*/
199  spec->lbufPtr = to;
200 /*@=mods@*/
201  *to++ = '\0';
202  ofi->readPtr = from;
203 
204  /* Check if we need another line before expanding the buffer. */
205  for (p = spec->lbuf; *p; p++) {
206  switch (*p) {
207  case '\\':
208  switch (*(p+1)) {
209  case '\n': p++, nc = 1; /*@innerbreak@*/ break;
210  case '\0': /*@innerbreak@*/ break;
211  default: p++; /*@innerbreak@*/ break;
212  }
213  /*@switchbreak@*/ break;
214  case '\n': nc = 0; /*@switchbreak@*/ break;
215  case '%':
216  switch (*(p+1)) {
217  case '{': p++, bc++; /*@innerbreak@*/ break;
218  case '(': p++, pc++; /*@innerbreak@*/ break;
219  case '%': p++; /*@innerbreak@*/ break;
220  }
221  /*@switchbreak@*/ break;
222  case '{': if (bc > 0) bc++; /*@switchbreak@*/ break;
223  case '}': if (bc > 0) bc--; /*@switchbreak@*/ break;
224  case '(': if (pc > 0) pc++; /*@switchbreak@*/ break;
225  case ')': if (pc > 0) pc--; /*@switchbreak@*/ break;
226  }
227  }
228 
229  /* If it doesn't, ask for one more line. We need a better
230  * error code for this. */
231  if (pc || bc || nc ) {
232 /*@-observertrans -readonlytrans@*/
233  spec->nextline = "";
234 /*@=observertrans =readonlytrans@*/
235  return RPMRC_FAIL;
236  }
237 /*@-mods@*/
238  spec->lbufPtr = spec->lbuf;
239 /*@=mods@*/
240 
241  /* Don't expand macros (eg. %define) in false branch of %if clause */
242  /* Also don't expand macros in %changelog if STRIP_NOEXPAND is set */
243  /* (first line is omitted, so %date macro will be expanded */
244  if (!(strip & STRIP_NOEXPAND)) {
245  if (spec->readStack->reading &&
246  expandMacros(spec, spec->macros, spec->lbuf, spec->lbuf_len)) {
247  rpmlog(RPMLOG_ERR, _("line %d: %s\n"),
248  spec->lineNum, spec->lbuf);
249  return RPMRC_FAIL;
250  }
251  }
252  spec->nextline = spec->lbuf;
253  }
254  return 0;
255 }
256 
259 static int copyNextLineFinish(Spec spec, int strip)
260  /*@modifies spec->line, spec->nextline, spec->nextpeekc @*/
261 {
262  char *last;
263  char ch;
264 
265  /* Find next line in expanded line buffer */
266  spec->line = last = spec->nextline;
267  ch = ' ';
268  while (*spec->nextline && ch != '\n') {
269  ch = *spec->nextline++;
270  if (!xisspace(ch))
271  last = spec->nextline;
272  }
273 
274  /* Save 1st char of next line in order to terminate current line. */
275  if (*spec->nextline != '\0') {
276  spec->nextpeekc = *spec->nextline;
277  *spec->nextline = '\0';
278  }
279 
280  if (strip & STRIP_COMMENTS)
281  handleComments(spec->line);
282 
283  if (strip & STRIP_TRAILINGSPACE)
284  *last = '\0';
285 
286  return 0;
287 }
288 
291 static int readLineFromOFI(Spec spec, OFI_t *ofi)
292  /*@globals h_errno, fileSystem, internalState @*/
293  /*@modifies ofi, spec->fileStack, spec->lineNum, spec->sl,
294  fileSystem, internalState @*/
295 {
296 retry:
297  /* Make sure the current file is open */
298  if (ofi->fd == NULL) {
299  ofi->fd = Fopen(ofi->fileName, "r.fpio");
300  if (ofi->fd == NULL || Ferror(ofi->fd)) {
301  /* XXX Fstrerror */
302  rpmlog(RPMLOG_ERR, _("Unable to open %s: %s\n"),
303  ofi->fileName, Fstrerror(ofi->fd));
304  return RPMRC_FAIL;
305  }
306  spec->lineNum = ofi->lineNum = 0;
307  }
308 
309  /* Make sure we have something in the read buffer */
310  if (!(ofi->readPtr && *(ofi->readPtr))) {
311  /*@-type@*/ /* FIX: cast? */
312  FILE * f = fdGetFp(ofi->fd);
313  /*@=type@*/
314  if (f == NULL || !fgets(ofi->readBuf, (int)sizeof(ofi->readBuf), f)) {
315  /* EOF */
316  if (spec->readStack->next) {
317  rpmlog(RPMLOG_ERR, _("Unclosed %%if\n"));
318  return RPMRC_FAIL;
319  }
320 
321  /* remove this file from the stack */
322  spec->fileStack = ofi->next;
323  (void) Fclose(ofi->fd);
324  ofi->fileName = _free(ofi->fileName);
325 /*@-temptrans@*/
326  ofi = _free(ofi);
327 /*@=temptrans@*/
328 
329  /* only on last file do we signal EOF to caller */
330  ofi = spec->fileStack;
331  if (ofi == NULL)
332  return 1;
333 
334  /* otherwise, go back and try the read again. */
335  goto retry;
336  }
337  ofi->readPtr = ofi->readBuf;
338  ofi->lineNum++;
339  spec->lineNum = ofi->lineNum;
340  if (spec->sl) {
341  speclines sl = spec->sl;
342  if (sl->sl_nlines == sl->sl_nalloc) {
343  sl->sl_nalloc += 100;
344  sl->sl_lines = (char **) xrealloc(sl->sl_lines,
345  sl->sl_nalloc * sizeof(*(sl->sl_lines)));
346  }
347  sl->sl_lines[sl->sl_nlines++] = xstrdup(ofi->readBuf);
348  }
349  }
350  return 0;
351 }
352 
353 int readLine(Spec spec, rpmStripFlags strip)
354 {
355  char *s;
356  int match;
357  struct ReadLevelEntry *rl;
358  OFI_t *ofi = spec->fileStack;
359  int rc;
360 
361  if (ofi == NULL) /* XXX segfault avoidance */
362  return 1;
363  if (!restoreFirstChar(spec)) {
364  retry:
365  if ((rc = readLineFromOFI(spec, ofi)) != 0)
366  return rc;
367 
368  /* Copy next file line into the spec line buffer */
369 
370  if ((rc = copyNextLineFromOFI(spec, ofi, strip)) != 0) {
371  if (rc == RPMRC_FAIL)
372  goto retry;
373  return rc;
374  }
375  }
376 
377  (void) copyNextLineFinish(spec, strip);
378 
379  s = spec->line;
380  SKIPSPACE(s);
381 
382  match = -1;
383  if (!(strip & STRIP_NOEXPAND)) {
384  if (!spec->readStack->reading && !strncmp("%if", s, sizeof("%if")-1)) {
385  match = 0;
386  } else if (! strncmp("%ifarch", s, sizeof("%ifarch")-1)) {
387  const char *arch = rpmExpand("%{_target_cpu}", NULL);
388  s += 7;
389  match = matchTok(arch, s);
390  arch = _free(arch);
391  } else if (! strncmp("%ifnarch", s, sizeof("%ifnarch")-1)) {
392  const char *arch = rpmExpand("%{_target_cpu}", NULL);
393  s += 8;
394  match = !matchTok(arch, s);
395  arch = _free(arch);
396  } else if (! strncmp("%ifos", s, sizeof("%ifos")-1)) {
397  const char *os = rpmExpand("%{_target_os}", NULL);
398  s += 5;
399  match = matchTok(os, s);
400  os = _free(os);
401  } else if (! strncmp("%ifnos", s, sizeof("%ifnos")-1)) {
402  const char *os = rpmExpand("%{_target_os}", NULL);
403  s += 6;
404  match = !matchTok(os, s);
405  os = _free(os);
406  } else if (! strncmp("%if", s, sizeof("%if")-1)) {
407  s += 3;
408  match = parseExpressionBoolean(spec, s);
409  if (match < 0) {
411  _("%s:%d: parseExpressionBoolean returns %d\n"),
412  ofi->fileName, ofi->lineNum, match);
413  return RPMRC_FAIL;
414  }
415  } else if (! strncmp("%else", s, sizeof("%else")-1)) {
416  s += 5;
417  if (! spec->readStack->next) {
418  /* Got an else with no %if ! */
420  _("%s:%d: Got a %%else with no %%if\n"),
421  ofi->fileName, ofi->lineNum);
422  return RPMRC_FAIL;
423  }
424  spec->readStack->reading =
425  spec->readStack->next->reading && ! spec->readStack->reading;
426  spec->line[0] = '\0';
427  } else if (! strncmp("%endif", s, sizeof("%endif")-1)) {
428  s += 6;
429  if (! spec->readStack->next) {
430  /* Got an end with no %if ! */
432  _("%s:%d: Got a %%endif with no %%if\n"),
433  ofi->fileName, ofi->lineNum);
434  return RPMRC_FAIL;
435  }
436  rl = spec->readStack;
437  spec->readStack = spec->readStack->next;
438  free(rl);
439  spec->line[0] = '\0';
440  } else if (spec->readStack->reading && ! strncmp("%include", s, sizeof("%include")-1)) {
441  char *fileName, *endFileName, *p;
442 
443  s += 8;
444  fileName = s;
445  if (! xisspace(*fileName)) {
446  rpmlog(RPMLOG_ERR, _("malformed %%include statement\n"));
447  return RPMRC_FAIL;
448  }
449  SKIPSPACE(fileName);
450  endFileName = fileName;
451  SKIPNONSPACE(endFileName);
452  p = endFileName;
453  SKIPSPACE(p);
454  if (*p != '\0') {
455  rpmlog(RPMLOG_ERR, _("malformed %%include statement\n"));
456  return RPMRC_FAIL;
457  }
458  *endFileName = '\0';
459 
460  forceIncludeFile(spec, fileName);
461 
462  ofi = spec->fileStack;
463  goto retry;
464  }
465  }
466 
467  if (match != -1) {
468  rl = xmalloc(sizeof(*rl));
469  rl->reading = spec->readStack->reading && match;
470  rl->next = spec->readStack;
471  spec->readStack = rl;
472  spec->line[0] = '\0';
473  }
474 
475  if (! spec->readStack->reading) {
476  spec->line[0] = '\0';
477  }
478 
479  /*@-compmempass@*/ /* FIX: spec->readStack->next should be dependent */
480  return 0;
481  /*@=compmempass@*/
482 }
483 
484 void closeSpec(Spec spec)
485 {
486  OFI_t *ofi;
487 
488  while (spec->fileStack) {
489  ofi = spec->fileStack;
490  spec->fileStack = spec->fileStack->next;
491  if (ofi->fd) (void) Fclose(ofi->fd);
492  ofi->fileName = _free(ofi->fileName);
493  ofi = _free(ofi);
494  }
495 }
496 
499 static inline int genSourceRpmName(Spec spec)
500  /*@globals internalState @*/
501  /*@modifies spec->sourceRpmName, spec->packages->header,
502  internalState @*/
503 {
504  if (spec->sourceRpmName == NULL) {
505  const char *N, *V, *R;
506  char fileName[BUFSIZ];
507 
508  (void) headerNEVRA(spec->packages->header, &N, NULL, &V, &R, NULL);
509  (void) snprintf(fileName, sizeof(fileName), "%s-%s-%s.%ssrc.rpm",
510  N, V, R, spec->noSource ? "no" : "");
511  fileName[sizeof(fileName)-1] = '\0';
512  N = _free(N);
513  V = _free(V);
514  R = _free(R);
515  spec->sourceRpmName = xstrdup(fileName);
516  }
517 
518  return 0;
519 }
520 
521 /*@-redecl@*/
522 /*@unchecked@*/
523 extern int noLang; /* XXX FIXME: pass as arg */
524 /*@=redecl@*/
525 
526 /*@todo Skip parse recursion if os is not compatible. @*/
527 int parseSpec(rpmts ts, const char *specFile, const char *rootURL,
528  int recursing, const char *passPhrase,
529  const char *cookie, int anyarch, int force, int verify)
530 {
531  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
532  rpmParseState parsePart = PART_PREAMBLE;
533  int initialPackage = 1;
534  Package pkg;
535  Spec spec;
536  int xx;
537 
538  /* Set up a new Spec structure with no packages. */
539  spec = newSpec();
540 
541  /*
542  * Note: rpmGetPath should guarantee a "canonical" path. That means
543  * that the following pathologies should be weeded out:
544  * //bin//sh
545  * //usr//bin/
546  * /.././../usr/../bin//./sh (XXX FIXME: dots not handled yet)
547  */
548  spec->specFile = rpmGetPath(specFile, NULL);
549  addMacro(spec->macros, "_specfile", NULL, spec->specFile, RMIL_SPEC);
550  spec->fileStack = newOpenFileInfo();
551  spec->fileStack->fileName = xstrdup(spec->specFile);
552 
553  spec->recursing = recursing;
554  spec->toplevel = (!recursing ? 1 : 0);
555  spec->anyarch = anyarch;
556  spec->force = force;
557 
558  if (rootURL)
559  spec->rootURL = xstrdup(rootURL);
560  if (passPhrase)
561  spec->passPhrase = xstrdup(passPhrase);
562  if (cookie)
563  spec->cookie = xstrdup(cookie);
564 
565  spec->timeCheck = rpmExpandNumeric("%{_timecheck}");
566 
567  /* XXX %_docdir should be set somewhere else. */
568  addMacro(NULL, "_docdir", NULL, "%{_defaultdocdir}", RMIL_SPEC);
569 
570  /* All the parse*() functions expect to have a line pre-read */
571  /* in the spec's line buffer. Except for parsePreamble(), */
572  /* which handles the initial entry into a spec file. */
573 
574  /*@-infloops@*/ /* LCL: parsePart is modified @*/
575  while (parsePart > PART_NONE) {
576  int goterror = 0;
577 
578  switch (parsePart) {
579  default:
580  goterror = 1;
581  /*@switchbreak@*/ break;
582  case PART_PREAMBLE:
583  parsePart = parsePreamble(spec, initialPackage);
584  initialPackage = 0;
585  /*@switchbreak@*/ break;
586  case PART_PREP:
587  parsePart = parsePrep(spec, verify);
588  /*@switchbreak@*/ break;
589  case PART_BUILD:
590  case PART_INSTALL:
591  case PART_CHECK:
592  case PART_CLEAN:
593  case PART_ARBITRARY:
594  parsePart = parseBuildInstallClean(spec, parsePart);
595  /*@switchbreak@*/ break;
596  case PART_CHANGELOG:
597  parsePart = parseChangelog(spec);
598  /*@switchbreak@*/ break;
599  case PART_DESCRIPTION:
600  parsePart = parseDescription(spec);
601  /*@switchbreak@*/ break;
602 
603  case PART_PRE:
604  case PART_POST:
605  case PART_PREUN:
606  case PART_POSTUN:
607  case PART_PRETRANS:
608  case PART_POSTTRANS:
609  case PART_VERIFYSCRIPT:
610  case PART_SANITYCHECK:
611  case PART_TRIGGERPREIN:
612  case PART_TRIGGERIN:
613  case PART_TRIGGERUN:
614  case PART_TRIGGERPOSTUN:
619  parsePart = parseScript(spec, parsePart);
620  /*@switchbreak@*/ break;
621 
622  case PART_FILES:
623  parsePart = parseFiles(spec);
624  /*@switchbreak@*/ break;
625 
626  case PART_NONE: /* XXX avoid gcc whining */
627  case PART_LAST:
629  /*@switchbreak@*/ break;
630  }
631 
632  if (goterror || parsePart >= PART_LAST) {
633  spec = freeSpec(spec);
634  return parsePart;
635  }
636 
637  /* Detect whether BuildArch: is toplevel or within %package. */
638  if (spec->toplevel && parsePart != PART_BUILDARCHITECTURES)
639  spec->toplevel = 0;
640 
641  /* Restart parse iff toplevel BuildArch: is encountered. */
642  if (spec->toplevel && parsePart == PART_BUILDARCHITECTURES) {
643  int index;
644  int x;
645 
646  closeSpec(spec);
647 
648  /* LCL: sizeof(spec->BASpecs[0]) -nullderef whine here */
649  spec->BASpecs = xcalloc(spec->BACount, sizeof(*spec->BASpecs));
650  index = 0;
651  if (spec->BANames != NULL)
652  for (x = 0; x < spec->BACount; x++) {
653 
654  /* XXX DIEDIEDIE: filter irrelevant platforms here. */
655 
656  /* XXX there's more to do than set the macro. */
657  addMacro(NULL, "_target_cpu", NULL, spec->BANames[x], RMIL_RPMRC);
658  spec->BASpecs[index] = NULL;
659  if (parseSpec(ts, specFile, spec->rootURL, 1,
660  passPhrase, cookie, anyarch, force, verify)
661  || (spec->BASpecs[index] = rpmtsSetSpec(ts, NULL)) == NULL)
662  {
663  spec->BACount = index;
664 /*@-nullstate@*/
665  spec = freeSpec(spec);
666  return RPMRC_FAIL;
667 /*@=nullstate@*/
668  }
669 
670  /* XXX there's more to do than delete the macro. */
671  delMacro(NULL, "_target_cpu");
672  index++;
673  }
674 
675  spec->BACount = index;
676  if (! index) {
678  _("No compatible architectures found for build\n"));
679 /*@-nullstate@*/
680  spec = freeSpec(spec);
681  return RPMRC_FAIL;
682 /*@=nullstate@*/
683  }
684 
685  /*
686  * Return the 1st child's fully parsed Spec structure.
687  * The restart of the parse when encountering BuildArch
688  * causes problems for "rpm -q --specfile". This is
689  * still a hack because there may be more than 1 arch
690  * specified (unlikely but possible.) There's also the
691  * further problem that the macro context, particularly
692  * %{_target_cpu}, disagrees with the info in the header.
693  */
694  if (spec->BACount >= 1) {
695  Spec nspec = spec->BASpecs[0];
696  spec->BASpecs = _free(spec->BASpecs);
697  spec = freeSpec(spec);
698  spec = nspec;
699  }
700 
701  (void) rpmtsSetSpec(ts, spec);
702  return 0;
703  }
704  }
705  /*@=infloops@*/ /* LCL: parsePart is modified @*/
706 
707  /* Initialize source RPM name. */
708  (void) genSourceRpmName(spec);
709 
710  /* Check for description in each package and add arch and os */
711  {
712  const char *platform = rpmExpand("%{_target_platform}", NULL);
713  const char *platformNoarch = NULL;
714  const char *arch = rpmExpand("%{_target_cpu}", NULL);
715  const char *os = rpmExpand("%{_target_os}", NULL);
716 
717  for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
718  he->tag = RPMTAG_OS;
719  he->t = RPM_STRING_TYPE;
720  /* XXX todo: really need "noos" like pkg->noarch somewhen. */
721  he->p.str = os;
722  he->c = 1;
723  xx = headerPut(pkg->header, he, 0);
724 
725  he->tag = RPMTAG_ARCH;
726  he->t = RPM_STRING_TYPE;
727  he->p.str = (pkg->noarch ? "noarch" : arch);
728  he->c = 1;
729  xx = headerPut(pkg->header, he, 0);
730 
731  /*
732  * If "noarch" subpackages of different arch, we need
733  * to use a separate platform tag for these (mdvbz#61746).
734  */
735  if(pkg->noarch && !platformNoarch && strcmp(arch, "noarch")) {
736  addMacro(NULL, "_target_cpu", NULL, "noarch", RMIL_RPMRC);
737  platformNoarch = rpmExpand("%{_target_platform}", NULL);
738  addMacro(NULL, "_target_cpu", NULL, arch, RMIL_RPMRC);
739  }
740  he->tag = RPMTAG_PLATFORM;
741  he->t = RPM_STRING_TYPE;
742  he->p.str = (pkg->noarch && platformNoarch ? platformNoarch : platform);
743  he->c = 1;
744  xx = headerPut(pkg->header, he, 0);
745 
746  he->tag = RPMTAG_SOURCERPM;
747  he->t = RPM_STRING_TYPE;
748  he->p.str = spec->sourceRpmName;
749  he->c = 1;
750  xx = headerPut(pkg->header, he, 0);
751 
753  he->tag = RPMTAG_NVRA;
754  xx = headerGet(pkg->header, he, 0);
755  rpmlog(RPMLOG_ERR, _("Package has no %%description: %s\n"),
756  he->p.str);
757  he->p.ptr = _free(he->p.ptr);
758  platform = _free(platform);
759  platformNoarch = _free(platformNoarch);
760  arch = _free(arch);
761  os = _free(os);
762  spec = freeSpec(spec);
763  return RPMRC_FAIL;
764  }
765 
767 
768  }
769 
770  platform = _free(platform);
771  platformNoarch = _free(platformNoarch);
772  arch = _free(arch);
773  os = _free(os);
774  }
775 
776  closeSpec(spec);
777  (void) rpmtsSetSpec(ts, spec);
778 
779  return 0;
780 }
rpmTagType t
Definition: rpmtag.h:505
static void initParts(struct PartRec *p)
Definition: parseSpec.c:61
const char * str
Definition: rpmtag.h:72
rpmTag tag
Definition: rpmtag.h:504
const char * fileName
Definition: rpmspec.h:64
char ** sl_lines
Definition: rpmspec.h:100
rpmParseState isPart(Spec spec)
Check line for section separator, return next parser state.
Definition: parseSpec.c:68
enum rpmStripFlags_e rpmStripFlags
Spec file parser stripping flags.
int headerIsEntry(Header h, rpmTag tag)
Check if tag is in header.
Definition: header.c:1431
int parseScript(Spec spec, int parsePart)
Parse %pre et al scriptlets from a spec file.
Definition: parseScript.c:74
const char * sourceRpmName
Definition: rpmspec.h:162
Package next
Definition: rpmspec.h:248
static void * fdGetFp(FD_t fd)
int parseDescription(Spec spec)
Parse %description section of a spec file.
int noSource
Definition: rpmspec.h:159
struct OpenFileInfo * next
Definition: rpmspec.h:72
char * xstrdup(const char *str)
Definition: rpmmalloc.c:322
FD_t Fopen(const char *path, const char *_fmode)
fopen(3) clone.
Definition: rpmio.c:2833
int parseBuildInstallClean(Spec spec, rpmParseState parsePart)
Parse %build/%install/%clean section(s) of a spec file.
const char * rootURL
Definition: rpmspec.h:115
char * rpmGetPath(const char *path,...)
Return (malloc&#39;ed) expanded, canonicalized, file path.
Definition: macro.c:3310
const char * specFile
Definition: rpmspec.h:111
int headerGet(Header h, HE_t he, unsigned int flags)
Retrieve extension or tag value from a header.
Definition: header.c:2222
char * lbuf
Definition: rpmspec.h:125
int headerPut(Header h, HE_t he, unsigned int flags)
Add or append tag container to header.
Definition: header.c:2285
int xstrncasecmp(const char *s1, const char *s2, size_t n)
Locale insensitive strncasecmp(3).
Definition: strcasecmp.c:30
int argvStrcasecmp(ARGstr_t *a, ARGstr_t *b)
Compare argv elements using strcasecmp (qsort/bsearch).
Definition: argv.c:102
int sl_nalloc
Definition: rpmspec.h:101
void addMacro(MacroContext mc, const char *n, const char *o, const char *b, int level)
Add macro to context.
Definition: macro.c:2684
size_t lbuf_len
Definition: rpmspec.h:126
static void rpmlog(int code, const char *fmt,...)
Definition: rpmlog.h:299
const char * token
Definition: parseSpec.c:28
const char ** BANames
Definition: rpmspec.h:142
int parsePrep(Spec spec, int verify)
Parse %prep section of a spec file.
Definition: parsePrep.c:887
char * passPhrase
Definition: rpmspec.h:151
int readLine(Spec spec, rpmStripFlags strip)
Read next line from spec file.
Definition: parseSpec.c:353
static int genSourceRpmName(Spec spec)
Definition: parseSpec.c:499
int parseSpec(rpmts ts, const char *specFile, const char *rootURL, int recursing, const char *passPhrase, const char *cookie, int anyarch, int force, int verify)
Parse spec file into spec control structure.
Definition: parseSpec.c:527
rpmTag tagGenerate(const char *s)
Generate a tag from arbitrary string.
Definition: tagname.c:456
char * alloca()
int lineNum
Definition: rpmspec.h:67
Header header
Definition: rpmspec.h:210
struct _HE_s * HE_t
Definition: rpmtag.h:58
void delMacro(MacroContext mc, const char *n)
Delete macro from context.
Definition: macro.c:2723
const char * Fstrerror(FD_t fd)
strerror(3) clone.
Definition: rpmio.c:2401
void * xcalloc(size_t nmemb, size_t size)
Definition: rpmmalloc.c:301
char * nextline
Definition: rpmspec.h:131
void * ptr
Definition: rpmtag.h:66
int recursing
Definition: rpmspec.h:144
const char * cookie
Definition: rpmspec.h:154
char * line
Definition: rpmspec.h:133
static int readLineFromOFI(Spec spec, OFI_t *ofi)
Definition: parseSpec.c:291
rpmTagData p
Definition: rpmtag.h:507
MacroContext macros
Definition: rpmspec.h:172
static int xisspace(int c)
Definition: rpmiotypes.h:446
char nextpeekc
Definition: rpmspec.h:129
const char * tagName(rpmTag tag)
Return tag name from value.
Definition: tagname.c:436
static struct PartRec partList[]
Structure(s) used for dependency tag sets.
int anyarch
Definition: rpmspec.h:148
rpmTagCount c
Definition: rpmtag.h:508
The structure used to store values parsed from a spec file.
Definition: rpmspec.h:108
char * rpmExpand(const char *arg,...)
Return (malloc&#39;ed) concatenated macro expansion(s).
Definition: macro.c:3117
Spec freeSpec(Spec spec)
Destroy a spec file control structure.
static int copyNextLineFromOFI(Spec spec, OFI_t *ofi, rpmStripFlags strip)
Definition: parseSpec.c:180
int parseExpressionBoolean(Spec spec, const char *expr)
Evaluate boolean expression.
Definition: expression.c:679
int parseFiles(Spec spec)
Parse %files section of a spec file.
Definition: parseFiles.c:28
int parsePreamble(Spec spec, int initialPackage)
Parse tags from preamble of a spec file.
size_t nfoo
Definition: rpmspec.h:191
int Fclose(FD_t fd)
fclose(3) clone.
Definition: rpmio.c:2534
struct ReadLevelEntry * readStack
Definition: rpmspec.h:137
Spec rpmtsSetSpec(rpmts ts, Spec spec)
Set a spec control structure in transaction set.
Definition: rpmts.c:1395
static int restoreFirstChar(Spec spec)
Definition: parseSpec.c:166
Spec newSpec(void)
Create and initialize Spec structure.
Definition: spec.c:645
int BACount
Definition: rpmspec.h:143
int noarch
Definition: rpmspec.h:218
static int copyNextLineFinish(Spec spec, int strip)
Definition: parseSpec.c:259
#define RMIL_SPEC
Definition: rpmmacro.h:56
int Ferror(FD_t fd)
ferror(3) clone.
Definition: rpmio.c:2944
static int matchTok(const char *token, const char *line)
Definition: parseSpec.c:122
Package packages
Definition: rpmspec.h:197
Definition: rpmtag.h:503
Spec * BASpecs
Definition: rpmspec.h:140
static int snprintf(char *buf, int nb, const char *fmt,...)
Definition: rpmps.c:220
This is the only module users of librpmbuild should need to include.
int timeCheck
Definition: rpmspec.h:152
char * readPtr
Definition: rpmspec.h:70
#define RMIL_RPMRC
Definition: rpmmacro.h:52
struct rpmts_s * rpmts
The RPM Transaction Set.
Definition: rpmtypes.h:14
size_t len
Definition: parseSpec.c:26
static void * _free(const void *p)
Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
Definition: rpmiotypes.h:647
int headerNEVRA(Header h, const char **np, const char **ep, const char **vp, const char **rp, const char **ap)
Return name, epoch, version, release, arch strings from header.
Definition: hdrNVR.c:162
Structures and prototypes used for an "rpmts" transaction set.
char * tagCanonicalize(const char *s)
Canonicalize a rpmTag string.
Definition: tagname.c:451
int sl_nlines
Definition: rpmspec.h:102
rpmds ds
Definition: rpmspec.h:212
int parseChangelog(Spec spec)
Parse %changelog section of a spec file.
void closeSpec(Spec spec)
Stop reading from spec file, freeing resources.
Definition: parseSpec.c:484
enum rpmParseState_e rpmParseState
int lineNum
Definition: rpmspec.h:134
ARGV_t argvSearch(ARGV_t argv, ARGstr_t val, int(*compar)(ARGstr_t *, ARGstr_t *))
Find an element in an argv array.
Definition: argv.c:146
speclines sl
Definition: rpmspec.h:118
headerTagIndices rpmTags
Definition: tagname.c:184
int expandMacros(void *spec, MacroContext mc, char *sbuf, size_t slen)
Expand macro into buffer.
Definition: macro.c:2649
int force
Definition: rpmspec.h:147
FD_t fd
Definition: rpmspec.h:66
#define _(Text)
Definition: system.h:30
The structure used to store values for a package.
Definition: rpmspec.h:207
char readBuf[BUFSIZ]
Definition: rpmspec.h:68
#define xmalloc
Definition: system.h:33
ARGstr_t * ARGV_t
Definition: argv.h:9
struct OpenFileInfo * newOpenFileInfo(void)
Definition: spec.c:716
#define SKIPSPACE(s)
Definition: rpmbuild.h:45
tagStore_t foo
Definition: rpmspec.h:193
int noLang
Definition: poptBT.c:57
void handleComments(char *s)
Truncate comment lines.
Definition: parseSpec.c:144
int toplevel
Definition: rpmspec.h:145
static const char * platform
Definition: rpmrc.c:41
struct OpenFileInfo * fileStack
Definition: rpmspec.h:123
int rpmExpandNumeric(const char *arg)
Return macro expansion as a numeric value.
Definition: macro.c:3191
rpmds rpmdsThis(Header h, rpmTag tagN, evrFlags Flags)
Create, load and initialize a dependency for this header.
Definition: rpmds.c:513
#define xrealloc
Definition: system.h:36
static void forceIncludeFile(Spec spec, const char *fileName)
Definition: parseSpec.c:153
char * lbufPtr
Definition: rpmspec.h:128
struct ReadLevelEntry * next
Definition: rpmspec.h:56
#define SKIPNONSPACE(s)
Definition: rpmbuild.h:46
rpmParseState part
Definition: parseSpec.c:25