rpm  4.5
spec.c
Go to the documentation of this file.
1 
6 #include "system.h"
7 
8 #include "buildio.h"
9 #include "rpmds.h"
10 #include "rpmfi.h"
11 #include "rpmts.h"
12 
13 #include "debug.h"
14 
15 /*@-redecl@*/
16 extern int specedit;
17 /*@=redecl@*/
18 
19 #define SKIPWHITE(_x) {while(*(_x) && (xisspace(*_x) || *(_x) == ',')) (_x)++;}
20 #define SKIPNONWHITE(_x){while(*(_x) &&!(xisspace(*_x) || *(_x) == ',')) (_x)++;}
21 
22 /*@access Header @*/ /* compared with NULL */
23 /*@access rpmfi @*/ /* compared with NULL */
24 
29 static inline
30 /*@null@*/ struct TriggerFileEntry * freeTriggerFiles(/*@only@*/ /*@null@*/ struct TriggerFileEntry * p)
31  /*@modifies p @*/
32 {
33  struct TriggerFileEntry *o, *q = p;
34 
35  while (q != NULL) {
36  o = q;
37  q = q->next;
38  o->fileName = _free(o->fileName);
39  o->script = _free(o->script);
40  o->prog = _free(o->prog);
41  o = _free(o);
42  }
43  return NULL;
44 }
45 
51 static inline
52 /*@null@*/ struct Source * freeSources(/*@only@*/ /*@null@*/ struct Source * s)
53  /*@modifies s @*/
54 {
55  struct Source *r, *t = s;
56 
57  while (t != NULL) {
58  r = t;
59  t = t->next;
60  r->fullSource = _free(r->fullSource);
61  r = _free(r);
62  }
63  return NULL;
64 }
65 
66 /*@-boundswrite@*/
67 int lookupPackage(Spec spec, const char *name, int flag, /*@out@*/Package *pkg)
68 {
69  const char *pname;
70  const char *fullName;
71  Package p;
72 
73  /* "main" package */
74  if (name == NULL) {
75  if (pkg)
76  *pkg = spec->packages;
77  return 0;
78  }
79 
80  /* Construct package name */
81  { char *n;
82  if (flag == PART_SUBNAME) {
83  (void) headerNVR(spec->packages->header, &pname, NULL, NULL);
84  fullName = n = alloca(strlen(pname) + 1 + strlen(name) + 1);
85  while (*pname != '\0') *n++ = *pname++;
86  *n++ = '-';
87  } else {
88  fullName = n = alloca(strlen(name)+1);
89  }
90  /*@-mayaliasunique@*/
91  strcpy(n, name);
92  /*@=mayaliasunique@*/
93  }
94 
95  /* Locate package with fullName */
96  for (p = spec->packages; p != NULL; p = p->next) {
97  (void) headerNVR(p->header, &pname, NULL, NULL);
98  if (pname && (! strcmp(fullName, pname))) {
99  break;
100  }
101  }
102 
103  if (pkg)
104  /*@-dependenttrans@*/ *pkg = p; /*@=dependenttrans@*/
105  return ((p == NULL) ? 1 : 0);
106 }
107 /*@=boundswrite@*/
108 
110 {
111  Package p;
112  Package pp;
113 
114  p = xcalloc(1, sizeof(*p));
115 
116  p->header = headerNew();
117  p->ds = NULL;
118 
119  p->autoProv = 1;
120  p->autoReq = 1;
121 
122 #if 0
123  p->reqProv = NULL;
124  p->triggers = NULL;
125  p->triggerScripts = NULL;
126 #endif
127 
128  p->triggerFiles = NULL;
129 
130  p->fileFile = NULL;
131  p->fileList = NULL;
132 
133  p->cpioList = NULL;
134 
135  p->preInFile = NULL;
136  p->postInFile = NULL;
137  p->preUnFile = NULL;
138  p->postUnFile = NULL;
139  p->verifyFile = NULL;
140 
141  p->specialDoc = NULL;
142 
143  if (spec->packages == NULL) {
144  spec->packages = p;
145  } else {
146  /* Always add package to end of list */
147  for (pp = spec->packages; pp->next != NULL; pp = pp->next)
148  {};
149  pp->next = p;
150  }
151  p->next = NULL;
152 
153  return p;
154 }
155 
157 {
158  if (pkg == NULL) return NULL;
159 
160  pkg->preInFile = _free(pkg->preInFile);
161  pkg->postInFile = _free(pkg->postInFile);
162  pkg->preUnFile = _free(pkg->preUnFile);
163  pkg->postUnFile = _free(pkg->postUnFile);
164  pkg->verifyFile = _free(pkg->verifyFile);
165 
166  pkg->header = headerFree(pkg->header);
167  pkg->ds = rpmdsFree(pkg->ds);
168  pkg->fileList = freeStringBuf(pkg->fileList);
169  pkg->fileFile = _free(pkg->fileFile);
170  if (pkg->cpioList) {
171  rpmfi fi = pkg->cpioList;
172  pkg->cpioList = NULL;
173  fi = rpmfiFree(fi);
174  }
175 
176  pkg->specialDoc = freeStringBuf(pkg->specialDoc);
178 
179  pkg = _free(pkg);
180  return NULL;
181 }
182 
184 {
185  Package p;
186 
187  while ((p = packages) != NULL) {
188  packages = p->next;
189  p->next = NULL;
190  p = freePackage(p);
191  }
192  return NULL;
193 }
194 
197 static inline /*@owned@*/ struct Source *findSource(Spec spec, int num, int flag)
198  /*@*/
199 {
200  struct Source *p;
201 
202  for (p = spec->sources; p != NULL; p = p->next)
203  if ((num == p->num) && (p->flags & flag)) return p;
204 
205  return NULL;
206 }
207 
208 /*@-boundsread@*/
209 int parseNoSource(Spec spec, const char * field, int tag)
210 {
211  const char *f, *fe;
212  const char *name;
213  int num, flag;
214 
215  if (tag == RPMTAG_NOSOURCE) {
216  flag = RPMFILE_SOURCE;
217  name = "source";
218  } else {
219  flag = RPMFILE_PATCH;
220  name = "patch";
221  }
222 
223  fe = field;
224  for (f = fe; *f != '\0'; f = fe) {
225  struct Source *p;
226 
227  SKIPWHITE(f);
228  if (*f == '\0')
229  break;
230  fe = f;
231  SKIPNONWHITE(fe);
232  if (*fe != '\0') fe++;
233 
234  if (parseNum(f, &num)) {
235  rpmError(RPMERR_BADSPEC, _("line %d: Bad number: %s\n"),
236  spec->lineNum, f);
237  return RPMERR_BADSPEC;
238  }
239 
240  if (! (p = findSource(spec, num, flag))) {
241  rpmError(RPMERR_BADSPEC, _("line %d: Bad no%s number: %d\n"),
242  spec->lineNum, name, num);
243  return RPMERR_BADSPEC;
244  }
245 
246  p->flags |= RPMFILE_GHOST;
247 
248  }
249 
250  return 0;
251 }
252 /*@=boundsread@*/
253 
254 /*@-boundswrite@*/
255 int addSource(Spec spec, Package pkg, const char *field, int tag)
256 {
257  struct Source *p;
258  int flag = 0;
259  const char *name = NULL;
260  const char *mdir = NULL;
261  char *nump;
262  const char *fieldp = NULL;
263  char buf[BUFSIZ];
264  int num = 0;
265 
266  buf[0] = '\0';
267  /*@-branchstate@*/
268  switch (tag) {
269  case RPMTAG_SOURCE:
270  flag = RPMFILE_SOURCE;
271  name = "source";
272  mdir = "%{_sourcedir}/";
273  fieldp = spec->line + (sizeof("Source")-1);
274  break;
275  case RPMTAG_PATCH:
276  flag = RPMFILE_PATCH;
277  name = "patch";
278  mdir = "%{_patchdir}/";
279  fieldp = spec->line + (sizeof("Patch")-1);
280  break;
281  case RPMTAG_ICON:
282  flag = RPMFILE_ICON;
283  name = "icon";
284  mdir = "%{_icondir}/";
285  fieldp = NULL;
286  break;
287  default:
288 assert(0);
289  /*@notreached@*/ break;
290  }
291  /*@=branchstate@*/
292 
293  /* Get the number */
294  if (fieldp != NULL) {
295  /* We already know that a ':' exists, and that there */
296  /* are no spaces before it. */
297  /* This also now allows for spaces and tabs between */
298  /* the number and the ':' */
299 
300  nump = buf;
301  while ((*fieldp != ':') && (*fieldp != ' ') && (*fieldp != '\t'))
302  *nump++ = *fieldp++;
303  *nump = '\0';
304 
305  nump = buf;
306  SKIPSPACE(nump);
307  if (nump == NULL || *nump == '\0')
308  num = 0;
309  else if (parseNum(buf, &num)) {
310  rpmError(RPMERR_BADSPEC, _("line %d: Bad %s number: %s\n"),
311  spec->lineNum, name, spec->line);
312  return RPMERR_BADSPEC;
313  }
314  }
315 
316  /* Create the entry and link it in */
317  p = xmalloc(sizeof(*p));
318  p->num = num;
319  p->fullSource = xstrdup(field);
320  p->flags = flag;
321  p->source = strrchr(p->fullSource, '/');
322  if (p->source)
323  p->source++;
324  else
325  p->source = p->fullSource;
326 
327  p->next = spec->sources;
328  spec->sources = p;
329 
330  spec->numSources++;
331 
332  /* XXX FIXME: need to add ICON* macros. */
333  if (tag != RPMTAG_ICON) {
334  const char *body = rpmGenPath(NULL, mdir, p->source);
335 
336  sprintf(buf, "%s%d",
337  (flag & RPMFILE_PATCH) ? "PATCH" : "SOURCE", num);
338  addMacro(spec->macros, buf, NULL, body, RMIL_SPEC);
339  sprintf(buf, "%sURL%d",
340  (flag & RPMFILE_PATCH) ? "PATCH" : "SOURCE", num);
341  addMacro(spec->macros, buf, NULL, p->fullSource, RMIL_SPEC);
342  body = _free(body);
343  }
344 
345  return 0;
346 }
347 /*@=boundswrite@*/
348 
351 static inline /*@only@*/ /*@null@*/ speclines newSl(void)
352  /*@*/
353 {
354  speclines sl = NULL;
355  /*@-branchstate@*/
356  if (specedit) {
357  sl = xmalloc(sizeof(*sl));
358  sl->sl_lines = NULL;
359  sl->sl_nalloc = 0;
360  sl->sl_nlines = 0;
361  }
362  /*@=branchstate@*/
363  return sl;
364 }
365 
368 /*@-boundswrite@*/
369 static inline /*@null@*/ speclines freeSl(/*@only@*/ /*@null@*/ speclines sl)
370  /*@modifies sl @*/
371 {
372  int i;
373  if (sl == NULL) return NULL;
374  for (i = 0; i < sl->sl_nlines; i++)
375  /*@-unqualifiedtrans@*/
376  sl->sl_lines[i] = _free(sl->sl_lines[i]);
377  /*@=unqualifiedtrans@*/
378  sl->sl_lines = _free(sl->sl_lines);
379  return _free(sl);
380 }
381 /*@=boundswrite@*/
382 
385 static inline /*@only@*/ /*@null@*/ spectags newSt(void)
386  /*@*/
387 {
388  spectags st = NULL;
389  /*@-branchstate@*/
390  if (specedit) {
391  st = xmalloc(sizeof(*st));
392  st->st_t = NULL;
393  st->st_nalloc = 0;
394  st->st_ntags = 0;
395  }
396  /*@=branchstate@*/
397  return st;
398 }
399 
402 static inline /*@null@*/ spectags freeSt(/*@only@*/ /*@null@*/ spectags st)
403  /*@modifies st @*/
404 {
405  int i;
406  if (st == NULL) return NULL;
407  for (i = 0; i < st->st_ntags; i++) {
408  spectag t = st->st_t + i;
409  t->t_lang = _free(t->t_lang);
410  t->t_msgid = _free(t->t_msgid);
411  }
412  st->st_t = _free(st->st_t);
413  return _free(st);
414 }
415 
417 {
418  Spec spec = xcalloc(1, sizeof(*spec));
419 
420  spec->specFile = NULL;
421 
422  spec->sl = newSl();
423  spec->st = newSt();
424 
425  spec->fileStack = NULL;
426 /*@-boundswrite@*/
427  spec->lbuf[0] = '\0';
428 /*@=boundswrite@*/
429  spec->line = spec->lbuf;
430  spec->nextline = NULL;
431  spec->nextpeekc = '\0';
432  spec->lineNum = 0;
433  spec->readStack = xcalloc(1, sizeof(*spec->readStack));
434  spec->readStack->next = NULL;
435  spec->readStack->reading = 1;
436 
437  spec->rootURL = NULL;
438  spec->prep = NULL;
439  spec->build = NULL;
440  spec->install = NULL;
441  spec->check = NULL;
442  spec->clean = NULL;
443 
444  spec->sources = NULL;
445  spec->packages = NULL;
446  spec->noSource = 0;
447  spec->numSources = 0;
448 
449  spec->sourceRpmName = NULL;
450  spec->sourcePkgId = NULL;
451  spec->sourceHeader = headerNew();
452  spec->sourceCpioList = NULL;
453 
454  spec->buildSubdir = NULL;
455 
456  spec->passPhrase = NULL;
457  spec->timeCheck = 0;
458  spec->cookie = NULL;
459 
460  spec->BANames = NULL;
461  spec->BACount = 0;
462  spec->recursing = 0;
463  spec->BASpecs = NULL;
464 
465  spec->force = 0;
466  spec->anyarch = 0;
467 
468 /*@i@*/ spec->macros = rpmGlobalMacroContext;
469 
470  spec->_parseRCPOT = parseRCPOT; /* XXX hack around backward linkage. */
471 
472  return spec;
473 }
474 
476 {
477  struct ReadLevelEntry *rl;
478 
479  if (spec == NULL) return NULL;
480 
481  spec->sl = freeSl(spec->sl);
482  spec->st = freeSt(spec->st);
483 
484  spec->prep = freeStringBuf(spec->prep);
485  spec->build = freeStringBuf(spec->build);
486  spec->install = freeStringBuf(spec->install);
487  spec->check = freeStringBuf(spec->check);
488  spec->clean = freeStringBuf(spec->clean);
489 
490  spec->buildSubdir = _free(spec->buildSubdir);
491  spec->rootURL = _free(spec->rootURL);
492  spec->specFile = _free(spec->specFile);
493 
494 #ifdef DEAD
495  { struct OpenFileInfo *ofi;
496  while (spec->fileStack) {
497  ofi = spec->fileStack;
498  spec->fileStack = ofi->next;
499  ofi->next = NULL;
500  ofi->fileName = _free(ofi->fileName);
501  ofi = _free(ofi);
502  }
503  }
504 #else
505  closeSpec(spec);
506 #endif
507 
508  while (spec->readStack) {
509  rl = spec->readStack;
510  /*@-dependenttrans@*/
511  spec->readStack = rl->next;
512  /*@=dependenttrans@*/
513  rl->next = NULL;
514  rl = _free(rl);
515  }
516 
517  spec->sourceRpmName = _free(spec->sourceRpmName);
518  spec->sourcePkgId = _free(spec->sourcePkgId);
519  spec->sourceHeader = headerFree(spec->sourceHeader);
520 
521  if (spec->sourceCpioList) {
522  rpmfi fi = spec->sourceCpioList;
523  spec->sourceCpioList = NULL;
524  fi = rpmfiFree(fi);
525  }
526 
527  if (!spec->recursing) {
528 /*@-boundswrite@*/
529  if (spec->BASpecs != NULL)
530  while (spec->BACount--) {
531  /*@-unqualifiedtrans@*/
532  spec->BASpecs[spec->BACount] =
533  freeSpec(spec->BASpecs[spec->BACount]);
534  /*@=unqualifiedtrans@*/
535  }
536 /*@=boundswrite@*/
537  /*@-compdef@*/
538  spec->BASpecs = _free(spec->BASpecs);
539  /*@=compdef@*/
540  }
541  spec->BANames = _free(spec->BANames);
542 
543  spec->passPhrase = _free(spec->passPhrase);
544  spec->cookie = _free(spec->cookie);
545 
546  spec->sources = freeSources(spec->sources);
547  spec->packages = freePackages(spec->packages);
548 
549  spec = _free(spec);
550 
551  return spec;
552 }
553 
554 /*@only@*/
556 {
557  struct OpenFileInfo *ofi;
558 
559  ofi = xmalloc(sizeof(*ofi));
560  ofi->fd = NULL;
561  ofi->fileName = NULL;
562  ofi->lineNum = 0;
563 /*@-boundswrite@*/
564  ofi->readBuf[0] = '\0';
565 /*@=boundswrite@*/
566  ofi->readPtr = NULL;
567  ofi->next = NULL;
568 
569  return ofi;
570 }
571 
576 static void
578  /*@globals fileSystem @*/
579  /*@modifies spec->sl->sl_lines[], fileSystem @*/
580 {
581  Header h;
582  speclines sl = spec->sl;
583  spectags st = spec->st;
584  const char * msgstr = NULL;
585  int i, j;
586 
587  if (sl == NULL || st == NULL)
588  return;
589 
590  /*@-branchstate@*/
591  for (i = 0; i < st->st_ntags; i++) {
592  spectag t = st->st_t + i;
593  const char * tn = tagName(t->t_tag);
594  const char * errstr;
595  char fmt[1024];
596 
597  fmt[0] = '\0';
598  if (t->t_msgid == NULL)
599  h = spec->packages->header;
600  else {
601  Package pkg;
602  char *fe;
603 
604 /*@-bounds@*/
605  strcpy(fmt, t->t_msgid);
606  for (fe = fmt; *fe && *fe != '('; fe++)
607  {} ;
608  if (*fe == '(') *fe = '\0';
609 /*@=bounds@*/
610  h = NULL;
611  for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
612  const char *pkgname;
613  h = pkg->header;
614  (void) headerNVR(h, &pkgname, NULL, NULL);
615  if (!strcmp(pkgname, fmt))
616  /*@innerbreak@*/ break;
617  }
618  if (pkg == NULL || h == NULL)
619  h = spec->packages->header;
620  }
621 
622  if (h == NULL)
623  continue;
624 
625  fmt[0] = '\0';
626 /*@-boundswrite@*/
627  (void) stpcpy( stpcpy( stpcpy( fmt, "%{"), tn), "}");
628 /*@=boundswrite@*/
629  msgstr = _free(msgstr);
630 
631  /* XXX this should use queryHeader(), but prints out tn as well. */
632  msgstr = headerSprintf(h, fmt, rpmTagTable, rpmHeaderFormats, &errstr);
633  if (msgstr == NULL) {
634  rpmError(RPMERR_QFMT, _("can't query %s: %s\n"), tn, errstr);
635  return;
636  }
637 
638 /*@-boundswrite@*/
639  switch(t->t_tag) {
640  case RPMTAG_SUMMARY:
641  case RPMTAG_GROUP:
642  /*@-unqualifiedtrans@*/
643  sl->sl_lines[t->t_startx] = _free(sl->sl_lines[t->t_startx]);
644  /*@=unqualifiedtrans@*/
645  if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG))
646  continue;
647  { char *buf = xmalloc(strlen(tn) + sizeof(": ") + strlen(msgstr));
648  (void) stpcpy( stpcpy( stpcpy(buf, tn), ": "), msgstr);
649  sl->sl_lines[t->t_startx] = buf;
650  }
651  /*@switchbreak@*/ break;
652  case RPMTAG_DESCRIPTION:
653  for (j = 1; j < t->t_nlines; j++) {
654  if (*sl->sl_lines[t->t_startx + j] == '%')
655  /*@innercontinue@*/ continue;
656  /*@-unqualifiedtrans@*/
657  sl->sl_lines[t->t_startx + j] =
658  _free(sl->sl_lines[t->t_startx + j]);
659  /*@=unqualifiedtrans@*/
660  }
661  if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG)) {
662  sl->sl_lines[t->t_startx] = _free(sl->sl_lines[t->t_startx]);
663  continue;
664  }
665  sl->sl_lines[t->t_startx + 1] = xstrdup(msgstr);
666  if (t->t_nlines > 2)
667  sl->sl_lines[t->t_startx + 2] = xstrdup("\n\n");
668  /*@switchbreak@*/ break;
669  }
670 /*@=boundswrite@*/
671  }
672  /*@=branchstate@*/
673  msgstr = _free(msgstr);
674 
675  for (i = 0; i < sl->sl_nlines; i++) {
676  const char * s = sl->sl_lines[i];
677  if (s == NULL)
678  continue;
679  printf("%s", s);
680  if (strchr(s, '\n') == NULL && s[strlen(s)-1] != '\n')
681  printf("\n");
682  }
683 }
684 
694  rpmTag progTag, rpmTag scriptTag, StringBuf sb)
695  /*@modifies h @*/
696 {
697  int xx;
698 
699  if (progTag !=(rpmTag) 0) {
700  static const char prog[] = "/bin/sh"; /* XXX FIXME */
701  xx = headerAddEntry(h, progTag, RPM_STRING_TYPE, prog, 1);
702  }
703 
704  if (scriptTag != (rpmTag)0 && sb != NULL) {
705  xx = headerAddEntry(h, scriptTag, RPM_STRING_TYPE, getStringBuf(sb), 1);
706  }
707  return 0;
708 }
709 
716  /*@modifies spec->sourceHeader @*/
717 {
718  int xx;
719 
720  if (spec->prep != NULL)
723  if (spec->build != NULL)
726  if (spec->install != NULL)
729  if (spec->check != NULL)
732  if (spec->clean != NULL)
735 
736  return 0;
737 }
738 
747 static int _specQuery(rpmts ts, QVA_t qva, const char *specName,
748  /*@null@*/ const char *target)
749  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
750  /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
751 {
752  Spec spec = NULL;
753  Package pkg;
754  int res = 1; /* assume error */
755  int anyarch = (target == NULL) ? 1 : 0;
756  char * passPhrase = "";
757  int recursing = 0;
758  char *cookie = NULL;
759  int force = 1;
760  int verify = 0;
761  int xx;
762 
763  /*@-mods@*/ /* FIX: make spec abstract */
764  if (parseSpec(ts, specName, "/", recursing, passPhrase,
765  cookie, anyarch, force, verify)
766  || (spec = rpmtsSetSpec(ts, NULL)) == NULL)
767  {
769  _("query of specfile %s failed, can't parse\n"),
770  specName);
771  goto exit;
772  }
773  /*@=mods@*/
774 
775  res = 0;
776  if (specedit) {
777  printNewSpecfile(spec);
778  goto exit;
779  }
780 
781  switch (qva->qva_source) {
782  case RPMQV_SPECSRPM:
783  xx = initSourceHeader(spec, NULL);
784  xx = initSourceHeaderScriptlets(spec);
785  xx = qva->qva_showPackage(qva, ts, spec->sourceHeader);
786  break;
787  default:
788  case RPMQV_SPECFILE:
789  for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
790  /* If no target was specified, display all packages.
791  * Packages with empty file lists are not produced.
792  */
793  /* XXX DIEDIEDIE: this logic looks flawed. */
794  if (target == NULL || pkg->fileList != NULL)
795  xx = qva->qva_showPackage(qva, ts, pkg->header);
796  }
797  break;
798  }
799 
800 exit:
801  spec = freeSpec(spec);
802  return res;
803 }
804 
805 int rpmspecQuery(rpmts ts, QVA_t qva, const char * arg)
806 {
807  int res = 1;
808  const char * targets = rpmcliTargets;
809  char *target;
810  const char * t;
811  const char * te;
812  const char * rcfile = rpmcliRcfile;
813  int nqueries = 0;
814 
815  if (qva->qva_showPackage == NULL)
816  goto exit;
817 
818  if (targets == NULL) {
819  res = _specQuery(ts, qva, arg, NULL);
820  nqueries++;
821  goto exit;
822  }
823 
825  D_("Query specfile for platform(s): %s\n"), targets);
826  for (t = targets; *t != '\0'; t = te) {
827  /* Parse out next target platform. */
828  if ((te = strchr(t, ',')) == NULL)
829  te = t + strlen(t);
830  target = alloca(te-t+1);
831  strncpy(target, t, (te-t));
832  target[te-t] = '\0';
833  if (*te != '\0')
834  te++;
835 
836  /* Query spec for this target platform. */
837  rpmMessage(RPMMESS_DEBUG, D_(" target platform: %s\n"), target);
838  /* Read in configuration for target. */
839  if (t != targets) {
840  rpmFreeMacros(NULL);
841  rpmFreeRpmrc();
842  (void) rpmReadConfigFiles(rcfile, target);
843  }
844  res = _specQuery(ts, qva, arg, target);
845  nqueries++;
846  if (res) break;
847  }
848 
849 exit:
850  /* Restore original configuration. */
851  if (nqueries > 1) {
852  t = targets;
853  if ((te = strchr(t, ',')) == NULL)
854  te = t + strlen(t);
855  target = alloca(te-t+1);
856  strncpy(target, t, (te-t));
857  target[te-t] = '\0';
858  if (*te != '\0')
859  te++;
860  rpmFreeMacros(NULL);
861  rpmFreeRpmrc();
862  (void) rpmReadConfigFiles(rcfile, target);
863  }
864  return res;
865 }