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