rpm 5.2.1

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

- File List
- Globals

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