rpm  5.4.10
rpmfc.c
Go to the documentation of this file.
1 #include "system.h"
2 
3 #include <signal.h> /* getOutputFrom() */
4 
5 #include <rpmio.h>
6 #include <rpmiotypes.h> /* XXX fnpyKey */
7 #include <rpmlog.h>
8 #include <rpmurl.h>
9 #include <rpmmg.h>
10 #include <argv.h>
11 #define _MIRE_INTERNAL
12 #include <mire.h>
13 
14 #include <rpmtag.h>
15 #define _RPMEVR_INTERNAL
16 #include <rpmbuild.h>
17 
18 #define _RPMNS_INTERNAL
19 #include <rpmns.h>
20 
21 #define _RPMFC_INTERNAL
22 #include <rpmfc.h>
23 
24 #define _RPMDS_INTERNAL
25 #include <rpmds.h>
26 #include <rpmfi.h>
27 
28 #include "debug.h"
29 
30 /*@access rpmds @*/
31 /*@access miRE @*/
32 
33 #ifdef __cplusplus
34 GENfree(rpmuint16_t *)
35 GENfree(rpmuint32_t *)
36 #endif /* __cplusplus */
37 
38 /*@unchecked@*/
39 static int _filter_values = 1;
40 /*@unchecked@*/
41 static int _filter_execs = 1;
42 
45 static int rpmfcExpandAppend(/*@out@*/ ARGV_t * argvp, const ARGV_t av)
46  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
47  /*@modifies *argvp, rpmGlobalMacroContext, internalState @*/
48  /*@requires maxRead(argvp) >= 0 @*/
49 {
50  ARGV_t argv = *argvp;
51  int argc = argvCount(argv);
52  int ac = argvCount(av);
53  int i;
54 
55  argv = (ARGV_t) xrealloc(argv, (argc + ac + 1) * sizeof(*argv));
56  for (i = 0; i < ac; i++)
57  argv[argc + i] = rpmExpand(av[i], NULL);
58  argv[argc + ac] = NULL;
59  *argvp = argv;
60  return 0;
61 }
62 
63 /* XXX FIXME: more AutoFu testing needed? */
64 #if defined(HAVE_SIG_T) && !defined(SIGHANDLER_T)
65 typedef sig_t sighandler_t;
66 #endif
67 
78 /*@null@*/
79 static rpmiob getOutputFrom(/*@null@*/ const char * dir, ARGV_t argv,
80  const char * writePtr, size_t writeBytesLeft,
81  int failNonZero)
82  /*@globals h_errno, fileSystem, internalState@*/
83  /*@modifies fileSystem, internalState@*/
84 {
85  pid_t child, reaped;
86  int toProg[2];
87  int fromProg[2];
88  int status;
89  sighandler_t oldhandler = signal(SIGPIPE, SIG_IGN);
90  rpmiob iob = NULL;
91  int done;
92 
93  toProg[0] = toProg[1] = 0;
94  fromProg[0] = fromProg[1] = 0;
95  if (pipe(toProg) < 0 || pipe(fromProg) < 0) {
96  rpmlog(RPMLOG_ERR, _("Couldn't create pipe for %s: %m\n"), argv[0]);
97  return NULL;
98  }
99 
100  if (!(child = fork())) {
101  (void) close(toProg[1]);
102  (void) close(fromProg[0]);
103 
104  (void) dup2(toProg[0], STDIN_FILENO); /* Make stdin the in pipe */
105  (void) dup2(fromProg[1], STDOUT_FILENO); /* Make stdout the out pipe */
106 
107  (void) close(toProg[0]);
108  (void) close(fromProg[1]);
109 
110  if (dir) {
111  (void) Chdir(dir);
112  }
113 
114  rpmlog(RPMLOG_DEBUG, D_("\texecv(%s) pid %d\n"),
115  argv[0], (unsigned)getpid());
116 
117  unsetenv("MALLOC_CHECK_");
118  (void) execvp(argv[0], (char *const *)argv);
119  /* XXX this error message is probably not seen. */
120  rpmlog(RPMLOG_ERR, _("Couldn't exec %s: %s\n"),
121  argv[0], strerror(errno));
122  _exit(EXIT_FAILURE);
123  }
124  if (child < 0) {
125  rpmlog(RPMLOG_ERR, _("Couldn't fork %s: %s\n"),
126  argv[0], strerror(errno));
127  return NULL;
128  }
129 
130  (void) close(toProg[0]);
131  (void) close(fromProg[1]);
132 
133  /* Do not block reading or writing from/to prog. */
134  (void) fcntl(fromProg[0], F_SETFL, O_NONBLOCK);
135  (void) fcntl(toProg[1], F_SETFL, O_NONBLOCK);
136 
137  iob = rpmiobNew(0);
138 
139  do {
140  fd_set ibits, obits;
141  struct timeval tv;
142  int nfd;
143  ssize_t nbr;
144  ssize_t nbw;
145  int rc;
146 
147  done = 0;
148 top:
149  FD_ZERO(&ibits);
150  FD_ZERO(&obits);
151  if (fromProg[0] >= 0) {
152  FD_SET(fromProg[0], &ibits);
153  }
154  if (toProg[1] >= 0) {
155  FD_SET(toProg[1], &obits);
156  }
157  /* XXX values set to limit spinning with perl doing ~100 forks/sec. */
158  tv.tv_sec = 0;
159  tv.tv_usec = 10000;
160  nfd = ((fromProg[0] > toProg[1]) ? fromProg[0] : toProg[1]);
161  if ((rc = select(nfd, &ibits, &obits, NULL, &tv)) < 0) {
162  if (errno == EINTR)
163  goto top;
164  break;
165  }
166 
167  /* Write any data to program */
168  if (toProg[1] >= 0 && FD_ISSET(toProg[1], &obits)) {
169  if (writePtr && writeBytesLeft > 0) {
170  if ((nbw = write(toProg[1], writePtr,
171  ((size_t)1024<writeBytesLeft) ? (size_t)1024 : writeBytesLeft)) < 0)
172  {
173  if (errno != EAGAIN) {
174  perror("getOutputFrom()");
175  exit(EXIT_FAILURE);
176  }
177  nbw = 0;
178  }
179  writeBytesLeft -= nbw;
180  writePtr += nbw;
181  } else if (toProg[1] >= 0) { /* close write fd */
182  (void) close(toProg[1]);
183  toProg[1] = -1;
184  }
185  }
186 
187  /* Read any data from prog */
188  { char buf[BUFSIZ+1];
189  while ((nbr = read(fromProg[0], buf, sizeof(buf)-1)) > 0) {
190  buf[nbr] = '\0';
191  iob = rpmiobAppend(iob, buf, 0);
192  }
193  }
194 
195  /* terminate on (non-blocking) EOF or error */
196  done = (nbr == 0 || (nbr < 0 && errno != EAGAIN));
197 
198  } while (!done);
199 
200  /* Clean up */
201  if (toProg[1] >= 0)
202  (void) close(toProg[1]);
203  if (fromProg[0] >= 0)
204  (void) close(fromProg[0]);
205  (void) signal(SIGPIPE, oldhandler);
206 
207  /* Collect status from prog */
208  reaped = waitpid(child, &status, 0);
209  rpmlog(RPMLOG_DEBUG, D_("\twaitpid(%d) rc %d status %x\n"),
210  (unsigned)child, (unsigned)reaped, status);
211 
212  if (failNonZero && (!WIFEXITED(status) || WEXITSTATUS(status))) {
213  const char *cmd = argvJoin(argv, ' ');
214  int rc = (WIFEXITED(status) ? WEXITSTATUS(status) : -1);
215 
216  rpmlog(RPMLOG_ERR, _("Command \"%s\" failed, exit(%d)\n"), cmd, rc);
217  cmd = _free(cmd);
218  iob = rpmiobFree(iob);
219  return NULL;
220  }
221  if (writeBytesLeft) {
222  rpmlog(RPMLOG_ERR, _("failed to write all data to %s\n"), argv[0]);
223  iob = rpmiobFree(iob);
224  return NULL;
225  }
226  return iob;
227 }
228 
229 int rpmfcExec(ARGV_t av, rpmiob iob_stdin, rpmiob * iob_stdoutp,
230  int failnonzero)
231 {
232  const char * s = NULL;
233  ARGV_t xav = NULL;
234  ARGV_t pav = NULL;
235  int pac = 0;
236  int ec = -1;
237  rpmiob iob = NULL;
238  const char * buf_stdin = NULL;
239  size_t buf_stdin_len = 0;
240  int xx;
241 
242  if (iob_stdoutp)
243  *iob_stdoutp = NULL;
244  if (!(av && *av))
245  goto exit;
246 
247  /* Find path to executable with (possible) args. */
248  s = rpmExpand(av[0], NULL);
249  if (!(s && *s))
250  goto exit;
251 
252  /* Parse args buried within expanded executable. */
253  pac = 0;
254  xx = poptParseArgvString(s, &pac, (const char ***)&pav);
255  if (!(xx == 0 && pac > 0 && pav != NULL))
256  goto exit;
257 
258  /* Build argv, appending args to the executable args. */
259  xav = NULL;
260  xx = argvAppend(&xav, pav);
261  if (av[1])
262  xx = rpmfcExpandAppend(&xav, av + 1);
263 
264  if (iob_stdin != NULL) {
265  buf_stdin = rpmiobStr(iob_stdin);
266  buf_stdin_len = rpmiobLen(iob_stdin);
267  }
268 
269  /* Read output from exec'd helper. */
270  iob = getOutputFrom(NULL, xav, buf_stdin, buf_stdin_len, failnonzero);
271 
272  if (iob_stdoutp != NULL) {
273  *iob_stdoutp = iob;
274  iob = NULL; /* XXX don't free */
275  }
276 
277  ec = 0;
278 
279 exit:
280  iob = rpmiobFree(iob);
281  xav = argvFree(xav);
282  pav = _free(pav); /* XXX popt mallocs in single blob. */
283  s = _free(s);
284  return ec;
285 }
286 
289 static int rpmfcSaveArg(/*@out@*/ ARGV_t * argvp, const char * key)
290  /*@modifies *argvp @*/
291  /*@requires maxSet(argvp) >= 0 @*/
292 {
293  int rc = 0;
294 
295  if (argvSearch(*argvp, key, NULL) == NULL) {
296  rc = argvAdd(argvp, key);
297  rc = argvSort(*argvp, NULL);
298  }
299  return rc;
300 }
301 
304 static char * rpmfcFileDep(/*@returned@*/ char * buf, size_t ix,
305  /*@null@*/ rpmds ds)
306  /*@globals internalState @*/
307  /*@modifies buf, internalState @*/
308  /*@requires maxSet(buf) >= 0 @*/
309 {
310  rpmTag tagN = rpmdsTagN(ds);
311  char deptype = 'X';
312 
313  buf[0] = '\0';
314  switch (tagN) {
315  default:
316 assert(0);
317  /*@notreached@*/ break;
318  case RPMTAG_PROVIDENAME:
319  deptype = 'P';
320  break;
321  case RPMTAG_REQUIRENAME:
322  deptype = 'R';
323  break;
324  }
325 /*@-nullpass@*/
326  if (ds != NULL)
327  sprintf(buf, "%08u%c %s %s 0x%08x", (unsigned)ix, deptype,
328  rpmdsN(ds), rpmdsEVR(ds), rpmdsFlags(ds));
329 /*@=nullpass@*/
330  return buf;
331 };
332 
333 /*@null@*/
334 static void * rpmfcExpandRegexps(const char * str, int * nmirep)
335  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
336  /*@modifies *nmirep, rpmGlobalMacroContext, internalState @*/
337 {
338  ARGV_t av = NULL;
339  int ac = 0;
340  miRE mire = NULL;
341  int nmire = 0;
342  const char * s;
343  int xx;
344  int i;
345 
346  s = rpmExpand(str, NULL);
347  if (s && *s) {
348  xx = poptParseArgvString(s, &ac, (const char ***)&av);
349  s = _free(s);
350  }
351  if (ac == 0 || av == NULL || *av == NULL) {
352  s = _free(s);
353  goto exit;
354  }
355 
356  for (i = 0; i < ac; i++) {
357  xx = mireAppend(RPMMIRE_REGEX, 0, av[i], NULL, &mire, &nmire);
358  /* XXX add REG_NOSUB? better error msg? */
359  if (xx) {
361  _("Compilation of pattern '%s'"
362  " (expanded from '%s') failed. Skipping ...\n"),
363  av[i], str);
364  nmire--; /* XXX does this actually skip?!? */
365  }
366  }
367  if (nmire == 0)
368  mire = mireFree(mire);
369 
370 exit:
371  av = _free(av);
372  if (nmirep)
373  *nmirep = nmire;
374  return mire;
375 }
376 
377 static int rpmfcMatchRegexps(void * _mire, int nmire,
378  const char * str, char deptype)
379  /*@modifies mires @*/
380 {
381  miRE mire = (miRE) _mire;
382  int xx;
383  int i;
384 
385  for (i = 0; i < nmire; i++) {
386 #ifdef DYING /* XXX noisy. use --miredebug if you need this spewage */
387  rpmlog(RPMLOG_DEBUG, D_("Checking %c: '%s'\n"), deptype, str);
388 #endif
389  if ((xx = mireRegexec(mire + i, str, 0)) < 0)
390  continue;
391  rpmlog(RPMLOG_NOTICE, _("Skipping %c: '%s'\n"), deptype, str);
392  return 1;
393  }
394  return 0;
395 }
396 
397 /*@null@*/
398 static void * rpmfcFreeRegexps(/*@only@*/ void * _mire, int nmire)
399  /*@modifies mires @*/
400 {
401  miRE mire = (miRE) _mire;
402 /*@-refcounttrans@*/
403  return mireFreeAll(mire, nmire);
404 /*@=refcounttrans@*/
405 }
406 
414 static int rpmfcHelper(rpmfc fc, unsigned char deptype, const char * nsdep)
415  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
416  /*@modifies fc, rpmGlobalMacroContext, fileSystem, internalState @*/
417 {
418  miRE mire = NULL;
419  int nmire = 0;
420  const char * fn = fc->fn[fc->ix];
421  char buf[BUFSIZ];
422  rpmiob iob_stdout = NULL;
423  rpmiob iob_stdin;
424  const char *av[2];
425  rpmds * depsp, ds;
426  const char * N;
427  const char * EVR;
428  rpmTag tagN;
429  evrFlags Flags;
430  evrFlags dsContext;
431  ARGV_t pav;
432  const char * s;
433  int pac;
434  int xx;
435  int i;
436 
437  switch (deptype) {
438  default:
439  return -1;
440  /*@notreached@*/ break;
441  case 'P':
442  if (fc->skipProv)
443  return 0;
444  xx = snprintf(buf, sizeof(buf), "%%{?__%s_provides}", nsdep);
445  depsp = &fc->provides;
446  dsContext = RPMSENSE_FIND_PROVIDES;
447  tagN = RPMTAG_PROVIDENAME;
448  mire = (miRE) fc->Pmires;
449  nmire = fc->Pnmire;
450  break;
451  case 'R':
452  if (fc->skipReq)
453  return 0;
454  xx = snprintf(buf, sizeof(buf), "%%{?__%s_requires}", nsdep);
455  depsp = &fc->requires;
456  dsContext = RPMSENSE_FIND_REQUIRES;
457  tagN = RPMTAG_REQUIRENAME;
458  mire = (miRE) fc->Rmires;
459  nmire = fc->Rnmire;
460  break;
461  }
462  buf[sizeof(buf)-1] = '\0';
463  av[0] = buf;
464  av[1] = NULL;
465 
466  iob_stdin = rpmiobNew(0);
467  iob_stdin = rpmiobAppend(iob_stdin, fn, 1);
468  iob_stdout = NULL;
469  xx = rpmfcExec(av, iob_stdin, &iob_stdout, 0);
470  iob_stdin = rpmiobFree(iob_stdin);
471 
472  if (xx == 0 && iob_stdout != NULL) {
473  pav = NULL;
474  xx = argvSplit(&pav, rpmiobStr(iob_stdout), " \t\n\r");
475  pac = argvCount(pav);
476  if (pav)
477  for (i = 0; i < pac; i++) {
478  N = pav[i];
479  EVR = "";
480  Flags = dsContext;
481  if (pav[i+1] && strchr("=<>", *pav[i+1])) {
482  i++;
483  for (s = pav[i]; *s; s++) {
484  switch(*s) {
485  default:
486 assert(*s != '\0');
487  /*@switchbreak@*/ break;
488  case '=':
489  Flags = (evrFlags) (Flags | RPMSENSE_EQUAL);
490  /*@switchbreak@*/ break;
491  case '<':
492  Flags = (evrFlags) (Flags | RPMSENSE_LESS);
493  /*@switchbreak@*/ break;
494  case '>':
495  Flags = (evrFlags) (Flags | RPMSENSE_GREATER);
496  /*@switchbreak@*/ break;
497  }
498  }
499  i++;
500  EVR = pav[i];
501 assert(EVR != NULL);
502  }
503 
504  if (_filter_values && rpmfcMatchRegexps(mire, nmire, N, deptype))
505  continue;
506 
507  ds = rpmdsSingle(tagN, N, EVR, Flags);
508 
509  int overlap = 0;
510 #if defined(RPM_VENDOR_MANDRIVA) /* filter-overlapping-dependencies */
511  /* XXX: should really share same code path as with what's in
512  * build/reqprov.c:addReqProv()
513  */
514  int res = 0;
515  if (*depsp) {
516  int ix = rpmdsSearch(*depsp, ds);
517  if (ix >= 0) {
518  /* do not consider dependency ranges like R: foo > 1, R: foo < 3
519  * as overlapping (mdvbz#65269)
520  */
521 #define RPMSENSE_SCRIPTS (RPMSENSE_SCRIPT_PRE|RPMSENSE_SCRIPT_POST|RPMSENSE_SCRIPT_PREUN|RPMSENSE_SCRIPT_POSTUN|RPMSENSE_SCRIPT_VERIFY)
522  if (!((Flags & RPMSENSE_GREATER && (*depsp)->Flags[(*depsp)->i] & RPMSENSE_LESS) ||
523  (Flags & RPMSENSE_LESS && (*depsp)->Flags[(*depsp)->i] & RPMSENSE_GREATER)) &&
524  /* R: foo >= 1 cannot overlap R: foo <= 1*/
525  !(((Flags & RPMSENSE_GREATER) && ((*depsp)->Flags[(*depsp)->i] & RPMSENSE_LESS)) ||
526  (((*depsp)->Flags[(*depsp)->i] & RPMSENSE_GREATER) && (Flags & RPMSENSE_LESS))) &&
527  /* do not merge script dependencies with non-script dependencies */
528  !(((Flags & RPMSENSE_SCRIPTS) && !((*depsp)->Flags[(*depsp)->i] & RPMSENSE_SCRIPTS)) ||
529  (((*depsp)->Flags[(*depsp)->i] & RPMSENSE_SCRIPTS) && !(Flags & RPMSENSE_SCRIPTS))))
530  overlap = rpmdsCompare(*depsp, ds);
531 #undef RPMSENSE_SCRIPTS
532 
533  if (overlap) {
534  EVR_t lEVR = rpmEVRnew(RPMSENSE_ANY, 0),
535  rEVR = rpmEVRnew(RPMSENSE_ANY, 0);
536  rpmuint32_t newflags;
537 
538  /* if we have both a requires and suggests, we turn it into a requires */
539  if (!(Flags & RPMSENSE_MISSINGOK) || !((*depsp)->Flags[(*depsp)->i] & RPMSENSE_MISSINGOK)) {
540  (*depsp)->Flags[(*depsp)->i] &= ~RPMSENSE_MISSINGOK;
541  Flags &= ~RPMSENSE_MISSINGOK;
542  }
543 
544  /* merge all flags about dependency type */
545  newflags = (((*depsp)->Flags[(*depsp)->i]| Flags) & _ALL_REQUIRES_MASK);
546 
547  rpmdsSetIx(*depsp, ix);
548 
549  rpmEVRparse(EVR, lEVR);
550  rpmEVRparse(rpmdsEVR(*depsp), rEVR);
551  lEVR->Flags = Flags;
552  rEVR->Flags = (*depsp)->Flags[(*depsp)->i];
553 
554  res = rpmEVRcompare(lEVR, rEVR);
555  if (res == 0 && rpmdsFlags(*depsp) == rpmdsFlags(ds))
556  overlap = 0;
557  else {
558  char *oldVal = xstrdup(strchr(rpmfcFileDep(buf, fc->ix, *depsp), ' '));
559  if (res > 0) {
560  (*depsp)->Flags[(*depsp)->i] = Flags;
561  (*depsp)->EVR[(*depsp)->i] = strdup(EVR);
562  rpmlog(RPMLOG_WARNING, "%s (%s) overlaps %s (%s), removing %s\n", rpmdsDNEVR(*depsp), ix < (int)fc->nfiles ? fc->fn[ix] + fc->brlen : "explicit", rpmdsDNEVR(ds), fc->fn[fc->ix] + fc->brlen, rpmdsDNEVR(*depsp));
563  } else if (res < 0)
564  rpmlog(RPMLOG_WARNING, "%s (%s) overlaps %s (%s), removing %s\n", rpmdsDNEVR(ds), fc->fn[fc->ix] + fc->brlen, rpmdsDNEVR(*depsp), ix < (int)fc->nfiles ? fc->fn[ix] + fc->brlen : "explicit", rpmdsDNEVR(ds));
565  else if ((*depsp)->Flags[(*depsp)->i] != Flags) {
566  if (((Flags & RPMSENSE_SENSEMASK) == RPMSENSE_EQUAL) && ((*depsp)->Flags[(*depsp)->i] & (RPMSENSE_GREATER|RPMSENSE_LESS)))
567  (*depsp)->Flags[(*depsp)->i] &= ~(RPMSENSE_GREATER|RPMSENSE_LESS);
568  rpmlog(RPMLOG_WARNING, "%s (%s) overlaps %s (%s), removing %s and merging flags\n", rpmdsDNEVR(ds), fc->fn[fc->ix] + fc->brlen, rpmdsDNEVR(*depsp), ix < (int)fc->nfiles ? fc->fn[ix] + fc->brlen : "explicit", rpmdsDNEVR(ds));
569  }
570 
571  (*depsp)->Flags[(*depsp)->i] |= newflags;
572 
573  /* update references in dictionary */
574  for (ix = 0; ix < argvCount(fc->ddict); ix++) {
575  if (!strcmp(strchr(fc->ddict[ix], ' '), oldVal)) {
576  size_t fcix = atol(fc->ddict[ix]);
577  _free(fc->ddict[ix]);
578  fc->ddict[ix] = xstrdup(rpmfcFileDep(buf, fcix, *depsp));
579  }
580  }
581  argvSort(fc->ddict, NULL);
582  free(oldVal);
583  }
584 
585  lEVR = rpmEVRfree(lEVR);
586  rEVR = rpmEVRfree(rEVR);
587  }
588  }
589  }
590  if (!overlap)
591 #endif
592  /* Add to package dependencies. */
593  xx = rpmdsMerge(depsp, ds);
594 
595  /* Add to file dependencies. */
596  xx = rpmfcSaveArg(&fc->ddict, rpmfcFileDep(buf, fc->ix, overlap ? *depsp : ds));
597 
598  (void)rpmdsFree(ds);
599  ds = NULL;
600  }
601 
602  pav = argvFree(pav);
603  }
604  iob_stdout = rpmiobFree(iob_stdout);
605 
606  return 0;
607 }
608 
611 /*@-nullassign@*/
612 /*@unchecked@*/ /*@observer@*/
613 static struct rpmfcTokens_s rpmfcTokens[] = {
614  { "directory", RPMFC_DIRECTORY|RPMFC_INCLUDE },
615 
616  { " shared object", RPMFC_LIBRARY },
617  { " executable", RPMFC_EXECUTABLE },
618  { " statically linked", RPMFC_STATIC },
619  { " not stripped", RPMFC_NOTSTRIPPED },
620  { " archive", RPMFC_ARCHIVE },
621 
622  { "MIPS, N32 MIPS32", RPMFC_ELFMIPSN32|RPMFC_INCLUDE },
623  { "ELF 32-bit", RPMFC_ELF32|RPMFC_INCLUDE },
624  { "ELF 64-bit", RPMFC_ELF64|RPMFC_INCLUDE },
625 
626  { " script", RPMFC_SCRIPT },
627  { " text", RPMFC_TEXT },
628  { " document", RPMFC_DOCUMENT },
629 
630  { " compressed", RPMFC_COMPRESSED },
631 
632  { "troff or preprocessor input", RPMFC_MANPAGE|RPMFC_INCLUDE },
633  { "GNU Info", RPMFC_MANPAGE|RPMFC_INCLUDE },
634 
635  { "perl script text", RPMFC_PERL|RPMFC_INCLUDE },
636  { "Perl5 module source text", RPMFC_PERL|RPMFC_MODULE|RPMFC_INCLUDE },
637 
638  { "NodeJS script text", RPMFC_NODEJS|RPMFC_INCLUDE },
639  { "PHP script text", RPMFC_PHP|RPMFC_INCLUDE },
640  { "G-IR binary database", RPMFC_TYPELIB|RPMFC_INCLUDE },
641 
642  /* XXX "a /usr/bin/python -t script text executable" */
643  /* XXX "python 2.3 byte-compiled" */
644  { " /usr/bin/python", RPMFC_PYTHON|RPMFC_INCLUDE },
645  { "python ", RPMFC_PYTHON|RPMFC_INCLUDE },
646  { "Python script", RPMFC_PYTHON|RPMFC_INCLUDE },
647 
648  { "libtool library ", RPMFC_LIBTOOL|RPMFC_INCLUDE },
649  { "pkgconfig ", RPMFC_PKGCONFIG|RPMFC_INCLUDE },
650  { "qml ", RPMFC_QML|RPMFC_INCLUDE },
651 
652  { "Bourne ", RPMFC_BOURNE|RPMFC_INCLUDE },
653  { "Bourne-Again ", RPMFC_BOURNE|RPMFC_INCLUDE },
654 
655  { "Java ", RPMFC_JAVA|RPMFC_INCLUDE },
656 
657  { "Mono/.Net assembly", RPMFC_MONO|RPMFC_INCLUDE },
658 
659  { "ruby script text", RPMFC_RUBY|RPMFC_INCLUDE },
660  { "Ruby script text", RPMFC_RUBY|RPMFC_INCLUDE },
661 
662  { "current ar archive", RPMFC_STATIC|RPMFC_LIBRARY|RPMFC_ARCHIVE|RPMFC_INCLUDE },
663 
664  { "Zip archive data", RPMFC_COMPRESSED|RPMFC_ARCHIVE|RPMFC_INCLUDE },
665  { "tar archive", RPMFC_ARCHIVE|RPMFC_INCLUDE },
666  { "cpio archive", RPMFC_ARCHIVE|RPMFC_INCLUDE },
667  { "RPM v3", RPMFC_ARCHIVE|RPMFC_INCLUDE },
668  { "RPM v4", RPMFC_ARCHIVE|RPMFC_INCLUDE },
669 
670  { " image", RPMFC_IMAGE|RPMFC_INCLUDE },
671  { " font", RPMFC_FONT|RPMFC_INCLUDE },
672  { " Font", RPMFC_FONT|RPMFC_INCLUDE },
673 
674  { " commands", RPMFC_SCRIPT|RPMFC_INCLUDE },
675  { " script", RPMFC_SCRIPT|RPMFC_INCLUDE },
676 
677  { "empty", RPMFC_WHITE|RPMFC_INCLUDE },
678 
679  { "HTML", RPMFC_WHITE|RPMFC_INCLUDE },
680  { "SGML", RPMFC_WHITE|RPMFC_INCLUDE },
681  { "XML", RPMFC_WHITE|RPMFC_INCLUDE },
682 
683  { " program text", RPMFC_WHITE|RPMFC_INCLUDE },
684  { " source", RPMFC_WHITE|RPMFC_INCLUDE },
685  { "GLS_BINARY_LSB_FIRST", RPMFC_WHITE|RPMFC_INCLUDE },
686  { " DB ", RPMFC_WHITE|RPMFC_INCLUDE },
687 
688  { "ASCII English text", RPMFC_WHITE|RPMFC_INCLUDE },
689  { "ASCII text", RPMFC_WHITE|RPMFC_INCLUDE },
690  { "ISO-8859 text", RPMFC_WHITE|RPMFC_INCLUDE },
691 
692  { "symbolic link to", RPMFC_SYMLINK },
693  { "socket", RPMFC_DEVICE },
694  { "special", RPMFC_DEVICE },
695 
696  { "ASCII", RPMFC_WHITE },
697  { "ISO-8859", RPMFC_WHITE },
698 
699  { "data", RPMFC_WHITE },
700 
701  { "application", RPMFC_WHITE },
702  { "boot", RPMFC_WHITE },
703  { "catalog", RPMFC_WHITE },
704  { "code", RPMFC_WHITE },
705  { "file", RPMFC_WHITE },
706  { "format", RPMFC_WHITE },
707  { "message", RPMFC_WHITE },
708  { "program", RPMFC_WHITE },
709 
710  { "broken symbolic link to ", RPMFC_WHITE|RPMFC_ERROR },
711  { "can't read", RPMFC_WHITE|RPMFC_ERROR },
712  { "can't stat", RPMFC_WHITE|RPMFC_ERROR },
713  { "executable, can't read", RPMFC_WHITE|RPMFC_ERROR },
714  { "core file", RPMFC_WHITE|RPMFC_ERROR },
715 
716  { NULL, RPMFC_BLACK }
717 };
718 /*@=nullassign@*/
719 
720 int rpmfcColoring(const char * fmstr)
721 {
722  rpmfcToken fct;
723  int fcolor = RPMFC_BLACK;
724 
725  for (fct = rpmfcTokens; fct->token != NULL; fct++) {
726  if (strstr(fmstr, fct->token) == NULL)
727  continue;
728  fcolor |= fct->colors;
729  if (fcolor & RPMFC_INCLUDE)
730  return fcolor;
731  }
732  return fcolor;
733 }
734 
735 void rpmfcPrint(const char * msg, rpmfc fc, FILE * fp)
736 {
737  int fcolor;
738  int ndx;
739  int cx;
740  int dx;
741  size_t fx;
742 
743 unsigned nprovides;
744 unsigned nrequires;
745 
746  if (fp == NULL) fp = stderr;
747 
748  if (msg)
749  fprintf(fp, "===================================== %s\n", msg);
750 
751 nprovides = rpmdsCount(fc->provides);
752 nrequires = rpmdsCount(fc->requires);
753 
754  if (fc)
755  for (fx = 0; fx < fc->nfiles; fx++) {
756 assert(fx < fc->fcdictx->nvals);
757  cx = fc->fcdictx->vals[fx];
758 assert(fx < fc->fcolor->nvals);
759  fcolor = fc->fcolor->vals[fx];
760 
761  fprintf(fp, "%3d %s", (int)fx, fc->fn[fx]);
762  if (fcolor != RPMFC_BLACK)
763  fprintf(fp, "\t0x%x", fc->fcolor->vals[fx]);
764  else
765  fprintf(fp, "\t%s", fc->cdict[cx]);
766  fprintf(fp, "\n");
767 
768  if (fc->fddictx == NULL || fc->fddictn == NULL)
769  continue;
770 
771 assert(fx < fc->fddictx->nvals);
772  dx = fc->fddictx->vals[fx];
773 assert(fx < fc->fddictn->nvals);
774  ndx = fc->fddictn->vals[fx];
775 
776  while (ndx-- > 0) {
777  const char * depval;
778  unsigned char deptype;
779  unsigned ix;
780 
781  ix = fc->ddictx->vals[dx++];
782  deptype = ((ix >> 24) & 0xff);
783  ix &= 0x00ffffff;
784  depval = NULL;
785  switch (deptype) {
786  default:
787 assert(depval != NULL);
788  /*@switchbreak@*/ break;
789  case 'P':
790  if (nprovides > 0) {
791 assert(ix < nprovides);
792  (void) rpmdsSetIx(fc->provides, ix-1);
793  if (rpmdsNext(fc->provides) >= 0)
794  depval = rpmdsDNEVR(fc->provides);
795  }
796  /*@switchbreak@*/ break;
797  case 'R':
798  if (nrequires > 0) {
799 assert(ix < nrequires);
800  (void) rpmdsSetIx(fc->requires, ix-1);
801  if (rpmdsNext(fc->requires) >= 0)
802  depval = rpmdsDNEVR(fc->requires);
803  }
804  /*@switchbreak@*/ break;
805  }
806  if (depval)
807  fprintf(fp, "\t%s\n", depval);
808  }
809  }
810 }
811 
817 static int rpmfcSCRIPT(rpmfc fc)
818  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
819  /*@modifies fc, rpmGlobalMacroContext, fileSystem, internalState @*/
820 {
821  const char * fn = fc->fn[fc->ix];
822  const char * bn;
823  rpmds ds;
824  char buf[BUFSIZ];
825  FILE * fp;
826  char * s, * se;
827  int i;
828  int is_executable;
829  int xx;
830 
831  /* Don't generate dependencies from files shipped as documentation */
832  if (!rpmExpandNumeric("%{_generate_dependencies_from_docdir}")) {
833  const char * defaultdocdir = rpmExpand("%{?_defaultdocdir}", NULL);
834  if (defaultdocdir == NULL || *defaultdocdir == '\0')
835  defaultdocdir = strdup("/usr/share/doc");
836  xx = !strncmp(fn+fc->brlen, defaultdocdir, strlen(defaultdocdir));
837  defaultdocdir = _free(defaultdocdir) ;
838  if (xx)
839  return 0;
840  }
841 
842  /* Extract dependencies only from files with executable bit set. */
843  { struct stat sb, * st = &sb;
844  if (stat(fn, st) != 0)
845  return -1;
846  is_executable = (int)(st->st_mode & (S_IXUSR|S_IXGRP|S_IXOTH));
847  }
848 
849  fp = fopen(fn, "r");
850  if (fp == NULL || ferror(fp)) {
851  if (fp) (void) fclose(fp);
852  return -1;
853  }
854 
855  /* Look for #! interpreter in first 10 lines. */
856  for (i = 0; i < 10; i++) {
857 
858  s = fgets(buf, sizeof(buf) - 1, fp);
859  if (s == NULL || ferror(fp) || feof(fp))
860  break;
861  s[sizeof(buf)-1] = '\0';
862  if (!(s[0] == '#' && s[1] == '!'))
863  continue;
864  s += 2;
865 
866  while (*s && strchr(" \t\n\r", *s) != NULL)
867  s++;
868  if (*s == '\0')
869  continue;
870  if (*s != '/')
871  continue;
872 
873  for (se = s+1; *se; se++) {
874  if (strchr(" \t\n\r", *se) != NULL)
875  /*@innerbreak@*/ break;
876  }
877  *se = '\0';
878  se++;
879 
880 /*@-moduncon@*/
881  bn = basename(s);
882 
883  if (!_filter_values
884  || (!fc->skipReq
885  && !rpmfcMatchRegexps(fc->Rmires, fc->Rnmire, s, 'R'))) {
886  if (is_executable &&
887  strncmp(bn, "bash", sizeof("bash")-1) &&
888  strcmp(bn, "env") &&
889  strncmp(bn, "perl", sizeof("perl")-1) &&
890  strncmp(bn, "python", sizeof("python")-1) &&
891  strncmp(bn, "ruby", sizeof("ruby")-1) &&
892  strcmp(bn, "sh")) {
893  /* Add to package requires. */
894  ds = rpmdsSingle(RPMTAG_REQUIRENAME, s, "", RPMSENSE_FIND_REQUIRES);
895  xx = rpmdsMerge(&fc->requires, ds);
896 
897  /* Add to file requires. */
898  xx = rpmfcSaveArg(&fc->ddict, rpmfcFileDep(se, fc->ix, ds));
899 
900  (void)rpmdsFree(ds);
901  ds = NULL;
902  } else if (!strcmp(bn, "env") && strlen(se)) {
903  bn = se;
904  strsep(&se, " \t\n\r");
905  }
906  }
907 
908  /* Set color based on interpreter name. */
909  /* XXX magic token should have already done this?!? */
910 /*@=moduncon@*/
911  if (!strcmp(bn, "perl"))
912  fc->fcolor->vals[fc->ix] |= RPMFC_PERL;
913  else if (!strncmp(bn, "python", sizeof("python")-1))
914  fc->fcolor->vals[fc->ix] |= RPMFC_PYTHON;
915  else if (!strncmp(bn, "php", sizeof("php")-1))
916  fc->fcolor->vals[fc->ix] |= RPMFC_PHP;
917  else if (!strncmp(bn, "json", sizeof("json")-1))
918  fc->fcolor->vals[fc->ix] |= RPMFC_NODEJS;
919  else if (!strncmp(bn, "ruby", sizeof("ruby")-1))
920  fc->fcolor->vals[fc->ix] |= RPMFC_RUBY;
921 
922  break;
923  }
924 
925  (void) fclose(fp);
926 
927  if (fc->fcolor->vals[fc->ix] & RPMFC_PERL) {
928  if (fc->fcolor->vals[fc->ix] & RPMFC_MODULE)
929  xx = rpmfcHelper(fc, 'P', "perl");
930  if (is_executable || (fc->fcolor->vals[fc->ix] & RPMFC_MODULE))
931  xx = rpmfcHelper(fc, 'R', "perl");
932  } else
933  if (fc->fcolor->vals[fc->ix] & RPMFC_PYTHON) {
934  if (fc->fcolor->vals[fc->ix] & RPMFC_MODULE && !(fc->fcolor->vals[fc->ix] & RPMFC_SCRIPT))
935  xx = rpmfcHelper(fc, 'P', "python");
936  if (is_executable || (fc->fcolor->vals[fc->ix] & RPMFC_MODULE))
937  xx = rpmfcHelper(fc, 'R', "python");
938  } else
939  if (fc->fcolor->vals[fc->ix] & RPMFC_NODEJS) {
940  xx = rpmfcHelper(fc, 'P', "nodejs");
941  xx = rpmfcHelper(fc, 'R', "nodejs");
942  } else
943  if (fc->fcolor->vals[fc->ix] & RPMFC_LIBTOOL) {
944  xx = rpmfcHelper(fc, 'P', "libtool");
945 #ifdef NOTYET
946  if (is_executable)
947 #endif
948  xx = rpmfcHelper(fc, 'R', "libtool");
949  } else
950  if (fc->fcolor->vals[fc->ix] & RPMFC_PKGCONFIG) {
951  xx = rpmfcHelper(fc, 'P', "pkgconfig");
952 #ifdef NOTYET
953  if (is_executable)
954 #endif
955  xx = rpmfcHelper(fc, 'R', "pkgconfig");
956  } else
957  if (fc->fcolor->vals[fc->ix] & RPMFC_QML) {
958  xx = rpmfcHelper(fc, 'P', "qml");
959 // xx = rpmfcHelper(fc, 'R', "qml");
960  } else
961  if (fc->fcolor->vals[fc->ix] & RPMFC_BOURNE) {
962 #ifdef NOTYET
963  xx = rpmfcHelper(fc, 'P', "executable");
964 #endif
965  if (is_executable)
966  xx = rpmfcHelper(fc, 'R', "executable");
967  } else
968  if (fc->fcolor->vals[fc->ix] & RPMFC_PHP) {
969  xx = rpmfcHelper(fc, 'P', "php");
970 #ifdef NOTYET
971  if (is_executable)
972 #endif
973  xx = rpmfcHelper(fc, 'R', "php");
974  } else
975  if (fc->fcolor->vals[fc->ix] & RPMFC_MONO) {
976  xx = rpmfcHelper(fc, 'P', "mono");
977  if (is_executable)
978  xx = rpmfcHelper(fc, 'R', "mono");
979  } else
980  if (fc->fcolor->vals[fc->ix] & RPMFC_RUBY) {
981  if (fc->fcolor->vals[fc->ix] & RPMFC_MODULE)
982  xx = rpmfcHelper(fc, 'P', "ruby");
983  if (is_executable || (fc->fcolor->vals[fc->ix] & RPMFC_MODULE))
984  xx = rpmfcHelper(fc, 'R', "ruby");
985  } else
986  if ((fc->fcolor->vals[fc->ix] == (RPMFC_FONT|RPMFC_INCLUDE))) {
987  xx = rpmfcHelper(fc, 'P', "font");
988  /* XXX: currently of no use, but for the sake of consistency... */
989  xx = rpmfcHelper(fc, 'R', "font");
990  } else
991  if (fc->fcolor->vals[fc->ix] & RPMFC_HASKELL) {
992  xx = rpmfcHelper(fc, 'P', "haskell");
993  xx = rpmfcHelper(fc, 'R', "haskell");
994  } else
995  if (fc->fcolor->vals[fc->ix] & RPMFC_TYPELIB) {
996  xx = rpmfcHelper(fc, 'P', "typelib");
997 #ifdef NOTYET
998  if (is_executable)
999 #endif
1000  xx = rpmfcHelper(fc, 'R', "typelib");
1001  } else
1002  if ((fc->fcolor->vals[fc->ix] & (RPMFC_MODULE|RPMFC_LIBRARY)) &&
1003  strstr(fn, "/gstreamer")) {
1004  xx = rpmfcHelper(fc, 'P', "gstreamer");
1005  /* XXX: currently of no use, but for the sake of consistency... */
1006  xx = rpmfcHelper(fc, 'R', "gstreamer");
1007 #if defined(RPM_VENDOR_MANDRIVA)
1008  } else
1009  if ((fc->fcolor->vals[fc->ix] & RPMFC_MODULE)) {
1011  if (!mireRegcomp(mire, "^.*((/lib/modules/|/var/lib/dkms/).*\\.ko(\\.gz|\\.xz)?|(/var/lib/dkms-binary/[^/]+/[^/]+|/usr/src)/[^/]+/dkms.conf)$"))
1012  if (mireRegexec(mire, fc->fn[fc->ix], (size_t) 0) >= 0) {
1013  fc->fcolor->vals[fc->ix] |= (RPMFC_MODULE|RPMFC_SCRIPT);
1014  xx = rpmfcHelper(fc, 'P', "kernel");
1015  /* XXX: currently of no use, but for the sake of consistency... */
1016  xx = rpmfcHelper(fc, 'R', "kernel");
1017  }
1018  mire = mireFree(mire);
1019  }
1020  if ((fc->fcolor->vals[fc->ix] & RPMFC_SCRIPT)) {
1022  if (!mireRegcomp(mire, "^.*/usr/share/applications/.*\\.desktop$"))
1023  if (mireRegexec(mire, fc->fn[fc->ix], (size_t) 0) >= 0) {
1024  fc->fcolor->vals[fc->ix] |= (RPMFC_MODULE|RPMFC_SCRIPT);
1025  xx = rpmfcHelper(fc, 'P', "desktop");
1026  /* XXX: currently of no use, but for the sake of consistency... */
1027  xx = rpmfcHelper(fc, 'R', "desktop");
1028  }
1029  mire = mireFree(mire);
1030 #endif
1031  }
1032 
1033 /*@=observertrans@*/
1034  return 0;
1035 }
1036 
1043 static int rpmfcMergePR(void * context, rpmds ds)
1044  /*@globals fileSystem, internalState @*/
1045  /*@modifies ds, fileSystem, internalState @*/
1046 {
1047  rpmfc fc = (rpmfc) context;
1048  char buf[BUFSIZ];
1049  int rc = 0;
1050 
1051 if (_rpmfc_debug < 0)
1052 fprintf(stderr, "*** rpmfcMergePR(%p, %p) %s\n", context, ds, tagName(rpmdsTagN(ds)));
1053  switch(rpmdsTagN(ds)) {
1054  default:
1055  rc = -1;
1056  break;
1057  case RPMTAG_PROVIDENAME:
1058  if (!_filter_values
1059  || (!fc->skipProv
1060  && !rpmfcMatchRegexps(fc->Pmires, fc->Pnmire, ds->N[0], 'P')))
1061  {
1062  /* Add to package provides. */
1063  rc = rpmdsMerge(&fc->provides, ds);
1064 
1065  /* Add to file dependencies. */
1066  buf[0] = '\0';
1067  rc = rpmfcSaveArg(&fc->ddict, rpmfcFileDep(buf, fc->ix, ds));
1068  }
1069  break;
1070  case RPMTAG_REQUIRENAME:
1071  if (!_filter_values
1072  || (!fc->skipReq
1073  && !rpmfcMatchRegexps(fc->Rmires, fc->Rnmire, ds->N[0], 'R')))
1074  {
1075  /* Add to package requires. */
1076  rc = rpmdsMerge(&fc->requires, ds);
1077 
1078  /* Add to file dependencies. */
1079  buf[0] = '\0';
1080  rc = rpmfcSaveArg(&fc->ddict, rpmfcFileDep(buf, fc->ix, ds));
1081  }
1082  break;
1083  }
1084  return rc;
1085 }
1086 
1092 static int rpmfcELF(rpmfc fc)
1093  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1094  /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
1095 {
1096  const char * fn = fc->fn[fc->ix];
1097  int flags = 0;
1098 
1099  if (fc->skipProv)
1100  flags |= RPMELF_FLAG_SKIPPROVIDES;
1101  if (fc->skipReq)
1102  flags |= RPMELF_FLAG_SKIPREQUIRES;
1103 
1104  return rpmdsELF(fn, flags, rpmfcMergePR, fc);
1105 }
1106 
1107 #if defined(RPM_VENDOR_MANDRIVA)
1108 
1117 extern int rpmdsSymlink(const char * fn, int flags,
1118  int (*add) (void * context, rpmds ds), void * context)
1119  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1120  /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/;
1121 
1122 static int rpmfcSYMLINK(rpmfc fc)
1123  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1124  /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
1125 {
1126  const char * fn = fc->fn[fc->ix];
1127  int flags = 0;
1128 
1129  if (fc->skipProv)
1130  flags |= RPMELF_FLAG_SKIPPROVIDES;
1131  if (fc->skipReq)
1132  flags |= RPMELF_FLAG_SKIPREQUIRES;
1133  /* XXX: Remove symlink classifier from linker scripts now that we've been
1134  * able to feed it to the generator.
1135  */
1136  if (fc->fcolor->vals[fc->ix] == (RPMFC_WHITE|RPMFC_INCLUDE|RPMFC_TEXT|RPMFC_SYMLINK))
1137  fc->fcolor->vals[fc->ix] &= ~RPMFC_SYMLINK;
1138 
1139  return rpmdsSymlink(fn, flags, rpmfcMergePR, fc);
1140 }
1141 #endif /* RPM_VENDOR_MANDRIVA */
1142 
1143 typedef struct rpmfcApplyTbl_s {
1144  int (*func) (rpmfc fc);
1146 } * rpmfcApplyTbl;
1147 
1151 /*@-nullassign@*/
1152 /*@unchecked@*/
1154  { rpmfcELF, RPMFC_ELF },
1156 #if defined(RPM_VENDOR_MANDRIVA)
1157  { rpmfcSYMLINK, RPMFC_SYMLINK },
1158 #endif
1159  { NULL, 0 }
1160 };
1161 /*@=nullassign@*/
1162 
1164 {
1165  rpmfcApplyTbl fcat;
1166  const char * s;
1167  char * se;
1168  rpmds ds;
1169  const char * fn;
1170  const char * N;
1171  const char * EVR;
1172  evrFlags Flags;
1173  unsigned char deptype;
1174  int nddict;
1175  int previx;
1176  unsigned int val;
1177  int dix;
1178  int ix;
1179  int i;
1180  int xx;
1181  int skipping;
1182 
1183  miRE mire;
1184  int skipProv = fc->skipProv;
1185  int skipReq = fc->skipReq;
1186  int j;
1187 
1188  if (_filter_execs) {
1189  fc->PFnmire = 0;
1190  fc->PFmires = rpmfcExpandRegexps("%{?__noautoprovfiles}", &fc->PFnmire);
1191  if (fc->PFnmire > 0)
1192  rpmlog(RPMLOG_DEBUG, D_("added %d %%__noautoprovfiles patterns.\n"),
1193  fc->PFnmire);
1194  fc->RFnmire = 0;
1195  fc->RFmires = rpmfcExpandRegexps("%{?__noautoreqfiles}", &fc->RFnmire);
1196  if (fc->RFnmire > 0)
1197  rpmlog(RPMLOG_DEBUG, D_("added %d %%__noautoreqfiles patterns.\n"),
1198  fc->RFnmire);
1199  fc->Pnmire = 0;
1200  fc->Pmires = rpmfcExpandRegexps("%{?__noautoprov}", &fc->Pnmire);
1201  if (fc->Pnmire > 0)
1202  rpmlog(RPMLOG_DEBUG, D_("added %d %%__noautoprov patterns.\n"),
1203  fc->Pnmire);
1204  fc->Rnmire = 0;
1205  fc->Rmires = rpmfcExpandRegexps("%{?__noautoreq}", &fc->Rnmire);
1206  if (fc->Rnmire > 0)
1207  rpmlog(RPMLOG_DEBUG, D_("added %d %%__noautoreq patterns.\n"),
1208  fc->Rnmire);
1209  }
1210 
1211 /* Make sure something didn't go wrong previously! */
1212 assert(fc->fn != NULL);
1213  /* Generate package and per-file dependencies. */
1214  for (fc->ix = 0; fc->fn[fc->ix] != NULL; fc->ix++) {
1215 
1216  /* XXX Insure that /usr/lib{,64}/python files are marked RPMFC_PYTHON */
1217  /* XXX HACK: classification by path is intrinsically stupid. */
1218  { fn = strstr(fc->fn[fc->ix], "/usr/lib");
1219  if (fn) {
1220  fn += sizeof("/usr/lib")-1;
1221  if ((fn[0] == '3' && fn[1] == '2') ||
1222  (fn[0] == '6' && fn[1] == '4'))
1223  fn += 2;
1224  if (!strncmp(fn, "/python", sizeof("/python")-1)) {
1225  fc->fcolor->vals[fc->ix] |= RPMFC_PYTHON;
1226  if (strstr(fn, "site-packages"))
1227  fc->fcolor->vals[fc->ix] |= RPMFC_MODULE;
1228  else if (strstr(fn, ".egg")) {
1230  if (!mireRegcomp(mire, ".*/.*\\.egg(|-info|-link)(|/.*)$"))
1231  if (mireRegexec(mire, fc->fn[fc->ix], (size_t) 0) >= 0)
1232  fc->fcolor->vals[fc->ix] |= RPMFC_MODULE;
1233  mire = mireFree(mire);
1234  }
1235  }
1236  else if (!strncmp(fn, "/ruby", sizeof("/ruby")-1)) {
1237  fc->fcolor->vals[fc->ix] |= RPMFC_RUBY;
1238  if ((strstr(fn, ".gemspec") || strstr(fn, "rbconfig.rb"))) {
1240  if (!mireRegcomp(mire, ".*/(specifications/.*\\.gemspec|rbconfig\\.rb)$"))
1241  if (mireRegexec(mire, fc->fn[fc->ix], (size_t) 0) >= 0)
1242  fc->fcolor->vals[fc->ix] |= RPMFC_MODULE;
1243  mire = mireFree(mire);
1244  }
1245  }
1246  /* XXX: lacking better, more generic classifier... */
1247  else if (!strncmp(fn, "/gstreamer", sizeof("/gstreamer")-1) &&
1248  fc->fcolor->vals[fc->ix] & RPMFC_LIBRARY)
1249  fc->fcolor->vals[fc->ix] |= (RPMFC_MODULE|RPMFC_SCRIPT);
1250 #if defined(RPM_VENDOR_MANDRIVA)
1251  } else {
1253  if (!mireRegcomp(mire, "^.*((/lib/modules/|/var/lib/dkms/).*\\.ko(\\.gz|\\.xz)?|(/var/lib/dkms-binary/[^/]+/[^/]+|/usr/src)/[^/]+/dkms.conf)$"))
1254  if (mireRegexec(mire, fc->fn[fc->ix], (size_t) 0) >= 0)
1255  fc->fcolor->vals[fc->ix] |= (RPMFC_MODULE|RPMFC_SCRIPT);
1256  mire = mireFree(mire);
1258  /* buttfuckin' retarded, but whatever.. it'll work at least! ;) */
1259  if (!mireRegcomp(mire, "^.*/usr/share/applications/.*\\.desktop$"))
1260  if (mireRegexec(mire, fc->fn[fc->ix], (size_t) 0) >= 0)
1261  fc->fcolor->vals[fc->ix] |= RPMFC_SCRIPT;
1262  mire = mireFree(mire);
1263 #endif
1264  }
1265  }
1266 
1267  /* XXX ugly quick & dirty integration of haskell() dependencies */
1268  { fn = strstr(fc->fn[fc->ix], "/usr/share/haskell-deps");
1269  if (fn)
1270  fc->fcolor->vals[fc->ix] |= RPMFC_HASKELL;
1271  }
1272 
1273  if (fc->fcolor->vals[fc->ix])
1274  for (fcat = rpmfcApplyTable; fcat->func != NULL; fcat++) {
1275  if (!(fc->fcolor->vals[fc->ix] & fcat->colormask))
1276  /*@innercontinue@*/ continue;
1277 
1278  if (_filter_execs) {
1279  fc->skipProv = skipProv;
1280  fc->skipReq = skipReq;
1281  if ((mire = (miRE)fc->PFmires) != NULL)
1282  for (j = 0; j < fc->PFnmire; j++, mire++) {
1283  fn = fc->fn[fc->ix] + fc->brlen;
1284  if ((xx = mireRegexec(mire, fn, 0)) < 0)
1285  /*@innercontinue@*/ continue;
1286  rpmlog(RPMLOG_NOTICE, _("skipping %s provides detection\n"),
1287  fn);
1288  fc->skipProv = 1;
1289  /*@innerbreak@*/ break;
1290  }
1291  if ((mire = (miRE)fc->RFmires) != NULL)
1292  for (j = 0; j < fc->RFnmire; j++, mire++) {
1293  fn = fc->fn[fc->ix] + fc->brlen;
1294  if ((xx = mireRegexec(mire, fn, 0)) < 0)
1295  /*@innercontinue@*/ continue;
1296  rpmlog(RPMLOG_NOTICE, _("skipping %s requires detection\n"),
1297  fn);
1298  fc->skipReq = 1;
1299  /*@innerbreak@*/ break;
1300  }
1301  }
1302 
1303  struct stat sb, * st = &sb;
1304  if (stat(fc->fn[fc->ix], st) == 0 && !(st->st_mode & (S_IFBLK|S_IFCHR)))
1305  xx = (*fcat->func) (fc);
1306  }
1307  }
1308 
1309  if (_filter_execs) {
1310  fc->PFmires = rpmfcFreeRegexps(fc->PFmires, fc->PFnmire);
1311  fc->RFmires = rpmfcFreeRegexps(fc->RFmires, fc->RFnmire);
1312  fc->Pmires = rpmfcFreeRegexps(fc->Pmires, fc->Pnmire);
1313  fc->Rmires = rpmfcFreeRegexps(fc->Rmires, fc->Rnmire);
1314  }
1315  fc->skipProv = skipProv;
1316  fc->skipReq = skipReq;
1317 
1318  /* Generate per-file indices into package dependencies. */
1319  nddict = argvCount(fc->ddict);
1320  previx = -1;
1321  for (i = 0; i < nddict; i++) {
1322  s = fc->ddict[i];
1323 
1324  /* Parse out (file#,deptype,N,EVR,Flags) */
1325  ix = strtol(s, &se, 10);
1326 assert(se != NULL);
1327  deptype = *se++;
1328  se++;
1329  N = se;
1330  while (*se && *se != ' ')
1331  se++;
1332  *se++ = '\0';
1333  EVR = se;
1334  while (*se && *se != ' ')
1335  se++;
1336  *se++ = '\0';
1337  Flags = (evrFlags) strtol(se, NULL, 16);
1338 
1339  dix = -1;
1340  skipping = 0;
1341  switch (deptype) {
1342  default:
1343  /*@switchbreak@*/ break;
1344  case 'P':
1345  skipping = fc->skipProv;
1346  ds = rpmdsSingle(RPMTAG_PROVIDENAME, N, EVR, Flags);
1347  dix = rpmdsFind(fc->provides, ds);
1348  (void)rpmdsFree(ds);
1349  ds = NULL;
1350  /*@switchbreak@*/ break;
1351  case 'R':
1352  skipping = fc->skipReq;
1353  ds = rpmdsSingle(RPMTAG_REQUIRENAME, N, EVR, Flags);
1354  dix = rpmdsFind(fc->requires, ds);
1355  (void)rpmdsFree(ds);
1356  ds = NULL;
1357  /*@switchbreak@*/ break;
1358  }
1359 
1360 /* XXX assertion incorrect while generating -debuginfo deps. */
1361 #if 0
1362 assert(dix >= 0);
1363 #else
1364  if (dix < 0)
1365  continue;
1366 #endif
1367 
1368  val = (deptype << 24) | (dix & 0x00ffffff);
1369  xx = argiAdd(&fc->ddictx, -1, val);
1370 
1371  if (previx != ix) {
1372  previx = ix;
1373  xx = argiAdd(&fc->fddictx, ix, argiCount(fc->ddictx)-1);
1374  }
1375  if (fc->fddictn && fc->fddictn->vals && !skipping)
1376  fc->fddictn->vals[ix]++;
1377  }
1378 
1379  return RPMRC_OK;
1380 }
1381 
1383 {
1384  ARGV_t fcav = NULL;
1385  ARGV_t dav;
1386  rpmmg mg = NULL;
1387  const char * s, * se;
1388  size_t slen;
1389  int fcolor;
1390  int xx;
1391  const char * magicfile = NULL;
1392 
1393  if (fc == NULL || argv == NULL)
1394  return RPMRC_OK;
1395 
1396  magicfile = rpmExpand("%{?_rpmfc_magic_path}", NULL);
1397  if (magicfile == NULL || *magicfile == '\0')
1398  magicfile = _free(magicfile);
1399 
1400  mg = rpmmgNew(magicfile, 0);
1401 assert(mg != NULL); /* XXX figger a proper return path. */
1402 
1403  fc->nfiles = argvCount(argv);
1404 
1405  /* Initialize the per-file dictionary indices. */
1406  xx = argiAdd(&fc->fddictx, fc->nfiles-1, 0);
1407  xx = argiAdd(&fc->fddictn, fc->nfiles-1, 0);
1408 
1409  /* Build (sorted) file class dictionary. */
1410  xx = argvAdd(&fc->cdict, "");
1411  xx = argvAdd(&fc->cdict, "directory");
1412 
1413  for (fc->ix = 0; fc->ix < fc->nfiles; fc->ix++) {
1414  const char * ftype;
1415  int freeftype;
1416  rpmuint16_t mode = (fmode ? fmode[fc->ix] : 0);
1417  int urltype;
1418 
1419  ftype = ""; freeftype = 0;
1420  urltype = urlPath(argv[fc->ix], &s);
1421 assert(s != NULL && *s == '/');
1422  slen = strlen(s);
1423 
1424  switch (mode & S_IFMT) {
1425  case S_IFCHR: ftype = "character special"; /*@switchbreak@*/ break;
1426  case S_IFBLK: ftype = "block special"; /*@switchbreak@*/ break;
1427 #if defined(S_IFIFO)
1428  case S_IFIFO: ftype = "fifo (named pipe)"; /*@switchbreak@*/ break;
1429 #endif
1430 #if defined(S_IFSOCK)
1431 /*@-unrecog@*/
1432  case S_IFSOCK: ftype = "socket"; /*@switchbreak@*/ break;
1433 /*@=unrecog@*/
1434 #endif
1435  case S_IFDIR:
1436  case S_IFLNK:
1437  case S_IFREG:
1438  default:
1439 
1440 #define _suffix(_s, _x) \
1441  (slen >= sizeof(_x) && !strcmp((_s)+slen-(sizeof(_x)-1), (_x)))
1442 
1443  /* XXX all files with extension ".pm" are perl modules for now. */
1444  if (_suffix(s, ".pm"))
1445  ftype = "Perl5 module source text";
1446 
1447  /* XXX all files with extension ".jar" are java archives for now. */
1448  else if (_suffix(s, ".jar"))
1449  ftype = "Java archive file";
1450 
1451  /* XXX all files with extension ".class" are java class files for now. */
1452  else if (_suffix(s, ".class"))
1453  ftype = "Java class file";
1454 
1455  /* XXX all files with extension ".la" are libtool for now. */
1456  else if (_suffix(s, ".la"))
1457  ftype = "libtool library file";
1458 
1459  /* XXX all files with extension ".pc" are pkgconfig for now. */
1460  else if (_suffix(s, ".pc"))
1461  ftype = "pkgconfig file";
1462 
1463  /* XXX all files with extension ".qml" are qml for now. */
1464  else if (_suffix(s, ".qml"))
1465  ftype = "qml file";
1466 
1467  /* XXX all files named "qmldir" are qml for now. */
1468  else if (_suffix(s, "qmldir"))
1469  ftype = "qml file";
1470 
1471  /* XXX all files with extension ".php" are PHP for now. */
1472  else if (_suffix(s, ".php"))
1473  ftype = "PHP script text";
1474 
1475  /* XXX all files with extension ".json" are NodeJS for now. */
1476  else if (_suffix(s, ".json"))
1477  ftype = "NodeJS script text";
1478 
1479  /* XXX files with extension ".typelib" are GNOME typelib for now. */
1480  else if (_suffix(s, ".typelib"))
1481  ftype = "G-IR binary database";
1482 
1483  /* XXX files with extension ".js" have GNOME typelib requires for now */
1484  else if (_suffix(s, ".js"))
1485  ftype = "G-IR binary database";
1486 
1487  /* XXX skip all files in /dev/ which are (or should be) %dev dummies. */
1488  else if (slen >= fc->brlen+sizeof("/dev/") && !strncmp(s+fc->brlen, "/dev/", sizeof("/dev/")-1))
1489  ftype = "";
1490  else if (magicfile) {
1491  ftype = rpmmgFile(mg, s);
1492 assert(ftype != NULL); /* XXX never happens, rpmmgFile() returns "" */
1493  freeftype = 1;
1494  }
1495  /*@switchbreak@*/ break;
1496  }
1497 
1498  se = ftype;
1499 
1500 if (_rpmfc_debug) /* XXX noisy */
1501  rpmlog(RPMLOG_DEBUG, "%s: %s\n", s, se);
1502 
1503  /* Save the path. */
1504  xx = argvAdd(&fc->fn, s);
1505 
1506  /* Save the file type string. */
1507  xx = argvAdd(&fcav, se);
1508 
1509  /* Add (filtered) entry to sorted class dictionary. */
1510  fcolor = rpmfcColoring(se);
1511 
1512  /* Quick&dirty hack for linker scripts replacing regular
1513  * symlinks. Better *really* needs to be done ASAP.
1514  */
1515 #if defined(RPM_VENDOR_MANDRIVA)
1516  if (fcolor == (RPMFC_WHITE|RPMFC_INCLUDE|RPMFC_TEXT)) {
1517  char * fn;
1518 
1519  if ((fn = strrchr(s, '.')) && !strcmp(fn, ".so")) {
1520  FILE * fp = fopen(s, "r");
1521  char buf[BUFSIZ];
1522  char * in;
1523  if (fp == NULL || ferror(fp)) {
1524  if (fp) (void) fclose(fp);
1525  }
1526  while ((in = fgets(buf, sizeof(buf) - 1, fp))) {
1527  in[sizeof(buf)-1] = '\0';
1528  if (ferror(fp) || feof(fp))
1529  break;
1530  if ((fn = strstr(in, "GROUP")) &&
1531  (fn = strchr(fn, '(')) && (fn = strchr(in, '/'))) {
1532  fcolor |= RPMFC_SYMLINK;
1533  break;
1534  }
1535  }
1536  if (fp)
1537  fclose(fp);
1538  }
1539  }
1540 #endif
1541  xx = argiAdd(&fc->fcolor, (int)fc->ix, fcolor);
1542 
1543  if (fcolor != RPMFC_WHITE && (fcolor & RPMFC_INCLUDE))
1544  xx = rpmfcSaveArg(&fc->cdict, se);
1545 
1546 /*@-modobserver -observertrans @*/ /* XXX mixed types in variable */
1547  if (freeftype)
1548  ftype = _free(ftype);
1549 /*@=modobserver =observertrans @*/
1550  }
1551 
1552  /* Build per-file class index array. */
1553  fc->fknown = 0;
1554  for (fc->ix = 0; fc->ix < fc->nfiles; fc->ix++) {
1555  se = fcav[fc->ix];
1556 assert(se != NULL);
1557 
1558  dav = argvSearch(fc->cdict, se, NULL);
1559  if (dav) {
1560  xx = argiAdd(&fc->fcdictx, (int)fc->ix, (dav - fc->cdict));
1561  fc->fknown++;
1562  } else {
1563  xx = argiAdd(&fc->fcdictx, (int)fc->ix, 0);
1564  fc->fwhite++;
1565  }
1566  }
1567 
1568  fcav = argvFree(fcav);
1569 
1570  mg = rpmmgFree(mg);
1572  D_("categorized %d files into %u classes (using %s).\n"),
1573  (unsigned)fc->nfiles, argvCount(fc->cdict), magicfile);
1574  magicfile = _free(magicfile);
1575 
1576  return RPMRC_OK;
1577 }
1578 
1581 typedef struct DepMsg_s * DepMsg_t;
1582 
1585 struct DepMsg_s {
1586 /*@observer@*/ /*@null@*/
1587  const char * msg;
1588 /*@observer@*/
1589  const char * argv[4];
1593  int mask;
1594  int toggle;
1595 };
1596 
1599 /*@-nullassign@*/
1600 /*@unchecked@*/
1601 static struct DepMsg_s depMsgs[] = {
1602  { "Provides", { "%{?__find_provides}", NULL, NULL, NULL },
1604  0, -1 },
1605  { "Requires(interp)", { NULL, "interp", NULL, NULL },
1607  _notpre(RPMSENSE_INTERP), 0 },
1608  { "Requires(rpmlib)", { NULL, "rpmlib", NULL, NULL },
1609  (rpmTag)-1, (rpmTag)-1, RPMTAG_REQUIREFLAGS,
1610  _notpre(RPMSENSE_RPMLIB), 0 },
1611  { "Requires(verify)", { NULL, "verify", NULL, NULL },
1612  (rpmTag)-1, (rpmTag)-1, RPMTAG_REQUIREFLAGS,
1613  RPMSENSE_SCRIPT_VERIFY, 0 },
1614  { "Requires(pre)", { NULL, "pre", NULL, NULL },
1615  (rpmTag)-1, (rpmTag)-1, RPMTAG_REQUIREFLAGS,
1616  _notpre(RPMSENSE_SCRIPT_PRE), 0 },
1617  { "Requires(post)", { NULL, "post", NULL, NULL },
1618  (rpmTag)-1, (rpmTag)-1, RPMTAG_REQUIREFLAGS,
1619  _notpre(RPMSENSE_SCRIPT_POST), 0 },
1620  { "Requires(preun)", { NULL, "preun", NULL, NULL },
1621  (rpmTag)-1, (rpmTag)-1, RPMTAG_REQUIREFLAGS,
1622  _notpre(RPMSENSE_SCRIPT_PREUN), 0 },
1623  { "Requires(postun)", { NULL, "postun", NULL, NULL },
1624  (rpmTag)-1, (rpmTag)-1, RPMTAG_REQUIREFLAGS,
1625  _notpre(RPMSENSE_SCRIPT_POSTUN), 0 },
1626  { "Requires", { "%{?__find_requires}", NULL, NULL, NULL },
1627  (rpmTag)-1, (rpmTag)-1, RPMTAG_REQUIREFLAGS, /* XXX inherit name/version arrays */
1628  RPMSENSE_FIND_REQUIRES|RPMSENSE_TRIGGERIN|RPMSENSE_TRIGGERUN|RPMSENSE_TRIGGERPOSTUN|RPMSENSE_TRIGGERPREIN, 0 },
1629  { "Conflicts", { "%{?__find_conflicts}", NULL, NULL, NULL },
1631  0, -1 },
1632  { "Obsoletes", { "%{?__find_obsoletes}", NULL, NULL, NULL },
1634  0, -1 },
1635  { NULL, { NULL, NULL, NULL, NULL }, (rpmTag)0, (rpmTag)0, (rpmTag)0, 0, 0 }
1636 };
1637 /*@=nullassign@*/
1638 
1639 /*@unchecked@*/
1640 static DepMsg_t DepMsgs = depMsgs;
1641 
1646 static void printDeps(Header h)
1647  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1648  /*@modifies h, rpmGlobalMacroContext, fileSystem, internalState @*/
1649 {
1650  DepMsg_t dm;
1651  rpmds ds = NULL;
1652  int flags = 0x2; /* XXX no filtering, !scareMem */
1653  const char * DNEVR;
1654  evrFlags Flags;
1655  int bingo = 0;
1656 
1657  for (dm = DepMsgs; dm->msg != NULL; dm++) {
1658  if ((int)dm->ntag != -1) {
1659  (void)rpmdsFree(ds);
1660  ds = NULL;
1661  ds = rpmdsNew(h, dm->ntag, flags);
1662  }
1663  if (dm->ftag == 0)
1664  continue;
1665 
1666  ds = rpmdsInit(ds);
1667  if (ds == NULL)
1668  continue; /* XXX can't happen */
1669 
1670  bingo = 0;
1671  while (rpmdsNext(ds) >= 0) {
1672 
1673  Flags = rpmdsFlags(ds);
1674 
1675  if (!((Flags & dm->mask) ^ (dm->toggle)))
1676  /*@innercontinue@*/ continue;
1677  if (bingo == 0) {
1678  rpmlog(RPMLOG_NOTICE, "%s:", (dm->msg ? dm->msg : ""));
1679  bingo = 1;
1680  }
1681  if ((DNEVR = rpmdsDNEVR(ds)) == NULL)
1682  /*@innercontinue@*/ continue; /* XXX can't happen */
1683  rpmlog(RPMLOG_NOTICE, " %s", DNEVR+2);
1684  }
1685  if (bingo)
1686  rpmlog(RPMLOG_NOTICE, "\n");
1687  }
1688  (void)rpmdsFree(ds);
1689  ds = NULL;
1690 }
1691 
1695  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1696  /*@modifies fi, rpmGlobalMacroContext, fileSystem, internalState @*/
1697 {
1698  rpmiob iob_stdin;
1699  rpmiob iob_stdout;
1700  DepMsg_t dm;
1701  int failnonzero = 0;
1702  rpmRC rc = RPMRC_OK;
1703 
1704  /*
1705  * Create file manifest buffer to deliver to dependency finder.
1706  */
1707  iob_stdin = rpmiobNew(0);
1708  fi = rpmfiInit(fi, 0);
1709  if (fi != NULL)
1710  while (rpmfiNext(fi) >= 0)
1711  iob_stdin = rpmiobAppend(iob_stdin, rpmfiFN(fi), 1);
1712 
1713  for (dm = DepMsgs; dm->msg != NULL; dm++) {
1714  rpmTag tag;
1715  rpmsenseFlags tagflags;
1716  char * s;
1717  int xx;
1718 
1719  tag = (dm->ftag > 0) ? dm->ftag : dm->ntag;
1720  tagflags = (rpmsenseFlags) 0;
1721  s = NULL;
1722 
1723  switch(tag) {
1724  case RPMTAG_PROVIDEFLAGS:
1725  if (!pkg->autoProv)
1726  continue;
1727  failnonzero = 1;
1728  tagflags = RPMSENSE_FIND_PROVIDES;
1729  /*@switchbreak@*/ break;
1730  case RPMTAG_REQUIREFLAGS:
1731  if (!pkg->autoReq)
1732  continue;
1733  failnonzero = 0;
1734  tagflags = RPMSENSE_FIND_REQUIRES;
1735  /*@switchbreak@*/ break;
1736  default:
1737  continue;
1738  /*@notreached@*/ /*@switchbreak@*/ break;
1739  }
1740 
1741  xx = rpmfcExec(dm->argv, iob_stdin, &iob_stdout, failnonzero);
1742  if (xx == -1)
1743  continue;
1744 
1745  s = rpmExpand(dm->argv[0], NULL);
1746  rpmlog(RPMLOG_NOTICE, _("Finding %s: %s\n"), dm->msg,
1747  (s ? s : ""));
1748  s = _free(s);
1749 
1750  if (iob_stdout == NULL) {
1751  rpmlog(RPMLOG_ERR, _("Failed to find %s:\n"), dm->msg);
1752  rc = RPMRC_FAIL;
1753  break;
1754  }
1755 
1756  /* Parse dependencies into header */
1757  if (spec->_parseRCPOT)
1758  rc = spec->_parseRCPOT(spec, pkg, rpmiobStr(iob_stdout), tag,
1759  0, tagflags);
1760  iob_stdout = rpmiobFree(iob_stdout);
1761 
1762  if (rc) {
1763  rpmlog(RPMLOG_ERR, _("Failed to find %s:\n"), dm->msg);
1764  break;
1765  }
1766  }
1767 
1768  iob_stdin = rpmiobFree(iob_stdin);
1769 
1770  return rc;
1771 }
1772 
1775 /*@-nullassign@*/
1776 /*@unchecked@*/
1777 static struct DepMsg_s scriptMsgs[] = {
1778  { "Requires(pre)", { "%{?__scriptlet_requires}", NULL, NULL, NULL },
1780  RPMSENSE_SCRIPT_PRE, 0 },
1781  { "Requires(post)", { "%{?__scriptlet_requires}", NULL, NULL, NULL },
1783  RPMSENSE_SCRIPT_POST, 0 },
1784  { "Requires(preun)", { "%{?__scriptlet_requires}", NULL, NULL, NULL },
1786  RPMSENSE_SCRIPT_PREUN, 0 },
1787  { "Requires(postun)", { "%{?__scriptlet_requires}", NULL, NULL, NULL },
1789  RPMSENSE_SCRIPT_POSTUN, 0 },
1790  { NULL, { NULL, NULL, NULL, NULL }, (rpmTag)0, (rpmTag)0, (rpmTag)0, 0, 0 }
1791 };
1792 /*@=nullassign@*/
1793 
1794 /*@unchecked@*/
1795 static DepMsg_t ScriptMsgs = scriptMsgs;
1796 
1799 static int rpmfcGenerateScriptletDeps(const Spec spec, Package pkg)
1800  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1801  /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
1802 {
1803  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
1804  rpmiob iob_stdin = rpmiobNew(0);
1805  rpmiob iob_stdout = NULL;
1806  DepMsg_t dm;
1807  int failnonzero = 0;
1808  int rc = 0;
1809  int xx;
1810 
1811  for (dm = ScriptMsgs; dm->msg != NULL; dm++) {
1812  rpmTag tag;
1813  rpmsenseFlags tagflags;
1814  char * s;
1815 
1816  tag = dm->ftag;
1817  tagflags = (rpmsenseFlags) (RPMSENSE_FIND_REQUIRES | dm->mask);
1818 
1819  /* Retrieve scriptlet interpreter. */
1820  he->tag = dm->ntag;
1821  xx = headerGet(pkg->header, he, 0);
1822  if (!xx || he->p.str == NULL)
1823  continue;
1824  xx = strcmp(he->p.str, "/bin/sh") && strcmp(he->p.str, "/bin/bash");
1825  he->p.ptr = _free(he->p.ptr);
1826  if (xx)
1827  continue;
1828 
1829  /* Retrieve scriptlet body. */
1830  he->tag = dm->vtag;
1831  xx = headerGet(pkg->header, he, 0);
1832  if (!xx || he->p.str == NULL)
1833  continue;
1834  iob_stdin = rpmiobEmpty(iob_stdin);
1835  iob_stdin = rpmiobAppend(iob_stdin, he->p.str, 1);
1836  iob_stdin = rpmiobRTrim(iob_stdin);
1837  he->p.ptr = _free(he->p.ptr);
1838 
1839  xx = rpmfcExec(dm->argv, iob_stdin, &iob_stdout, failnonzero);
1840  if (xx == -1)
1841  continue;
1842 
1843  /* Parse dependencies into header */
1844  s = rpmiobStr(iob_stdout);
1845  if (s != NULL && *s != '\0') {
1846  char * se = s;
1847  /* XXX Convert "executable(/path/to/file)" to "/path/to/file". */
1848  while ((se = strstr(se, "executable(/")) != NULL) {
1849 /*@-modobserver@*/ /* FIX: rpmiobStr should not be observer */
1850  se = stpcpy(se, " ");
1851  *se = '/'; /* XXX stpcpy truncates the '/' */
1852 /*@=modobserver@*/
1853  se = strchr(se, ')');
1854  if (se == NULL)
1855  /*@innerbreak@*/ break;
1856  *se++ = ' ';
1857  }
1858  if (spec->_parseRCPOT)
1859  rc = spec->_parseRCPOT(spec, pkg, s, tag, 0, tagflags);
1860  }
1861  iob_stdout = rpmiobFree(iob_stdout);
1862 
1863  }
1864 
1865  iob_stdin = rpmiobFree(iob_stdin);
1866 
1867  return rc;
1868 }
1869 
1870 static unsigned removeSillyDeps(Header h, rpmfc fc) {
1871  HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
1872  int xx;
1873  unsigned i, rnum, removed = 0;
1874  const char **deps = NULL;
1875  const char **versions = NULL;
1876  evrFlags *flags = NULL;
1877  int *newpos = NULL, *ddictxPos = NULL;
1878 
1879  he->tag = RPMTAG_REQUIRENAME;
1880  xx = headerGet(h, he, 0);
1881  deps = he->p.argv;
1882  rnum = he->c;
1883 
1884  he->tag = RPMTAG_REQUIREVERSION;
1885  xx = headerGet(h, he, 0);
1886  versions = he->p.argv;
1887 
1888  he->tag = RPMTAG_REQUIREFLAGS;
1889  xx = headerGet(h, he, 0);
1890  flags = (evrFlags*)he->p.ui32p;
1891 
1892  if (fc && fc->requires != NULL && fc->ddictx != NULL) {
1893  newpos = alloca(he->c*sizeof(newpos[0]));
1894  if (fc->ddictx)
1895  ddictxPos = alloca(fc->ddictx->nvals*sizeof(ddictxPos[0]));
1896  }
1897  for (i = 0; i < rnum-removed; i++) {
1898  if (removed) {
1899  deps[i] = deps[i+removed];
1900  versions[i] = versions[i+removed];
1901  flags[i] = flags[i+removed];
1902  if (fc) {
1903  fc->requires->N[i] = fc->requires->N[i+removed];
1904  fc->requires->EVR[i] = fc->requires->EVR[i+removed];
1905  fc->requires->Flags[i] = fc->requires->Flags[i+removed];
1906  }
1907  }
1908  if (fc && fc->requires != NULL && fc->ddictx != NULL)
1909  newpos[i+removed] = i;
1910  rpmds req = rpmdsSingle(RPMTAG_REQUIRENAME, deps[i], versions[i], flags[i]);
1911  rpmds prov = rpmdsNew(h, (*deps[i] == '/' && !*versions[i]) ? RPMTAG_BASENAMES : RPMTAG_PROVIDENAME, 0);
1912  if (rpmdsMatch(req, prov)) {
1913  if (flags[i] & RPMSENSE_SCRIPT_PRE)
1914  rpmlog(RPMLOG_ERR, "Requires(pre): on dependency provided by self: %s\n", rpmdsDNEVR(req));
1915  else {
1916  if (fc && fc->requires != NULL && fc->ddictx != NULL)
1917  newpos[i+removed] = -1;
1918  rpmlog(RPMLOG_NOTICE, "Removing dependency on self: %s\n", rpmdsDNEVR(req));
1919  removed++;
1920  i--;
1921  }
1922  }
1923  req = rpmdsFree(req);
1924  prov = rpmdsFree(prov);
1925  }
1926  if (fc && fc->requires != NULL && fc->ddictx != NULL && removed) {
1927  fc->requires->Count -= removed;
1928  unsigned rx = 0;
1929  for (i = 0; i < fc->ddictx->nvals-rx; i++) {
1930  unsigned ix;
1931  unsigned char deptype;
1932 
1933  ix = fc->ddictx->vals[i+rx];
1934  deptype = ((ix >> 24) & 0xff);
1935  ix &= 0x00ffffff;
1936 
1937  if (deptype == 'P') {
1938  ddictxPos[i+rx] = i;
1939  fc->ddictx->vals[i] = fc->ddictx->vals[i+rx];
1940  continue;
1941  }
1942  if (newpos[ix] == -1) {
1943  ddictxPos[i+rx] = -1;
1944  i--, rx++;
1945  }
1946  else
1947  {
1948  ddictxPos[i+rx] = i;
1949  fc->ddictx->vals[i] = (deptype << 24) | (newpos[ix] & 0x00ffffff);
1950  }
1951  }
1952  fc->ddictx->nvals -= rx;
1953 
1954  for (i = 0; i < fc->fddictn->nvals; i++) {
1955  rx = 0;
1956  if (fc->fddictn->vals[i]) {
1957  unsigned j, ix = fc->fddictx->vals[i];
1958  for (j = 0, rx = 0; j < fc->fddictn->vals[i]; j++, ix++) {
1959  if (ddictxPos[ix] == -1)
1960  rx++;
1961  if (j == 0 || fc->fddictx->vals[i] == -1)
1962  fc->fddictx->vals[i] = ddictxPos[ix];
1963  }
1964  }
1965  if (rx)
1966  fc->fddictn->vals[i] -= rx;
1967  if (fc->fddictn->vals[i] == 0)
1968  fc->fddictx->vals[i] = 0;
1969  }
1970  }
1971 
1972  if (removed) {
1973  he->tag = RPMTAG_REQUIRENAME;
1974  he->t = RPM_STRING_ARRAY_TYPE;
1975  he->p.argv = deps;
1976  he->c -= removed;
1977  headerMod(h, he, 0);
1978 
1979  he->tag = RPMTAG_REQUIREVERSION;
1980  he->p.argv = versions;
1981  headerMod(h, he, 0);
1982 
1983  he->tag = RPMTAG_REQUIREFLAGS;
1984  he->t = RPM_UINT32_TYPE;
1985  he->p.ui32p = (uint32_t*)flags;
1986  headerMod(h, he, 0);
1987  }
1988 
1989  return removed;
1990 }
1991 
1992 rpmRC rpmfcGenerateDepends(void * _spec, void * _pkg)
1993 {
1994  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
1995  const Spec spec = (Spec) _spec;
1996  Package pkg = (Package) _pkg;
1997  rpmfi fi = pkg->fi;
1998  rpmfc fc = NULL;
1999  rpmds ds;
2000  int flags = 0x2; /* XXX no filtering, !scareMem */
2001  ARGV_t av;
2002  rpmuint16_t * fmode;
2003  int ac = rpmfiFC(fi);
2004  char buf[BUFSIZ];
2005  const char * N;
2006  const char * EVR;
2007  int genConfigDeps, internaldeps;
2008  rpmRC rc = RPMRC_OK;
2009  int i;
2010  int xx;
2011 
2012  /* Skip packages with no files. */
2013  if (ac <= 0)
2014  return RPMRC_OK;
2015 
2016  /* Skip packages that have dependency generation disabled. */
2017  if (! (pkg->autoReq || pkg->autoProv))
2018  return RPMRC_OK;
2019 
2020  /* If new-fangled dependency generation is disabled ... */
2021  internaldeps = rpmExpandNumeric("%{?_use_internal_dependency_generator}");
2022  if (internaldeps == 0) {
2023  /* ... then generate dependencies using %{__find_requires} et al. */
2024  rc = rpmfcGenerateDependsHelper(spec, pkg, fi);
2025  removeSillyDeps(pkg->header, NULL);
2026  printDeps(pkg->header);
2027  return rc;
2028  }
2029 
2030  /* Generate scriptlet Dependencies. */
2031  if (internaldeps > 1)
2032  xx = rpmfcGenerateScriptletDeps(spec, pkg);
2033 
2034  /* Extract absolute file paths in argv format. */
2035  /* XXX TODO: should use argvFoo ... */
2036  av = (ARGV_t) xcalloc(ac+1, sizeof(*av));
2037  fmode = (rpmuint16_t *) xcalloc(ac+1, sizeof(*fmode));
2038 
2039  genConfigDeps = 0;
2040  fi = rpmfiInit(fi, 0);
2041  if (fi != NULL)
2042  while ((i = rpmfiNext(fi)) >= 0) {
2043  rpmfileAttrs fileAttrs;
2044 
2045  /* Does package have any %config files? */
2046  fileAttrs = (rpmfileAttrs) rpmfiFFlags(fi);
2047  genConfigDeps |= (fileAttrs & RPMFILE_CONFIG);
2048 
2049  av[i] = xstrdup(rpmfiFN(fi));
2050  fmode[i] = rpmfiFMode(fi);
2051  }
2052  av[ac] = NULL;
2053 
2054  fc = rpmfcNew();
2055  fc->skipProv = !pkg->autoProv;
2056  fc->skipReq = !pkg->autoReq;
2057 
2058  { const char * buildRootURL;
2059  const char * buildRoot;
2060  buildRootURL = rpmGenPath(spec->rootURL, "%{?buildroot}", NULL);
2061  (void) urlPath(buildRootURL, &buildRoot);
2062  if (buildRoot && !strcmp(buildRoot, "/")) buildRoot = NULL;
2063  fc->brlen = (buildRoot ? strlen(buildRoot) : 0);
2064  buildRootURL = _free(buildRootURL);
2065  }
2066 
2067  /* Copy (and delete) manually generated dependencies to dictionary. */
2068  if (!fc->skipProv) {
2069  ds = rpmdsNew(pkg->header, RPMTAG_PROVIDENAME, flags);
2070  xx = rpmdsMerge(&fc->provides, ds);
2071  (void)rpmdsFree(ds);
2072  ds = NULL;
2073  he->tag = RPMTAG_PROVIDENAME;
2074  xx = headerDel(pkg->header, he, 0);
2075  he->tag = RPMTAG_PROVIDEVERSION;
2076  xx = headerDel(pkg->header, he, 0);
2077  he->tag = RPMTAG_PROVIDEFLAGS;
2078  xx = headerDel(pkg->header, he, 0);
2079 
2080  /* Add config dependency, Provides: config(N) = EVR */
2081  if (genConfigDeps) {
2082  static evrFlags _Flags = (evrFlags)(RPMSENSE_EQUAL|RPMSENSE_CONFIG);
2083  N = rpmdsN(pkg->ds);
2084 assert(N != NULL);
2085  EVR = rpmdsEVR(pkg->ds);
2086 assert(EVR != NULL);
2087  sprintf(buf, "config(%s)", N);
2088  ds = rpmdsSingle(RPMTAG_PROVIDENAME, buf, EVR, _Flags);
2089  xx = rpmdsMerge(&fc->provides, ds);
2090  (void)rpmdsFree(ds);
2091  ds = NULL;
2092  }
2093  }
2094 
2095  if (!fc->skipReq) {
2096  ds = rpmdsNew(pkg->header, RPMTAG_REQUIRENAME, flags);
2097  xx = rpmdsMerge(&fc->requires, ds);
2098  (void)rpmdsFree(ds);
2099  ds = NULL;
2100  he->tag = RPMTAG_REQUIRENAME;
2101  xx = headerDel(pkg->header, he, 0);
2102  he->tag = RPMTAG_REQUIREVERSION;
2103  xx = headerDel(pkg->header, he, 0);
2104  he->tag = RPMTAG_REQUIREFLAGS;
2105  xx = headerDel(pkg->header, he, 0);
2106 
2107  /* Add config dependency, Requires: config(N) = EVR */
2108  if (genConfigDeps) {
2109  static evrFlags _Flags = (evrFlags)(RPMSENSE_EQUAL|RPMSENSE_CONFIG);
2110  N = rpmdsN(pkg->ds);
2111 assert(N != NULL);
2112  EVR = rpmdsEVR(pkg->ds);
2113 assert(EVR != NULL);
2114  sprintf(buf, "config(%s)", N);
2115  ds = rpmdsSingle(RPMTAG_REQUIRENAME, buf, EVR, _Flags);
2116  xx = rpmdsMerge(&fc->requires, ds);
2117  (void)rpmdsFree(ds);
2118  ds = NULL;
2119  }
2120  }
2121 
2122  /* Build file class dictionary. */
2123  xx = rpmfcClassify(fc, av, fmode);
2124 
2125  /* Build file/package dependency dictionary. */
2126  xx = rpmfcApply(fc);
2127 
2128  /* Add per-file colors(#files) */
2129  he->tag = RPMTAG_FILECOLORS;
2130  he->t = RPM_UINT32_TYPE;
2131  he->p.ui32p = argiData(fc->fcolor);
2132  he->c = argiCount(fc->fcolor);
2133 assert(ac == (int)he->c);
2134  if (he->p.ptr != NULL && he->c > 0) {
2135  rpmuint32_t * fcolors = he->p.ui32p;
2136 
2137  /* XXX Make sure only primary (i.e. Elf32/Elf64) colors are added. */
2138  for (i = 0; i < (int)he->c; i++)
2139  fcolors[i] &= 0x0f;
2140 
2141  xx = headerPut(pkg->header, he, 0);
2142  }
2143 
2144  /* Add classes(#classes) */
2145  he->tag = RPMTAG_CLASSDICT;
2146  he->t = RPM_STRING_ARRAY_TYPE;
2147  he->p.argv = argvData(fc->cdict);
2148  he->c = argvCount(fc->cdict);
2149  if (he->p.ptr != NULL && he->c > 0) {
2150  xx = headerPut(pkg->header, he, 0);
2151  }
2152 
2153  /* Add per-file classes(#files) */
2154  he->tag = RPMTAG_FILECLASS;
2155  he->t = RPM_UINT32_TYPE;
2156  he->p.ui32p = argiData(fc->fcdictx);
2157  he->c = argiCount(fc->fcdictx);
2158 assert(ac == (int)he->c);
2159  if (he->p.ptr != NULL && he->c > 0) {
2160  xx = headerPut(pkg->header, he, 0);
2161  }
2162 
2163  /* Add Provides: */
2164  if (fc->provides != NULL && (he->c = rpmdsCount(fc->provides)) > 0
2165  && !fc->skipProv)
2166  {
2167  he->tag = RPMTAG_PROVIDENAME;
2168  he->t = RPM_STRING_ARRAY_TYPE;
2169  he->p.argv = fc->provides->N;
2170  xx = headerPut(pkg->header, he, 0);
2171 
2172  /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
2173 /*@-nullpass@*/
2174  he->tag = RPMTAG_PROVIDEVERSION;
2175  he->t = RPM_STRING_ARRAY_TYPE;
2176  he->p.argv = fc->provides->EVR;
2177 assert(he->p.ptr != NULL);
2178  xx = headerPut(pkg->header, he, 0);
2179 
2180  he->tag = RPMTAG_PROVIDEFLAGS;
2181  he->t = RPM_UINT32_TYPE;
2182  he->p.ui32p = (rpmuint32_t *) fc->provides->Flags;
2183 assert(he->p.ptr != NULL);
2184  xx = headerPut(pkg->header, he, 0);
2185 /*@=nullpass@*/
2186  }
2187 
2188  /* Add Requires: */
2189  if (fc->requires != NULL && (he->c = rpmdsCount(fc->requires)) > 0
2190  && !fc->skipReq)
2191  {
2192  he->tag = RPMTAG_REQUIRENAME;
2193  he->t = RPM_STRING_ARRAY_TYPE;
2194  he->p.argv = fc->requires->N;
2195 assert(he->p.ptr != NULL);
2196  xx = headerPut(pkg->header, he, 0);
2197 
2198  /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
2199 /*@-nullpass@*/
2200  he->tag = RPMTAG_REQUIREVERSION;
2201  he->t = RPM_STRING_ARRAY_TYPE;
2202  he->p.argv = fc->requires->EVR;
2203 assert(he->p.ptr != NULL);
2204  xx = headerPut(pkg->header, he, 0);
2205 
2206  he->tag = RPMTAG_REQUIREFLAGS;
2207  he->t = RPM_UINT32_TYPE;
2208  he->p.ui32p = (rpmuint32_t *) fc->requires->Flags;
2209 assert(he->p.ptr != NULL);
2210  xx = headerPut(pkg->header, he, 0);
2211 /*@=nullpass@*/
2212  }
2213 
2214  removeSillyDeps(pkg->header, fc);
2215 
2216  /* Add dependency dictionary(#dependencies) */
2217  he->tag = RPMTAG_DEPENDSDICT;
2218  he->t = RPM_UINT32_TYPE;
2219  he->p.ui32p = argiData(fc->ddictx);
2220  he->c = argiCount(fc->ddictx);
2221  if (he->p.ptr != NULL) {
2222  xx = headerPut(pkg->header, he, 0);
2223  }
2224 
2225  /* Add per-file dependency (start,number) pairs (#files) */
2226  he->tag = RPMTAG_FILEDEPENDSX;
2227  he->t = RPM_UINT32_TYPE;
2228  he->p.ui32p = argiData(fc->fddictx);
2229  he->c = argiCount(fc->fddictx);
2230 assert(ac == (int)he->c);
2231  if (he->p.ptr != NULL) {
2232  xx = headerPut(pkg->header, he, 0);
2233  }
2234 
2235  he->tag = RPMTAG_FILEDEPENDSN;
2236  he->t = RPM_UINT32_TYPE;
2237  he->p.ui32p = argiData(fc->fddictn);
2238  he->c = argiCount(fc->fddictn);
2239 assert(ac == (int)he->c);
2240  if (he->p.ptr != NULL) {
2241  xx = headerPut(pkg->header, he, 0);
2242  }
2243 
2244  printDeps(pkg->header);
2245 
2246 if (fc != NULL && _rpmfc_debug) {
2247 char msg[BUFSIZ];
2248 sprintf(msg, "final: files %u cdict[%d] %u%% ddictx[%d]", (unsigned int)fc->nfiles, argvCount(fc->cdict), (unsigned int)((100 * fc->fknown)/fc->nfiles), argiCount(fc->ddictx));
2249 rpmfcPrint(msg, fc, NULL);
2250 }
2251 
2252  /* Clean up. */
2253  fmode = _free(fmode);
2254  fc = rpmfcFree(fc);
2255  av = argvFree(av);
2256 
2257  return rc;
2258 }
2259 
2260 /*@-mustmod@*/
2261 static void rpmfcFini(void * _fc)
2262  /*@modifies _fc @*/
2263 {
2264  rpmfc fc = (rpmfc) _fc;
2265 
2266  fc->fn = argvFree(fc->fn);
2267  fc->fcolor = argiFree(fc->fcolor);
2268  fc->fcdictx = argiFree(fc->fcdictx);
2269  fc->fddictx = argiFree(fc->fddictx);
2270  fc->fddictn = argiFree(fc->fddictn);
2271  fc->cdict = argvFree(fc->cdict);
2272  fc->ddict = argvFree(fc->ddict);
2273  fc->ddictx = argiFree(fc->ddictx);
2274 
2275  (void)rpmdsFree(fc->provides);
2276  fc->provides = NULL;
2277  (void)rpmdsFree(fc->requires);
2278  fc->requires = NULL;
2279 
2280  fc->iob_java = rpmiobFree(fc->iob_java);
2281  fc->iob_perl = rpmiobFree(fc->iob_perl);
2282  fc->iob_python = rpmiobFree(fc->iob_python);
2283  fc->iob_php = rpmiobFree(fc->iob_php);
2284 }
2285 /*@=mustmod@*/
2286 
2287 /*@unchecked@*/ /*@only@*/ /*@null@*/
2289 
2290 static rpmfc rpmfcGetPool(/*@null@*/ rpmioPool pool)
2291  /*@globals _rpmfcPool, fileSystem, internalState @*/
2292  /*@modifies pool, _rpmfcPool, fileSystem, internalState @*/
2293 {
2294  rpmfc fc;
2295 
2296  if (_rpmfcPool == NULL) {
2297  _rpmfcPool = rpmioNewPool("fc", sizeof(*fc), -1, _rpmfc_debug,
2298  NULL, NULL, rpmfcFini);
2299  pool = _rpmfcPool;
2300  }
2301  fc = (rpmfc) rpmioGetPool(pool, sizeof(*fc));
2302  memset(((char *)fc)+sizeof(fc->_item), 0, sizeof(*fc)-sizeof(fc->_item));
2303  return fc;
2304 }
2305 
2307 {
2308  rpmfc fc = rpmfcGetPool(_rpmfcPool);
2309  fc->fn = (ARGV_t) xcalloc(1, sizeof(*fc->fn));
2310  return rpmfcLink(fc);
2311 }
2312 
rpmuint32_t rpmfiFFlags(rpmfi fi)
Return current file flags from file info set.
Definition: rpmfi.c:217
#define RPM_VENDOR_MANDRIVA
Definition: config.h:1144
rpmds rpmdsSingle(rpmTag tagN, const char *N, const char *EVR, evrFlags Flags)
Create, load and initialize a dependency set of size 1.
Definition: rpmds.c:609
rpmTagType t
Definition: rpmtag.h:505
evrFlags rpmdsFlags(const rpmds ds)
Return current dependency flags.
Definition: rpmds.c:691
rpmiob rpmiobRTrim(rpmiob iob)
Trim trailing white space.
Definition: rpmiob.c:67
const char * str
Definition: rpmtag.h:72
rpmTag tag
Definition: rpmtag.h:504
const char ** argv
Definition: rpmtag.h:74
rpmds rpmdsInit(rpmds ds)
Initialize dependency set iterator.
Definition: rpmds.c:943
miRE mireNew(rpmMireMode mode, int tag)
Create pattern container.
Definition: mire.c:113
const char * rpmmgFile(rpmmg mg, const char *fn)
Return magic string for a file.
Definition: rpmmg.c:84
static struct rpmfcApplyTbl_s rpmfcApplyTable[]
XXX Having two entries for rpmfcSCRIPT may be unnecessary duplication.
Definition: rpmfc.c:1153
#define RPMELF_FLAG_SKIPREQUIRES
Definition: rpmds.h:616
static DepMsg_t ScriptMsgs
Definition: rpmfc.c:1795
#define RPMSENSE_SENSEMASK
Definition: rpmevr.h:74
ARGI_t argiFree(ARGI_t argi)
Destroy an argi array.
Definition: argv.c:34
void * mireFreeAll(miRE mire, int nmire)
Destroy compiled patterns.
Definition: mire.c:96
enum urltype_e urltype
Supported URL types.
static void rpmfcFini(void *_fc)
Definition: rpmfc.c:2261
static int rpmfcMatchRegexps(void *_mire, int nmire, const char *str, char deptype)
Definition: rpmfc.c:377
struct DepMsg_s * DepMsg_t
Definition: rpmfc.c:1581
#define EXIT_FAILURE
static void printDeps(Header h)
Print dependencies in a header.
Definition: rpmfc.c:1646
char * xstrdup(const char *str)
Definition: rpmmalloc.c:322
size_t rpmiobLen(rpmiob iob)
Return I/O buffer len.
Definition: rpmiob.c:123
rpmuint32_t * ui32p
Definition: rpmtag.h:69
static int rpmfcExpandAppend(ARGV_t *argvp, const ARGV_t av)
Definition: rpmfc.c:45
const char * rootURL
Definition: rpmspec.h:115
Structure(s) used for file info tag sets.
int headerGet(Header h, HE_t he, unsigned int flags)
Retrieve extension or tag value from a header.
Definition: header.c:2222
int headerPut(Header h, HE_t he, unsigned int flags)
Add or append tag container to header.
Definition: header.c:2285
The Header data structure.
int mireRegcomp(miRE mire, const char *pattern)
Compile pattern match.
Definition: mire.c:334
int argvAppend(ARGV_t *argvp, ARGV_t av)
Append one argv array to another.
Definition: argv.c:216
static int rpmfcELF(rpmfc fc)
Extract Elf dependencies.
Definition: rpmfc.c:1092
int errno
rpmTag rpmdsTagN(const rpmds ds)
Return current dependency type.
Definition: rpmds.c:702
int headerDel(Header h, HE_t he, unsigned int flags)
Remove tag container from header.
Definition: header.c:2304
const char * rpmfiFN(rpmfi fi)
Return current file name from file info set.
Definition: rpmfi.c:163
unsigned short rpmuint16_t
Definition: rpmiotypes.h:24
rpmiob rpmiobFree(rpmiob iob)
Destroy a I/O buffer instance.
int rpmEVRparse(const char *evrstr, EVR_t evr)
Split EVR string into epoch, version, and release components.
Definition: rpmevr.c:179
struct EVR_s * EVR_t
Definition: rpmevr.h:20
static void rpmlog(int code, const char *fmt,...)
Definition: rpmlog.h:299
rpmRC rpmfcApply(rpmfc fc)
Build file/package dependency dictionary and mappings.
Definition: rpmfc.c:1163
const char * rpmdsDNEVR(const rpmds ds)
Return current formatted dependency string.
Definition: rpmds.c:657
rpmiob rpmiobAppend(rpmiob iob, const char *s, size_t nl)
Append string to I/O buffer.
Definition: rpmiob.c:78
static int rpmfcSaveArg(ARGV_t *argvp, const char *key)
Definition: rpmfc.c:289
struct rpmds_s * rpmds
Dependency tag sets from a header, so that a header can be discarded early.
Definition: rpmtypes.h:28
static rpmiob getOutputFrom(const char *dir, ARGV_t argv, const char *writePtr, size_t writeBytesLeft, int failNonZero)
Return output from helper script.
Definition: rpmfc.c:79
int argiCount(ARGI_t argi)
Return no.
Definition: argv.c:55
rpmds rpmdsFree(rpmds ds)
Destroy a dependency set.
int rpmfiFC(rpmfi fi)
Return file count from file info set.
Definition: rpmfi.c:87
int rpmEVRcompare(const EVR_t a, const EVR_t b)
Compare EVR containers for equality.
Definition: rpmevr.c:274
char * argvJoin(ARGV_t argv, char sep)
Concatenate an argv array into a string.
Definition: argv.c:274
enum evrFlags_e evrFlags
Dependency Attributes.
int toggle
Definition: rpmfc.c:1594
char * alloca()
Yet Another syslog(3) API clone.
int headerMod(Header h, HE_t he, unsigned int flags)
Modify tag container in header.
Definition: header.c:2310
static struct rpmfcTokens_s rpmfcTokens[]
Definition: rpmfc.c:613
Header header
Definition: rpmspec.h:210
static rpmfc rpmfcGetPool(rpmioPool pool)
Definition: rpmfc.c:2290
unsigned int rpmuint32_t
Definition: rpmiotypes.h:25
struct _HE_s * HE_t
Definition: rpmtag.h:58
miRE mireFree(miRE mire)
Free pattern container.
const char * argv[4]
Definition: rpmfc.c:1589
void * xcalloc(size_t nmemb, size_t size)
Definition: rpmmalloc.c:301
void * ptr
Definition: rpmtag.h:66
rpmfc rpmfcLink(rpmfc fc)
Reference a file classifier instance.
rpmioItem rpmioGetPool(rpmioPool pool, size_t size)
Get unused item from pool, or alloc a new item.
Definition: rpmmalloc.c:221
rpmfc rpmfcFree(rpmfc fc)
Destroy a file classifier.
rpmTag vtag
Definition: rpmfc.c:1591
static DepMsg_t DepMsgs
Definition: rpmfc.c:1640
struct rpmfi_s * rpmfi
File info tag sets from a header, so that a header can be discarded early.
Definition: rpmfi.h:78
int rpmdsCompare(const rpmds A, const rpmds B)
Compare two versioned dependency ranges, looking for overlap.
Definition: rpmds.c:4347
RPM pattern matching.
int argvCount(const ARGV_t argv)
Return no.
Definition: argv.c:71
rpmuint16_t rpmfiFMode(rpmfi fi)
Return current file mode from file info set.
Definition: rpmfi.c:265
ARGV_t argvData(ARGV_t argv)
Return data from argv array.
Definition: argv.c:80
int rpmdsFind(rpmds ds, const rpmds ods)
Find a dependency set element using binary search.
Definition: rpmds.c:1001
enum evrFlags_e rpmsenseFlags
Definition: rpmevr.h:72
rpmTagData p
Definition: rpmtag.h:507
static int rpmfcMergePR(void *context, rpmds ds)
Merge provides/requires dependencies into a rpmfc container.
Definition: rpmfc.c:1043
static unsigned removeSillyDeps(Header h, rpmfc fc)
Definition: rpmfc.c:1870
ARGV_t argvFree(ARGV_t argv)
Destroy an argv array.
Definition: argv.c:44
struct miRE_s * miRE
Definition: mire.h:60
int _rpmfc_debug
Definition: poptALL.c:122
int rpmfcExec(ARGV_t av, rpmiob iob_stdin, rpmiob *iob_stdoutp, int failnonzero)
Definition: rpmfc.c:229
const char * rpmdsEVR(const rpmds ds)
Return current dependency epoch-version-release.
Definition: rpmds.c:680
const char * tagName(rpmTag tag)
Return tag name from value.
Definition: tagname.c:436
const char * msg
Definition: rpmfc.c:1587
static int _filter_values
Definition: rpmfc.c:39
int rpmdsNext(rpmds ds)
Return next dependency set iterator index.
Definition: rpmds.c:912
Structure(s) used for dependency tag sets.
static const char * ftype(unsigned type)
Definition: rpmmtree.c:1700
int autoProv
Definition: rpmspec.h:217
rpmTag ftag
Definition: rpmfc.c:1592
struct Spec_s * Spec
Definition: rpmtypes.h:23
const char * rpmGenPath(const char *urlroot, const char *urlmdir, const char *urlfile)
Merge 3 args into path, any or all of which may be a url.
Definition: macro.c:3356
int argvAdd(ARGV_t *argvp, ARGstr_t val)
Add a string to an argv array.
Definition: argv.c:199
rpmTagCount c
Definition: rpmtag.h:508
int mireRegexec(miRE mire, const char *val, size_t vallen)
Execute pattern match.
Definition: mire.c:398
rpmmg rpmmgNew(const char *fn, int flags)
Create and load a magic wrapper.
Definition: rpmmg.c:57
The structure used to store values parsed from a spec file.
Definition: rpmspec.h:108
static char * rpmfcFileDep(char *buf, size_t ix, rpmds ds)
Definition: rpmfc.c:304
struct rpmfcApplyTbl_s * rpmfcApplyTbl
char * rpmExpand(const char *arg,...)
Return (malloc&#39;ed) concatenated macro expansion(s).
Definition: macro.c:3117
static struct DepMsg_s scriptMsgs[]
Definition: rpmfc.c:1777
int Chdir(const char *path)
chdir(2) clone.
Definition: rpmrpc.c:105
int rpmdsCount(const rpmds ds)
Return dependency set count.
Definition: rpmds.c:636
void rpmfcPrint(const char *msg, rpmfc fc, FILE *fp)
Print results of file classification.
Definition: rpmfc.c:735
struct Package_s * Package
Definition: rpmspec.h:15
void unsetenv(const char *name)
static int rpmfcHelper(rpmfc fc, unsigned char deptype, const char *nsdep)
Run per-interpreter dependency helper.
Definition: rpmfc.c:414
static struct DepMsg_s depMsgs[]
Definition: rpmfc.c:1601
const char * rpmdsN(const rpmds ds)
Return current dependency name.
Definition: rpmds.c:668
static int rpmfcSCRIPT(rpmfc fc)
Extract script dependencies.
Definition: rpmfc.c:817
rpmiob rpmiobNew(size_t len)
Create an I/O buffer.
Definition: rpmiob.c:44
enum rpmfileAttrs_e rpmfileAttrs
File Attributes.
int rpmfiNext(rpmfi fi)
Return next file iterator index.
Definition: rpmfi.c:526
EVR_t rpmEVRnew(uint32_t Flags, int initialize)
Create a new EVR container.
Definition: rpmevr.c:31
#define S_IFSOCK
Definition: system.h:606
int(* func)(rpmfc fc)
Definition: rpmfc.c:1144
enum rpmRC_e rpmRC
RPM return codes.
char * rpmiobStr(rpmiob iob)
Return I/O buffer (as string).
Definition: rpmiob.c:113
Definition: rpmtag.h:503
rpmfi rpmfiInit(rpmfi fi, int fx)
Initialize file iterator index.
Definition: rpmfi.c:548
EVR_t rpmEVRfree(EVR_t evr)
Destroy an EVR container.
Definition: rpmevr.c:47
urltype urlPath(const char *url, const char **pathp)
Return path component of URL.
Definition: url.c:429
int rpmfcColoring(const char *fmstr)
Return file color given file(1) string.
Definition: rpmfc.c:720
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.
rpmioPool rpmioNewPool(const char *name, size_t size, int limit, int flags, char *(*dbg)(void *item), void(*init)(void *item), void(*fini)(void *item))
Create a memory pool.
Definition: rpmmalloc.c:110
rpmRC(* _parseRCPOT)(Spec spec, Package pkg, const char *field, rpmTag tagN, rpmuint32_t index, rpmsenseFlags tagflags)
Definition: rpmspec.h:174
rpmRC rpmfcClassify(rpmfc fc, ARGV_t argv, rpmuint16_t *fmode)
Definition: rpmfc.c:1382
int rpmdsMerge(rpmds *dsp, rpmds ods)
Merge a dependency set maintaining (N,EVR,Flags) sorted order.
Definition: rpmds.c:1033
char * stpcpy(char *dest, const char *src)
struct rpmmg_s * rpmmg
Definition: rpmmg.h:15
static rpmRC rpmfcGenerateDependsHelper(const Spec spec, Package pkg, rpmfi fi)
Definition: rpmfc.c:1694
static int rpmfcGenerateScriptletDeps(const Spec spec, Package pkg)
Definition: rpmfc.c:1799
static void * _free(const void *p)
Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
Definition: rpmiotypes.h:647
struct rpmiob_s * rpmiob
Definition: rpmiotypes.h:57
#define _suffix(_s, _x)
rpmds ds
Definition: rpmspec.h:212
int argiAdd(ARGI_t *argip, int ix, int val)
Add an int to an argi array.
Definition: argv.c:178
rpmioPool _rpmfcPool
Definition: rpmfc.c:2288
int mask
Definition: rpmfc.c:1593
int rpmdsSearch(rpmds ds, rpmds ods)
Search a sorted dependency set for an element that overlaps.
Definition: rpmds.c:1115
int argvSplit(ARGV_t *argvp, const char *str, const char *seps)
Split a string into an argv array.
Definition: argv.c:233
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
rpmiob rpmiobEmpty(rpmiob iob)
Empty an I/O buffer.
Definition: rpmiob.c:57
int rpmdsMatch(const rpmds A, rpmds B)
Compare A against every member of B, looking for 1st match.
Definition: rpmds.c:4485
struct rpmfcTokens_s * rpmfcToken
Definition: rpmfc.h:15
static void * rpmfcFreeRegexps(void *_mire, int nmire)
Definition: rpmfc.c:398
int argvSort(ARGV_t argv, int(*compar)(ARGstr_t *, ARGstr_t *))
Sort an argv array.
Definition: argv.c:137
int rpmdsELF(const char *fn, int flags, int(*add)(void *context, rpmds ds), void *context)
Return a soname dependency constructed from an elf string.
Definition: rpmds.c:3212
int mireAppend(rpmMireMode mode, int tag, const char *pattern, const unsigned char *table, miRE *mirep, int *nmirep)
Append pattern to array.
Definition: mire.c:499
#define _(Text)
Definition: system.h:30
The structure used to store values for a package.
Definition: rpmspec.h:207
#define RPMELF_FLAG_SKIPPROVIDES
Definition: rpmds.h:615
rpmRC rpmfcGenerateDepends(void *_spec, void *_pkg)
Generate package dependencies.
Definition: rpmfc.c:1992
ARGstr_t * ARGV_t
Definition: argv.h:9
rpmfi fi
Definition: rpmspec.h:214
enum rpmTag_e rpmTag
Definition: rpmtag.h:471
#define D_(Text)
Definition: system.h:485
rpmds rpmdsNew(Header h, rpmTag tagN, int flags)
Create and load a dependency set.
Definition: rpmds.c:238
static int _filter_execs
Definition: rpmfc.c:41
int rpmdsSetIx(rpmds ds, int ix)
Set dependency set index.
Definition: rpmds.c:646
ARGint_t argiData(ARGI_t argi)
Return data from argi array.
Definition: argv.c:63
int rpmExpandNumeric(const char *arg)
Return macro expansion as a numeric value.
Definition: macro.c:3191
struct rpmfc_s * rpmfc
Definition: rpmfc.h:11
#define xrealloc
Definition: system.h:36
rpmmg rpmmgFree(rpmmg mg)
Destroy a magic wrapper.
rpmfc rpmfcNew(void)
Create a file classifier.
Definition: rpmfc.c:2306
#define RPMFC_ELF
Definition: rpmfc.h:24
int autoReq
Definition: rpmspec.h:216
rpmTag ntag
Definition: rpmfc.c:1590
static void * rpmfcExpandRegexps(const char *str, int *nmirep)
Definition: rpmfc.c:334