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  { "PHP script text", RPMFC_PHP|RPMFC_INCLUDE },
639  { "G-IR binary database", RPMFC_TYPELIB|RPMFC_INCLUDE },
640 
641  /* XXX "a /usr/bin/python -t script text executable" */
642  /* XXX "python 2.3 byte-compiled" */
643  { " /usr/bin/python", RPMFC_PYTHON|RPMFC_INCLUDE },
644  { "python ", RPMFC_PYTHON|RPMFC_INCLUDE },
645  { "Python script", RPMFC_PYTHON|RPMFC_INCLUDE },
646 
647  { "libtool library ", RPMFC_LIBTOOL|RPMFC_INCLUDE },
648  { "pkgconfig ", RPMFC_PKGCONFIG|RPMFC_INCLUDE },
649 
650  { "Bourne ", RPMFC_BOURNE|RPMFC_INCLUDE },
651  { "Bourne-Again ", RPMFC_BOURNE|RPMFC_INCLUDE },
652 
653  { "Java ", RPMFC_JAVA|RPMFC_INCLUDE },
654 
655  { "Mono/.Net assembly", RPMFC_MONO|RPMFC_INCLUDE },
656 
657  { "ruby script text", RPMFC_RUBY|RPMFC_INCLUDE },
658  { "Ruby script text", RPMFC_RUBY|RPMFC_INCLUDE },
659 
660  { "current ar archive", RPMFC_STATIC|RPMFC_LIBRARY|RPMFC_ARCHIVE|RPMFC_INCLUDE },
661 
662  { "Zip archive data", RPMFC_COMPRESSED|RPMFC_ARCHIVE|RPMFC_INCLUDE },
663  { "tar archive", RPMFC_ARCHIVE|RPMFC_INCLUDE },
664  { "cpio archive", RPMFC_ARCHIVE|RPMFC_INCLUDE },
665  { "RPM v3", RPMFC_ARCHIVE|RPMFC_INCLUDE },
666  { "RPM v4", RPMFC_ARCHIVE|RPMFC_INCLUDE },
667 
668  { " image", RPMFC_IMAGE|RPMFC_INCLUDE },
669  { " font", RPMFC_FONT|RPMFC_INCLUDE },
670  { " Font", RPMFC_FONT|RPMFC_INCLUDE },
671 
672  { " commands", RPMFC_SCRIPT|RPMFC_INCLUDE },
673  { " script", RPMFC_SCRIPT|RPMFC_INCLUDE },
674 
675  { "empty", RPMFC_WHITE|RPMFC_INCLUDE },
676 
677  { "HTML", RPMFC_WHITE|RPMFC_INCLUDE },
678  { "SGML", RPMFC_WHITE|RPMFC_INCLUDE },
679  { "XML", RPMFC_WHITE|RPMFC_INCLUDE },
680 
681  { " program text", RPMFC_WHITE|RPMFC_INCLUDE },
682  { " source", RPMFC_WHITE|RPMFC_INCLUDE },
683  { "GLS_BINARY_LSB_FIRST", RPMFC_WHITE|RPMFC_INCLUDE },
684  { " DB ", RPMFC_WHITE|RPMFC_INCLUDE },
685 
686  { "ASCII English text", RPMFC_WHITE|RPMFC_INCLUDE },
687  { "ASCII text", RPMFC_WHITE|RPMFC_INCLUDE },
688  { "ISO-8859 text", RPMFC_WHITE|RPMFC_INCLUDE },
689 
690  { "symbolic link to", RPMFC_SYMLINK },
691  { "socket", RPMFC_DEVICE },
692  { "special", RPMFC_DEVICE },
693 
694  { "ASCII", RPMFC_WHITE },
695  { "ISO-8859", RPMFC_WHITE },
696 
697  { "data", RPMFC_WHITE },
698 
699  { "application", RPMFC_WHITE },
700  { "boot", RPMFC_WHITE },
701  { "catalog", RPMFC_WHITE },
702  { "code", RPMFC_WHITE },
703  { "file", RPMFC_WHITE },
704  { "format", RPMFC_WHITE },
705  { "message", RPMFC_WHITE },
706  { "program", RPMFC_WHITE },
707 
708  { "broken symbolic link to ", RPMFC_WHITE|RPMFC_ERROR },
709  { "can't read", RPMFC_WHITE|RPMFC_ERROR },
710  { "can't stat", RPMFC_WHITE|RPMFC_ERROR },
711  { "executable, can't read", RPMFC_WHITE|RPMFC_ERROR },
712  { "core file", RPMFC_WHITE|RPMFC_ERROR },
713 
714  { NULL, RPMFC_BLACK }
715 };
716 /*@=nullassign@*/
717 
718 int rpmfcColoring(const char * fmstr)
719 {
720  rpmfcToken fct;
721  int fcolor = RPMFC_BLACK;
722 
723  for (fct = rpmfcTokens; fct->token != NULL; fct++) {
724  if (strstr(fmstr, fct->token) == NULL)
725  continue;
726  fcolor |= fct->colors;
727  if (fcolor & RPMFC_INCLUDE)
728  return fcolor;
729  }
730  return fcolor;
731 }
732 
733 void rpmfcPrint(const char * msg, rpmfc fc, FILE * fp)
734 {
735  int fcolor;
736  int ndx;
737  int cx;
738  int dx;
739  size_t fx;
740 
741 unsigned nprovides;
742 unsigned nrequires;
743 
744  if (fp == NULL) fp = stderr;
745 
746  if (msg)
747  fprintf(fp, "===================================== %s\n", msg);
748 
749 nprovides = rpmdsCount(fc->provides);
750 nrequires = rpmdsCount(fc->requires);
751 
752  if (fc)
753  for (fx = 0; fx < fc->nfiles; fx++) {
754 assert(fx < fc->fcdictx->nvals);
755  cx = fc->fcdictx->vals[fx];
756 assert(fx < fc->fcolor->nvals);
757  fcolor = fc->fcolor->vals[fx];
758 
759  fprintf(fp, "%3d %s", (int)fx, fc->fn[fx]);
760  if (fcolor != RPMFC_BLACK)
761  fprintf(fp, "\t0x%x", fc->fcolor->vals[fx]);
762  else
763  fprintf(fp, "\t%s", fc->cdict[cx]);
764  fprintf(fp, "\n");
765 
766  if (fc->fddictx == NULL || fc->fddictn == NULL)
767  continue;
768 
769 assert(fx < fc->fddictx->nvals);
770  dx = fc->fddictx->vals[fx];
771 assert(fx < fc->fddictn->nvals);
772  ndx = fc->fddictn->vals[fx];
773 
774  while (ndx-- > 0) {
775  const char * depval;
776  unsigned char deptype;
777  unsigned ix;
778 
779  ix = fc->ddictx->vals[dx++];
780  deptype = ((ix >> 24) & 0xff);
781  ix &= 0x00ffffff;
782  depval = NULL;
783  switch (deptype) {
784  default:
785 assert(depval != NULL);
786  /*@switchbreak@*/ break;
787  case 'P':
788  if (nprovides > 0) {
789 assert(ix < nprovides);
790  (void) rpmdsSetIx(fc->provides, ix-1);
791  if (rpmdsNext(fc->provides) >= 0)
792  depval = rpmdsDNEVR(fc->provides);
793  }
794  /*@switchbreak@*/ break;
795  case 'R':
796  if (nrequires > 0) {
797 assert(ix < nrequires);
798  (void) rpmdsSetIx(fc->requires, ix-1);
799  if (rpmdsNext(fc->requires) >= 0)
800  depval = rpmdsDNEVR(fc->requires);
801  }
802  /*@switchbreak@*/ break;
803  }
804  if (depval)
805  fprintf(fp, "\t%s\n", depval);
806  }
807  }
808 }
809 
815 static int rpmfcSCRIPT(rpmfc fc)
816  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
817  /*@modifies fc, rpmGlobalMacroContext, fileSystem, internalState @*/
818 {
819  const char * fn = fc->fn[fc->ix];
820  const char * bn;
821  rpmds ds;
822  char buf[BUFSIZ];
823  FILE * fp;
824  char * s, * se;
825  int i;
826  int is_executable;
827  int xx;
828 
829  /* Don't generate dependencies from files shipped as documentation */
830  if (!rpmExpandNumeric("%{_generate_dependencies_from_docdir}")) {
831  const char * defaultdocdir = rpmExpand("%{?_defaultdocdir}", NULL);
832  if (defaultdocdir == NULL || *defaultdocdir == '\0')
833  defaultdocdir = strdup("/usr/share/doc");
834  xx = !strncmp(fn+fc->brlen, defaultdocdir, strlen(defaultdocdir));
835  defaultdocdir = _free(defaultdocdir) ;
836  if (xx)
837  return 0;
838  }
839 
840  /* Extract dependencies only from files with executable bit set. */
841  { struct stat sb, * st = &sb;
842  if (stat(fn, st) != 0)
843  return -1;
844  is_executable = (int)(st->st_mode & (S_IXUSR|S_IXGRP|S_IXOTH));
845  }
846 
847  fp = fopen(fn, "r");
848  if (fp == NULL || ferror(fp)) {
849  if (fp) (void) fclose(fp);
850  return -1;
851  }
852 
853  /* Look for #! interpreter in first 10 lines. */
854  for (i = 0; i < 10; i++) {
855 
856  s = fgets(buf, sizeof(buf) - 1, fp);
857  if (s == NULL || ferror(fp) || feof(fp))
858  break;
859  s[sizeof(buf)-1] = '\0';
860  if (!(s[0] == '#' && s[1] == '!'))
861  continue;
862  s += 2;
863 
864  while (*s && strchr(" \t\n\r", *s) != NULL)
865  s++;
866  if (*s == '\0')
867  continue;
868  if (*s != '/')
869  continue;
870 
871  for (se = s+1; *se; se++) {
872  if (strchr(" \t\n\r", *se) != NULL)
873  /*@innerbreak@*/ break;
874  }
875  *se = '\0';
876  se++;
877 
878 /*@-moduncon@*/
879  bn = basename(s);
880 
881  if (!_filter_values
882  || (!fc->skipReq
883  && !rpmfcMatchRegexps(fc->Rmires, fc->Rnmire, s, 'R'))) {
884  if (is_executable &&
885  strncmp(bn, "bash", sizeof("bash")-1) &&
886  strcmp(bn, "env") &&
887  strncmp(bn, "perl", sizeof("perl")-1) &&
888  strncmp(bn, "python", sizeof("python")-1) &&
889  strncmp(bn, "ruby", sizeof("ruby")-1) &&
890  strcmp(bn, "sh")) {
891  /* Add to package requires. */
892  ds = rpmdsSingle(RPMTAG_REQUIRENAME, s, "", RPMSENSE_FIND_REQUIRES);
893  xx = rpmdsMerge(&fc->requires, ds);
894 
895  /* Add to file requires. */
896  xx = rpmfcSaveArg(&fc->ddict, rpmfcFileDep(se, fc->ix, ds));
897 
898  (void)rpmdsFree(ds);
899  ds = NULL;
900  } else if (!strcmp(bn, "env") && strlen(se)) {
901  bn = se;
902  strsep(&se, " \t\n\r");
903  }
904  }
905 
906  /* Set color based on interpreter name. */
907  /* XXX magic token should have already done this?!? */
908 /*@=moduncon@*/
909  if (!strcmp(bn, "perl"))
910  fc->fcolor->vals[fc->ix] |= RPMFC_PERL;
911  else if (!strncmp(bn, "python", sizeof("python")-1))
912  fc->fcolor->vals[fc->ix] |= RPMFC_PYTHON;
913  else if (!strncmp(bn, "php", sizeof("php")-1))
914  fc->fcolor->vals[fc->ix] |= RPMFC_PHP;
915  else if (!strncmp(bn, "ruby", sizeof("ruby")-1))
916  fc->fcolor->vals[fc->ix] |= RPMFC_RUBY;
917 
918  break;
919  }
920 
921  (void) fclose(fp);
922 
923  if (fc->fcolor->vals[fc->ix] & RPMFC_PERL) {
924  if (fc->fcolor->vals[fc->ix] & RPMFC_MODULE)
925  xx = rpmfcHelper(fc, 'P', "perl");
926  if (is_executable || (fc->fcolor->vals[fc->ix] & RPMFC_MODULE))
927  xx = rpmfcHelper(fc, 'R', "perl");
928  } else
929  if (fc->fcolor->vals[fc->ix] & RPMFC_PYTHON) {
930  if (fc->fcolor->vals[fc->ix] & RPMFC_MODULE && !(fc->fcolor->vals[fc->ix] & RPMFC_SCRIPT))
931  xx = rpmfcHelper(fc, 'P', "python");
932  if (is_executable || (fc->fcolor->vals[fc->ix] & RPMFC_MODULE))
933  xx = rpmfcHelper(fc, 'R', "python");
934  } else
935  if (fc->fcolor->vals[fc->ix] & RPMFC_LIBTOOL) {
936  xx = rpmfcHelper(fc, 'P', "libtool");
937 #ifdef NOTYET
938  if (is_executable)
939 #endif
940  xx = rpmfcHelper(fc, 'R', "libtool");
941  } else
942  if (fc->fcolor->vals[fc->ix] & RPMFC_PKGCONFIG) {
943  xx = rpmfcHelper(fc, 'P', "pkgconfig");
944 #ifdef NOTYET
945  if (is_executable)
946 #endif
947  xx = rpmfcHelper(fc, 'R', "pkgconfig");
948  } else
949  if (fc->fcolor->vals[fc->ix] & RPMFC_BOURNE) {
950 #ifdef NOTYET
951  xx = rpmfcHelper(fc, 'P', "executable");
952 #endif
953  if (is_executable)
954  xx = rpmfcHelper(fc, 'R', "executable");
955  } else
956  if (fc->fcolor->vals[fc->ix] & RPMFC_PHP) {
957  xx = rpmfcHelper(fc, 'P', "php");
958 #ifdef NOTYET
959  if (is_executable)
960 #endif
961  xx = rpmfcHelper(fc, 'R', "php");
962  } else
963  if (fc->fcolor->vals[fc->ix] & RPMFC_MONO) {
964  xx = rpmfcHelper(fc, 'P', "mono");
965  if (is_executable)
966  xx = rpmfcHelper(fc, 'R', "mono");
967  } else
968  if (fc->fcolor->vals[fc->ix] & RPMFC_RUBY) {
969  if (fc->fcolor->vals[fc->ix] & RPMFC_MODULE)
970  xx = rpmfcHelper(fc, 'P', "ruby");
971  if (is_executable || (fc->fcolor->vals[fc->ix] & RPMFC_MODULE))
972  xx = rpmfcHelper(fc, 'R', "ruby");
973  } else
974  if (fc->fcolor->vals[fc->ix] & RPMFC_FONT) {
975  xx = rpmfcHelper(fc, 'P', "font");
976  /* XXX: currently of no use, but for the sake of consistency... */
977  xx = rpmfcHelper(fc, 'R', "font");
978  } else
979  if (fc->fcolor->vals[fc->ix] & RPMFC_HASKELL) {
980  xx = rpmfcHelper(fc, 'P', "haskell");
981  xx = rpmfcHelper(fc, 'R', "haskell");
982  } else
983  if (fc->fcolor->vals[fc->ix] & RPMFC_TYPELIB) {
984  xx = rpmfcHelper(fc, 'P', "typelib");
985 #ifdef NOTYET
986  if (is_executable)
987 #endif
988  xx = rpmfcHelper(fc, 'R', "typelib");
989  } else
990  if ((fc->fcolor->vals[fc->ix] & (RPMFC_MODULE|RPMFC_LIBRARY)) &&
991  strstr(fn, "/gstreamer")) {
992  xx = rpmfcHelper(fc, 'P', "gstreamer");
993  /* XXX: currently of no use, but for the sake of consistency... */
994  xx = rpmfcHelper(fc, 'R', "gstreamer");
995 #if defined(RPM_VENDOR_MANDRIVA)
996  } else
997  if ((fc->fcolor->vals[fc->ix] & RPMFC_MODULE)) {
999  if (!mireRegcomp(mire, "^.*((/lib/modules/|/var/lib/dkms/).*\\.ko(\\.gz|\\.xz)?|(/var/lib/dkms-binary/[^/]+/[^/]+|/usr/src)/[^/]+/dkms.conf)$"))
1000  if (mireRegexec(mire, fc->fn[fc->ix], (size_t) 0) >= 0) {
1001  fc->fcolor->vals[fc->ix] |= (RPMFC_MODULE|RPMFC_SCRIPT);
1002  xx = rpmfcHelper(fc, 'P', "kernel");
1003  /* XXX: currently of no use, but for the sake of consistency... */
1004  xx = rpmfcHelper(fc, 'R', "kernel");
1005  }
1006  mire = mireFree(mire);
1007  }
1008  if ((fc->fcolor->vals[fc->ix] & RPMFC_SCRIPT)) {
1010  if (!mireRegcomp(mire, "^.*/usr/share/applications/.*\\.desktop$"))
1011  if (mireRegexec(mire, fc->fn[fc->ix], (size_t) 0) >= 0) {
1012  fc->fcolor->vals[fc->ix] |= (RPMFC_MODULE|RPMFC_SCRIPT);
1013  xx = rpmfcHelper(fc, 'P', "desktop");
1014  /* XXX: currently of no use, but for the sake of consistency... */
1015  xx = rpmfcHelper(fc, 'R', "desktop");
1016  }
1017  mire = mireFree(mire);
1018 #endif
1019  }
1020 
1021 /*@=observertrans@*/
1022  return 0;
1023 }
1024 
1031 static int rpmfcMergePR(void * context, rpmds ds)
1032  /*@globals fileSystem, internalState @*/
1033  /*@modifies ds, fileSystem, internalState @*/
1034 {
1035  rpmfc fc = (rpmfc) context;
1036  char buf[BUFSIZ];
1037  int rc = 0;
1038 
1039 if (_rpmfc_debug < 0)
1040 fprintf(stderr, "*** rpmfcMergePR(%p, %p) %s\n", context, ds, tagName(rpmdsTagN(ds)));
1041  switch(rpmdsTagN(ds)) {
1042  default:
1043  rc = -1;
1044  break;
1045  case RPMTAG_PROVIDENAME:
1046  if (!_filter_values
1047  || (!fc->skipProv
1048  && !rpmfcMatchRegexps(fc->Pmires, fc->Pnmire, ds->N[0], 'P')))
1049  {
1050  /* Add to package provides. */
1051  rc = rpmdsMerge(&fc->provides, ds);
1052 
1053  /* Add to file dependencies. */
1054  buf[0] = '\0';
1055  rc = rpmfcSaveArg(&fc->ddict, rpmfcFileDep(buf, fc->ix, ds));
1056  }
1057  break;
1058  case RPMTAG_REQUIRENAME:
1059  if (!_filter_values
1060  || (!fc->skipReq
1061  && !rpmfcMatchRegexps(fc->Rmires, fc->Rnmire, ds->N[0], 'R')))
1062  {
1063  /* Add to package requires. */
1064  rc = rpmdsMerge(&fc->requires, ds);
1065 
1066  /* Add to file dependencies. */
1067  buf[0] = '\0';
1068  rc = rpmfcSaveArg(&fc->ddict, rpmfcFileDep(buf, fc->ix, ds));
1069  }
1070  break;
1071  }
1072  return rc;
1073 }
1074 
1080 static int rpmfcELF(rpmfc fc)
1081  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1082  /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
1083 {
1084  const char * fn = fc->fn[fc->ix];
1085  int flags = 0;
1086 
1087  if (fc->skipProv)
1088  flags |= RPMELF_FLAG_SKIPPROVIDES;
1089  if (fc->skipReq)
1090  flags |= RPMELF_FLAG_SKIPREQUIRES;
1091 
1092  return rpmdsELF(fn, flags, rpmfcMergePR, fc);
1093 }
1094 
1095 #if defined(RPM_VENDOR_MANDRIVA)
1096 
1105 extern int rpmdsSymlink(const char * fn, int flags,
1106  int (*add) (void * context, rpmds ds), void * context)
1107  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1108  /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/;
1109 
1110 static int rpmfcSYMLINK(rpmfc fc)
1111  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1112  /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
1113 {
1114  const char * fn = fc->fn[fc->ix];
1115  int flags = 0;
1116 
1117  if (fc->skipProv)
1118  flags |= RPMELF_FLAG_SKIPPROVIDES;
1119  if (fc->skipReq)
1120  flags |= RPMELF_FLAG_SKIPREQUIRES;
1121  /* XXX: Remove symlink classifier from linker scripts now that we've been
1122  * able to feed it to the generator.
1123  */
1124  if (fc->fcolor->vals[fc->ix] == (RPMFC_WHITE|RPMFC_INCLUDE|RPMFC_TEXT|RPMFC_SYMLINK))
1125  fc->fcolor->vals[fc->ix] &= ~RPMFC_SYMLINK;
1126 
1127  return rpmdsSymlink(fn, flags, rpmfcMergePR, fc);
1128 }
1129 #endif /* RPM_VENDOR_MANDRIVA */
1130 
1131 typedef struct rpmfcApplyTbl_s {
1132  int (*func) (rpmfc fc);
1134 } * rpmfcApplyTbl;
1135 
1139 /*@-nullassign@*/
1140 /*@unchecked@*/
1142  { rpmfcELF, RPMFC_ELF },
1144 #if defined(RPM_VENDOR_MANDRIVA)
1145  { rpmfcSYMLINK, RPMFC_SYMLINK },
1146 #endif
1147  { NULL, 0 }
1148 };
1149 /*@=nullassign@*/
1150 
1152 {
1153  rpmfcApplyTbl fcat;
1154  const char * s;
1155  char * se;
1156  rpmds ds;
1157  const char * fn;
1158  const char * N;
1159  const char * EVR;
1160  evrFlags Flags;
1161  unsigned char deptype;
1162  int nddict;
1163  int previx;
1164  unsigned int val;
1165  int dix;
1166  int ix;
1167  int i;
1168  int xx;
1169  int skipping;
1170 
1171  miRE mire;
1172  int skipProv = fc->skipProv;
1173  int skipReq = fc->skipReq;
1174  int j;
1175 
1176  if (_filter_execs) {
1177  fc->PFnmire = 0;
1178  fc->PFmires = rpmfcExpandRegexps("%{?__noautoprovfiles}", &fc->PFnmire);
1179  if (fc->PFnmire > 0)
1180  rpmlog(RPMLOG_DEBUG, D_("added %d %%__noautoprovfiles patterns.\n"),
1181  fc->PFnmire);
1182  fc->RFnmire = 0;
1183  fc->RFmires = rpmfcExpandRegexps("%{?__noautoreqfiles}", &fc->RFnmire);
1184  if (fc->RFnmire > 0)
1185  rpmlog(RPMLOG_DEBUG, D_("added %d %%__noautoreqfiles patterns.\n"),
1186  fc->RFnmire);
1187  fc->Pnmire = 0;
1188  fc->Pmires = rpmfcExpandRegexps("%{?__noautoprov}", &fc->Pnmire);
1189  if (fc->Pnmire > 0)
1190  rpmlog(RPMLOG_DEBUG, D_("added %d %%__noautoprov patterns.\n"),
1191  fc->Pnmire);
1192  fc->Rnmire = 0;
1193  fc->Rmires = rpmfcExpandRegexps("%{?__noautoreq}", &fc->Rnmire);
1194  if (fc->Rnmire > 0)
1195  rpmlog(RPMLOG_DEBUG, D_("added %d %%__noautoreq patterns.\n"),
1196  fc->Rnmire);
1197  }
1198 
1199 /* Make sure something didn't go wrong previously! */
1200 assert(fc->fn != NULL);
1201  /* Generate package and per-file dependencies. */
1202  for (fc->ix = 0; fc->fn[fc->ix] != NULL; fc->ix++) {
1203 
1204  /* XXX Insure that /usr/lib{,64}/python files are marked RPMFC_PYTHON */
1205  /* XXX HACK: classification by path is intrinsically stupid. */
1206  { fn = strstr(fc->fn[fc->ix], "/usr/lib");
1207  if (fn) {
1208  fn += sizeof("/usr/lib")-1;
1209  if ((fn[0] == '3' && fn[1] == '2') ||
1210  (fn[0] == '6' && fn[1] == '4'))
1211  fn += 2;
1212  if (!strncmp(fn, "/python", sizeof("/python")-1)) {
1213  fc->fcolor->vals[fc->ix] |= RPMFC_PYTHON;
1214  if (strstr(fn, "site-packages"))
1215  fc->fcolor->vals[fc->ix] |= RPMFC_MODULE;
1216  else if (strstr(fn, ".egg")) {
1218  if (!mireRegcomp(mire, ".*/.*\\.egg(|-info|-link)(|/.*)$"))
1219  if (mireRegexec(mire, fc->fn[fc->ix], (size_t) 0) >= 0)
1220  fc->fcolor->vals[fc->ix] |= RPMFC_MODULE;
1221  mire = mireFree(mire);
1222  }
1223  }
1224  else if (!strncmp(fn, "/ruby", sizeof("/ruby")-1)) {
1225  fc->fcolor->vals[fc->ix] |= RPMFC_RUBY;
1226  if ((strstr(fn, ".gemspec") || strstr(fn, "rbconfig.rb"))) {
1228  if (!mireRegcomp(mire, ".*/(specifications/.*\\.gemspec|rbconfig\\.rb)$"))
1229  if (mireRegexec(mire, fc->fn[fc->ix], (size_t) 0) >= 0)
1230  fc->fcolor->vals[fc->ix] |= RPMFC_MODULE;
1231  mire = mireFree(mire);
1232  }
1233  }
1234  /* XXX: lacking better, more generic classifier... */
1235  else if (!strncmp(fn, "/gstreamer", sizeof("/gstreamer")-1) &&
1236  fc->fcolor->vals[fc->ix] & RPMFC_LIBRARY)
1237  fc->fcolor->vals[fc->ix] |= (RPMFC_MODULE|RPMFC_SCRIPT);
1238 #if defined(RPM_VENDOR_MANDRIVA)
1239  } else {
1241  if (!mireRegcomp(mire, "^.*((/lib/modules/|/var/lib/dkms/).*\\.ko(\\.gz|\\.xz)?|(/var/lib/dkms-binary/[^/]+/[^/]+|/usr/src)/[^/]+/dkms.conf)$"))
1242  if (mireRegexec(mire, fc->fn[fc->ix], (size_t) 0) >= 0)
1243  fc->fcolor->vals[fc->ix] |= (RPMFC_MODULE|RPMFC_SCRIPT);
1244  mire = mireFree(mire);
1246  /* buttfuckin' retarded, but whatever.. it'll work at least! ;) */
1247  if (!mireRegcomp(mire, "^.*/usr/share/applications/.*\\.desktop$"))
1248  if (mireRegexec(mire, fc->fn[fc->ix], (size_t) 0) >= 0)
1249  fc->fcolor->vals[fc->ix] |= RPMFC_SCRIPT;
1250  mire = mireFree(mire);
1251 #endif
1252  }
1253  }
1254 
1255  /* XXX ugly quick & dirty integration of haskell() dependencies */
1256  { fn = strstr(fc->fn[fc->ix], "/usr/share/haskell-deps");
1257  if (fn)
1258  fc->fcolor->vals[fc->ix] |= RPMFC_HASKELL;
1259  }
1260 
1261  if (fc->fcolor->vals[fc->ix])
1262  for (fcat = rpmfcApplyTable; fcat->func != NULL; fcat++) {
1263  if (!(fc->fcolor->vals[fc->ix] & fcat->colormask))
1264  /*@innercontinue@*/ continue;
1265 
1266  if (_filter_execs) {
1267  fc->skipProv = skipProv;
1268  fc->skipReq = skipReq;
1269  if ((mire = (miRE)fc->PFmires) != NULL)
1270  for (j = 0; j < fc->PFnmire; j++, mire++) {
1271  fn = fc->fn[fc->ix] + fc->brlen;
1272  if ((xx = mireRegexec(mire, fn, 0)) < 0)
1273  /*@innercontinue@*/ continue;
1274  rpmlog(RPMLOG_NOTICE, _("skipping %s provides detection\n"),
1275  fn);
1276  fc->skipProv = 1;
1277  /*@innerbreak@*/ break;
1278  }
1279  if ((mire = (miRE)fc->RFmires) != NULL)
1280  for (j = 0; j < fc->RFnmire; j++, mire++) {
1281  fn = fc->fn[fc->ix] + fc->brlen;
1282  if ((xx = mireRegexec(mire, fn, 0)) < 0)
1283  /*@innercontinue@*/ continue;
1284  rpmlog(RPMLOG_NOTICE, _("skipping %s requires detection\n"),
1285  fn);
1286  fc->skipReq = 1;
1287  /*@innerbreak@*/ break;
1288  }
1289  }
1290 
1291  struct stat sb, * st = &sb;
1292  if (stat(fc->fn[fc->ix], st) == 0 && !(st->st_mode & (S_IFBLK|S_IFCHR)))
1293  xx = (*fcat->func) (fc);
1294  }
1295  }
1296 
1297  if (_filter_execs) {
1298  fc->PFmires = rpmfcFreeRegexps(fc->PFmires, fc->PFnmire);
1299  fc->RFmires = rpmfcFreeRegexps(fc->RFmires, fc->RFnmire);
1300  fc->Pmires = rpmfcFreeRegexps(fc->Pmires, fc->Pnmire);
1301  fc->Rmires = rpmfcFreeRegexps(fc->Rmires, fc->Rnmire);
1302  }
1303  fc->skipProv = skipProv;
1304  fc->skipReq = skipReq;
1305 
1306  /* Generate per-file indices into package dependencies. */
1307  nddict = argvCount(fc->ddict);
1308  previx = -1;
1309  for (i = 0; i < nddict; i++) {
1310  s = fc->ddict[i];
1311 
1312  /* Parse out (file#,deptype,N,EVR,Flags) */
1313  ix = strtol(s, &se, 10);
1314 assert(se != NULL);
1315  deptype = *se++;
1316  se++;
1317  N = se;
1318  while (*se && *se != ' ')
1319  se++;
1320  *se++ = '\0';
1321  EVR = se;
1322  while (*se && *se != ' ')
1323  se++;
1324  *se++ = '\0';
1325  Flags = (evrFlags) strtol(se, NULL, 16);
1326 
1327  dix = -1;
1328  skipping = 0;
1329  switch (deptype) {
1330  default:
1331  /*@switchbreak@*/ break;
1332  case 'P':
1333  skipping = fc->skipProv;
1334  ds = rpmdsSingle(RPMTAG_PROVIDENAME, N, EVR, Flags);
1335  dix = rpmdsFind(fc->provides, ds);
1336  (void)rpmdsFree(ds);
1337  ds = NULL;
1338  /*@switchbreak@*/ break;
1339  case 'R':
1340  skipping = fc->skipReq;
1341  ds = rpmdsSingle(RPMTAG_REQUIRENAME, N, EVR, Flags);
1342  dix = rpmdsFind(fc->requires, ds);
1343  (void)rpmdsFree(ds);
1344  ds = NULL;
1345  /*@switchbreak@*/ break;
1346  }
1347 
1348 /* XXX assertion incorrect while generating -debuginfo deps. */
1349 #if 0
1350 assert(dix >= 0);
1351 #else
1352  if (dix < 0)
1353  continue;
1354 #endif
1355 
1356  val = (deptype << 24) | (dix & 0x00ffffff);
1357  xx = argiAdd(&fc->ddictx, -1, val);
1358 
1359  if (previx != ix) {
1360  previx = ix;
1361  xx = argiAdd(&fc->fddictx, ix, argiCount(fc->ddictx)-1);
1362  }
1363  if (fc->fddictn && fc->fddictn->vals && !skipping)
1364  fc->fddictn->vals[ix]++;
1365  }
1366 
1367  return RPMRC_OK;
1368 }
1369 
1371 {
1372  ARGV_t fcav = NULL;
1373  ARGV_t dav;
1374  rpmmg mg = NULL;
1375  const char * s, * se;
1376  size_t slen;
1377  int fcolor;
1378  int xx;
1379  const char * magicfile = NULL;
1380 
1381  if (fc == NULL || argv == NULL)
1382  return RPMRC_OK;
1383 
1384  magicfile = rpmExpand("%{?_rpmfc_magic_path}", NULL);
1385  if (magicfile == NULL || *magicfile == '\0')
1386  magicfile = _free(magicfile);
1387 
1388  mg = rpmmgNew(magicfile, 0);
1389 assert(mg != NULL); /* XXX figger a proper return path. */
1390 
1391  fc->nfiles = argvCount(argv);
1392 
1393  /* Initialize the per-file dictionary indices. */
1394  xx = argiAdd(&fc->fddictx, fc->nfiles-1, 0);
1395  xx = argiAdd(&fc->fddictn, fc->nfiles-1, 0);
1396 
1397  /* Build (sorted) file class dictionary. */
1398  xx = argvAdd(&fc->cdict, "");
1399  xx = argvAdd(&fc->cdict, "directory");
1400 
1401  for (fc->ix = 0; fc->ix < fc->nfiles; fc->ix++) {
1402  const char * ftype;
1403  int freeftype;
1404  rpmuint16_t mode = (fmode ? fmode[fc->ix] : 0);
1405  int urltype;
1406 
1407  ftype = ""; freeftype = 0;
1408  urltype = urlPath(argv[fc->ix], &s);
1409 assert(s != NULL && *s == '/');
1410  slen = strlen(s);
1411 
1412  switch (mode & S_IFMT) {
1413  case S_IFCHR: ftype = "character special"; /*@switchbreak@*/ break;
1414  case S_IFBLK: ftype = "block special"; /*@switchbreak@*/ break;
1415 #if defined(S_IFIFO)
1416  case S_IFIFO: ftype = "fifo (named pipe)"; /*@switchbreak@*/ break;
1417 #endif
1418 #if defined(S_IFSOCK)
1419 /*@-unrecog@*/
1420  case S_IFSOCK: ftype = "socket"; /*@switchbreak@*/ break;
1421 /*@=unrecog@*/
1422 #endif
1423  case S_IFDIR:
1424  case S_IFLNK:
1425  case S_IFREG:
1426  default:
1427 
1428 #define _suffix(_s, _x) \
1429  (slen >= sizeof(_x) && !strcmp((_s)+slen-(sizeof(_x)-1), (_x)))
1430 
1431  /* XXX all files with extension ".pm" are perl modules for now. */
1432  if (_suffix(s, ".pm"))
1433  ftype = "Perl5 module source text";
1434 
1435  /* XXX all files with extension ".jar" are java archives for now. */
1436  else if (_suffix(s, ".jar"))
1437  ftype = "Java archive file";
1438 
1439  /* XXX all files with extension ".class" are java class files for now. */
1440  else if (_suffix(s, ".class"))
1441  ftype = "Java class file";
1442 
1443  /* XXX all files with extension ".la" are libtool for now. */
1444  else if (_suffix(s, ".la"))
1445  ftype = "libtool library file";
1446 
1447  /* XXX all files with extension ".pc" are pkgconfig for now. */
1448  else if (_suffix(s, ".pc"))
1449  ftype = "pkgconfig file";
1450 
1451  /* XXX all files with extension ".php" are PHP for now. */
1452  else if (_suffix(s, ".php"))
1453  ftype = "PHP script text";
1454 
1455  /* XXX files with extension ".typelib" are GNOME typelib for now. */
1456  else if (_suffix(s, ".typelib"))
1457  ftype = "G-IR binary database";
1458 
1459  /* XXX files with extension ".js" have GNOME typelib requires for now */
1460  else if (_suffix(s, ".js"))
1461  ftype = "G-IR binary database";
1462 
1463  /* XXX skip all files in /dev/ which are (or should be) %dev dummies. */
1464  else if (slen >= fc->brlen+sizeof("/dev/") && !strncmp(s+fc->brlen, "/dev/", sizeof("/dev/")-1))
1465  ftype = "";
1466  else if (magicfile) {
1467  ftype = rpmmgFile(mg, s);
1468 assert(ftype != NULL); /* XXX never happens, rpmmgFile() returns "" */
1469  freeftype = 1;
1470  }
1471  /*@switchbreak@*/ break;
1472  }
1473 
1474  se = ftype;
1475 
1476 if (_rpmfc_debug) /* XXX noisy */
1477  rpmlog(RPMLOG_DEBUG, "%s: %s\n", s, se);
1478 
1479  /* Save the path. */
1480  xx = argvAdd(&fc->fn, s);
1481 
1482  /* Save the file type string. */
1483  xx = argvAdd(&fcav, se);
1484 
1485  /* Add (filtered) entry to sorted class dictionary. */
1486  fcolor = rpmfcColoring(se);
1487 
1488  /* Quick&dirty hack for linker scripts replacing regular
1489  * symlinks. Better *really* needs to be done ASAP.
1490  */
1491 #if defined(RPM_VENDOR_MANDRIVA)
1492  if (fcolor == (RPMFC_WHITE|RPMFC_INCLUDE|RPMFC_TEXT)) {
1493  char * fn;
1494 
1495  if ((fn = strrchr(s, '.')) && !strcmp(fn, ".so")) {
1496  FILE * fp = fopen(s, "r");
1497  char buf[BUFSIZ];
1498  char * in;
1499  if (fp == NULL || ferror(fp)) {
1500  if (fp) (void) fclose(fp);
1501  }
1502  while ((in = fgets(buf, sizeof(buf) - 1, fp))) {
1503  in[sizeof(buf)-1] = '\0';
1504  if (ferror(fp) || feof(fp))
1505  break;
1506  if ((fn = strstr(in, "GROUP")) &&
1507  (fn = strchr(fn, '(')) && (fn = strchr(in, '/'))) {
1508  fcolor |= RPMFC_SYMLINK;
1509  break;
1510  }
1511  }
1512  if (fp)
1513  fclose(fp);
1514  }
1515  }
1516 #endif
1517  xx = argiAdd(&fc->fcolor, (int)fc->ix, fcolor);
1518 
1519  if (fcolor != RPMFC_WHITE && (fcolor & RPMFC_INCLUDE))
1520  xx = rpmfcSaveArg(&fc->cdict, se);
1521 
1522 /*@-modobserver -observertrans @*/ /* XXX mixed types in variable */
1523  if (freeftype)
1524  ftype = _free(ftype);
1525 /*@=modobserver =observertrans @*/
1526  }
1527 
1528  /* Build per-file class index array. */
1529  fc->fknown = 0;
1530  for (fc->ix = 0; fc->ix < fc->nfiles; fc->ix++) {
1531  se = fcav[fc->ix];
1532 assert(se != NULL);
1533 
1534  dav = argvSearch(fc->cdict, se, NULL);
1535  if (dav) {
1536  xx = argiAdd(&fc->fcdictx, (int)fc->ix, (dav - fc->cdict));
1537  fc->fknown++;
1538  } else {
1539  xx = argiAdd(&fc->fcdictx, (int)fc->ix, 0);
1540  fc->fwhite++;
1541  }
1542  }
1543 
1544  fcav = argvFree(fcav);
1545 
1546  mg = rpmmgFree(mg);
1548  D_("categorized %d files into %u classes (using %s).\n"),
1549  (unsigned)fc->nfiles, argvCount(fc->cdict), magicfile);
1550  magicfile = _free(magicfile);
1551 
1552  return RPMRC_OK;
1553 }
1554 
1557 typedef struct DepMsg_s * DepMsg_t;
1558 
1561 struct DepMsg_s {
1562 /*@observer@*/ /*@null@*/
1563  const char * msg;
1564 /*@observer@*/
1565  const char * argv[4];
1569  int mask;
1570  int toggle;
1571 };
1572 
1575 /*@-nullassign@*/
1576 /*@unchecked@*/
1577 static struct DepMsg_s depMsgs[] = {
1578  { "Provides", { "%{?__find_provides}", NULL, NULL, NULL },
1580  0, -1 },
1581  { "Requires(interp)", { NULL, "interp", NULL, NULL },
1583  _notpre(RPMSENSE_INTERP), 0 },
1584  { "Requires(rpmlib)", { NULL, "rpmlib", NULL, NULL },
1585  (rpmTag)-1, (rpmTag)-1, RPMTAG_REQUIREFLAGS,
1586  _notpre(RPMSENSE_RPMLIB), 0 },
1587  { "Requires(verify)", { NULL, "verify", NULL, NULL },
1588  (rpmTag)-1, (rpmTag)-1, RPMTAG_REQUIREFLAGS,
1589  RPMSENSE_SCRIPT_VERIFY, 0 },
1590  { "Requires(pre)", { NULL, "pre", NULL, NULL },
1591  (rpmTag)-1, (rpmTag)-1, RPMTAG_REQUIREFLAGS,
1592  _notpre(RPMSENSE_SCRIPT_PRE), 0 },
1593  { "Requires(post)", { NULL, "post", NULL, NULL },
1594  (rpmTag)-1, (rpmTag)-1, RPMTAG_REQUIREFLAGS,
1595  _notpre(RPMSENSE_SCRIPT_POST), 0 },
1596  { "Requires(preun)", { NULL, "preun", NULL, NULL },
1597  (rpmTag)-1, (rpmTag)-1, RPMTAG_REQUIREFLAGS,
1598  _notpre(RPMSENSE_SCRIPT_PREUN), 0 },
1599  { "Requires(postun)", { NULL, "postun", NULL, NULL },
1600  (rpmTag)-1, (rpmTag)-1, RPMTAG_REQUIREFLAGS,
1601  _notpre(RPMSENSE_SCRIPT_POSTUN), 0 },
1602  { "Requires", { "%{?__find_requires}", NULL, NULL, NULL },
1603  (rpmTag)-1, (rpmTag)-1, RPMTAG_REQUIREFLAGS, /* XXX inherit name/version arrays */
1604  RPMSENSE_FIND_REQUIRES|RPMSENSE_TRIGGERIN|RPMSENSE_TRIGGERUN|RPMSENSE_TRIGGERPOSTUN|RPMSENSE_TRIGGERPREIN, 0 },
1605  { "Conflicts", { "%{?__find_conflicts}", NULL, NULL, NULL },
1607  0, -1 },
1608  { "Obsoletes", { "%{?__find_obsoletes}", NULL, NULL, NULL },
1610  0, -1 },
1611  { NULL, { NULL, NULL, NULL, NULL }, (rpmTag)0, (rpmTag)0, (rpmTag)0, 0, 0 }
1612 };
1613 /*@=nullassign@*/
1614 
1615 /*@unchecked@*/
1616 static DepMsg_t DepMsgs = depMsgs;
1617 
1622 static void printDeps(Header h)
1623  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1624  /*@modifies h, rpmGlobalMacroContext, fileSystem, internalState @*/
1625 {
1626  DepMsg_t dm;
1627  rpmds ds = NULL;
1628  int flags = 0x2; /* XXX no filtering, !scareMem */
1629  const char * DNEVR;
1630  evrFlags Flags;
1631  int bingo = 0;
1632 
1633  for (dm = DepMsgs; dm->msg != NULL; dm++) {
1634  if ((int)dm->ntag != -1) {
1635  (void)rpmdsFree(ds);
1636  ds = NULL;
1637  ds = rpmdsNew(h, dm->ntag, flags);
1638  }
1639  if (dm->ftag == 0)
1640  continue;
1641 
1642  ds = rpmdsInit(ds);
1643  if (ds == NULL)
1644  continue; /* XXX can't happen */
1645 
1646  bingo = 0;
1647  while (rpmdsNext(ds) >= 0) {
1648 
1649  Flags = rpmdsFlags(ds);
1650 
1651  if (!((Flags & dm->mask) ^ (dm->toggle)))
1652  /*@innercontinue@*/ continue;
1653  if (bingo == 0) {
1654  rpmlog(RPMLOG_NOTICE, "%s:", (dm->msg ? dm->msg : ""));
1655  bingo = 1;
1656  }
1657  if ((DNEVR = rpmdsDNEVR(ds)) == NULL)
1658  /*@innercontinue@*/ continue; /* XXX can't happen */
1659  rpmlog(RPMLOG_NOTICE, " %s", DNEVR+2);
1660  }
1661  if (bingo)
1662  rpmlog(RPMLOG_NOTICE, "\n");
1663  }
1664  (void)rpmdsFree(ds);
1665  ds = NULL;
1666 }
1667 
1671  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1672  /*@modifies fi, rpmGlobalMacroContext, fileSystem, internalState @*/
1673 {
1674  rpmiob iob_stdin;
1675  rpmiob iob_stdout;
1676  DepMsg_t dm;
1677  int failnonzero = 0;
1678  rpmRC rc = RPMRC_OK;
1679 
1680  /*
1681  * Create file manifest buffer to deliver to dependency finder.
1682  */
1683  iob_stdin = rpmiobNew(0);
1684  fi = rpmfiInit(fi, 0);
1685  if (fi != NULL)
1686  while (rpmfiNext(fi) >= 0)
1687  iob_stdin = rpmiobAppend(iob_stdin, rpmfiFN(fi), 1);
1688 
1689  for (dm = DepMsgs; dm->msg != NULL; dm++) {
1690  rpmTag tag;
1691  rpmsenseFlags tagflags;
1692  char * s;
1693  int xx;
1694 
1695  tag = (dm->ftag > 0) ? dm->ftag : dm->ntag;
1696  tagflags = (rpmsenseFlags) 0;
1697  s = NULL;
1698 
1699  switch(tag) {
1700  case RPMTAG_PROVIDEFLAGS:
1701  if (!pkg->autoProv)
1702  continue;
1703  failnonzero = 1;
1704  tagflags = RPMSENSE_FIND_PROVIDES;
1705  /*@switchbreak@*/ break;
1706  case RPMTAG_REQUIREFLAGS:
1707  if (!pkg->autoReq)
1708  continue;
1709  failnonzero = 0;
1710  tagflags = RPMSENSE_FIND_REQUIRES;
1711  /*@switchbreak@*/ break;
1712  default:
1713  continue;
1714  /*@notreached@*/ /*@switchbreak@*/ break;
1715  }
1716 
1717  xx = rpmfcExec(dm->argv, iob_stdin, &iob_stdout, failnonzero);
1718  if (xx == -1)
1719  continue;
1720 
1721  s = rpmExpand(dm->argv[0], NULL);
1722  rpmlog(RPMLOG_NOTICE, _("Finding %s: %s\n"), dm->msg,
1723  (s ? s : ""));
1724  s = _free(s);
1725 
1726  if (iob_stdout == NULL) {
1727  rpmlog(RPMLOG_ERR, _("Failed to find %s:\n"), dm->msg);
1728  rc = RPMRC_FAIL;
1729  break;
1730  }
1731 
1732  /* Parse dependencies into header */
1733  if (spec->_parseRCPOT)
1734  rc = spec->_parseRCPOT(spec, pkg, rpmiobStr(iob_stdout), tag,
1735  0, tagflags);
1736  iob_stdout = rpmiobFree(iob_stdout);
1737 
1738  if (rc) {
1739  rpmlog(RPMLOG_ERR, _("Failed to find %s:\n"), dm->msg);
1740  break;
1741  }
1742  }
1743 
1744  iob_stdin = rpmiobFree(iob_stdin);
1745 
1746  return rc;
1747 }
1748 
1751 /*@-nullassign@*/
1752 /*@unchecked@*/
1753 static struct DepMsg_s scriptMsgs[] = {
1754  { "Requires(pre)", { "%{?__scriptlet_requires}", NULL, NULL, NULL },
1756  RPMSENSE_SCRIPT_PRE, 0 },
1757  { "Requires(post)", { "%{?__scriptlet_requires}", NULL, NULL, NULL },
1759  RPMSENSE_SCRIPT_POST, 0 },
1760  { "Requires(preun)", { "%{?__scriptlet_requires}", NULL, NULL, NULL },
1762  RPMSENSE_SCRIPT_PREUN, 0 },
1763  { "Requires(postun)", { "%{?__scriptlet_requires}", NULL, NULL, NULL },
1765  RPMSENSE_SCRIPT_POSTUN, 0 },
1766  { NULL, { NULL, NULL, NULL, NULL }, (rpmTag)0, (rpmTag)0, (rpmTag)0, 0, 0 }
1767 };
1768 /*@=nullassign@*/
1769 
1770 /*@unchecked@*/
1771 static DepMsg_t ScriptMsgs = scriptMsgs;
1772 
1775 static int rpmfcGenerateScriptletDeps(const Spec spec, Package pkg)
1776  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1777  /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
1778 {
1779  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
1780  rpmiob iob_stdin = rpmiobNew(0);
1781  rpmiob iob_stdout = NULL;
1782  DepMsg_t dm;
1783  int failnonzero = 0;
1784  int rc = 0;
1785  int xx;
1786 
1787  for (dm = ScriptMsgs; dm->msg != NULL; dm++) {
1788  rpmTag tag;
1789  rpmsenseFlags tagflags;
1790  char * s;
1791 
1792  tag = dm->ftag;
1793  tagflags = (rpmsenseFlags) (RPMSENSE_FIND_REQUIRES | dm->mask);
1794 
1795  /* Retrieve scriptlet interpreter. */
1796  he->tag = dm->ntag;
1797  xx = headerGet(pkg->header, he, 0);
1798  if (!xx || he->p.str == NULL)
1799  continue;
1800  xx = strcmp(he->p.str, "/bin/sh") && strcmp(he->p.str, "/bin/bash");
1801  he->p.ptr = _free(he->p.ptr);
1802  if (xx)
1803  continue;
1804 
1805  /* Retrieve scriptlet body. */
1806  he->tag = dm->vtag;
1807  xx = headerGet(pkg->header, he, 0);
1808  if (!xx || he->p.str == NULL)
1809  continue;
1810  iob_stdin = rpmiobEmpty(iob_stdin);
1811  iob_stdin = rpmiobAppend(iob_stdin, he->p.str, 1);
1812  iob_stdin = rpmiobRTrim(iob_stdin);
1813  he->p.ptr = _free(he->p.ptr);
1814 
1815  xx = rpmfcExec(dm->argv, iob_stdin, &iob_stdout, failnonzero);
1816  if (xx == -1)
1817  continue;
1818 
1819  /* Parse dependencies into header */
1820  s = rpmiobStr(iob_stdout);
1821  if (s != NULL && *s != '\0') {
1822  char * se = s;
1823  /* XXX Convert "executable(/path/to/file)" to "/path/to/file". */
1824  while ((se = strstr(se, "executable(/")) != NULL) {
1825 /*@-modobserver@*/ /* FIX: rpmiobStr should not be observer */
1826  se = stpcpy(se, " ");
1827  *se = '/'; /* XXX stpcpy truncates the '/' */
1828 /*@=modobserver@*/
1829  se = strchr(se, ')');
1830  if (se == NULL)
1831  /*@innerbreak@*/ break;
1832  *se++ = ' ';
1833  }
1834  if (spec->_parseRCPOT)
1835  rc = spec->_parseRCPOT(spec, pkg, s, tag, 0, tagflags);
1836  }
1837  iob_stdout = rpmiobFree(iob_stdout);
1838 
1839  }
1840 
1841  iob_stdin = rpmiobFree(iob_stdin);
1842 
1843  return rc;
1844 }
1845 
1846 static unsigned removeSillyDeps(Header h, rpmfc fc) {
1847  HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
1848  int xx;
1849  unsigned i, rnum, removed = 0;
1850  const char **deps = NULL;
1851  const char **versions = NULL;
1852  evrFlags *flags = NULL;
1853  int *newpos = NULL, *ddictxPos = NULL;
1854 
1855  he->tag = RPMTAG_REQUIRENAME;
1856  xx = headerGet(h, he, 0);
1857  deps = he->p.argv;
1858  rnum = he->c;
1859 
1860  he->tag = RPMTAG_REQUIREVERSION;
1861  xx = headerGet(h, he, 0);
1862  versions = he->p.argv;
1863 
1864  he->tag = RPMTAG_REQUIREFLAGS;
1865  xx = headerGet(h, he, 0);
1866  flags = (evrFlags*)he->p.ui32p;
1867 
1868  if (fc && fc->requires != NULL && fc->ddictx != NULL) {
1869  newpos = alloca(he->c*sizeof(newpos[0]));
1870  if (fc->ddictx)
1871  ddictxPos = alloca(fc->ddictx->nvals*sizeof(ddictxPos[0]));
1872  }
1873  for (i = 0; i < rnum-removed; i++) {
1874  if (removed) {
1875  deps[i] = deps[i+removed];
1876  versions[i] = versions[i+removed];
1877  flags[i] = flags[i+removed];
1878  if (fc) {
1879  fc->requires->N[i] = fc->requires->N[i+removed];
1880  fc->requires->EVR[i] = fc->requires->EVR[i+removed];
1881  fc->requires->Flags[i] = fc->requires->Flags[i+removed];
1882  }
1883  }
1884  if (fc && fc->requires != NULL && fc->ddictx != NULL)
1885  newpos[i+removed] = i;
1886  rpmds req = rpmdsSingle(RPMTAG_REQUIRENAME, deps[i], versions[i], flags[i]);
1887  rpmds prov = rpmdsNew(h, (*deps[i] == '/' && !*versions[i]) ? RPMTAG_BASENAMES : RPMTAG_PROVIDENAME, 0);
1888  if (rpmdsMatch(req, prov)) {
1889  if (flags[i] & RPMSENSE_SCRIPT_PRE)
1890  rpmlog(RPMLOG_ERR, "Requires(pre): on dependency provided by self: %s\n", rpmdsDNEVR(req));
1891  else {
1892  if (fc && fc->requires != NULL && fc->ddictx != NULL)
1893  newpos[i+removed] = -1;
1894  rpmlog(RPMLOG_NOTICE, "Removing dependency on self: %s\n", rpmdsDNEVR(req));
1895  removed++;
1896  i--;
1897  }
1898  }
1899  req = rpmdsFree(req);
1900  prov = rpmdsFree(prov);
1901  }
1902  if (fc && fc->requires != NULL && fc->ddictx != NULL && removed) {
1903  fc->requires->Count -= removed;
1904  unsigned rx = 0;
1905  for (i = 0; i < fc->ddictx->nvals-rx; i++) {
1906  unsigned ix;
1907  unsigned char deptype;
1908 
1909  ix = fc->ddictx->vals[i+rx];
1910  deptype = ((ix >> 24) & 0xff);
1911  ix &= 0x00ffffff;
1912 
1913  if (deptype == 'P') {
1914  ddictxPos[i+rx] = i;
1915  fc->ddictx->vals[i] = fc->ddictx->vals[i+rx];
1916  continue;
1917  }
1918  if (newpos[ix] == -1) {
1919  ddictxPos[i+rx] = -1;
1920  i--, rx++;
1921  }
1922  else
1923  {
1924  ddictxPos[i+rx] = i;
1925  fc->ddictx->vals[i] = (deptype << 24) | (newpos[ix] & 0x00ffffff);
1926  }
1927  }
1928  fc->ddictx->nvals -= rx;
1929 
1930  for (i = 0; i < fc->fddictn->nvals; i++) {
1931  rx = 0;
1932  if (fc->fddictn->vals[i]) {
1933  unsigned j, ix = fc->fddictx->vals[i];
1934  for (j = 0, rx = 0; j < fc->fddictn->vals[i]; j++, ix++) {
1935  if (ddictxPos[ix] == -1)
1936  rx++;
1937  if (j == 0 || fc->fddictx->vals[i] == -1)
1938  fc->fddictx->vals[i] = ddictxPos[ix];
1939  }
1940  }
1941  if (rx)
1942  fc->fddictn->vals[i] -= rx;
1943  if (fc->fddictn->vals[i] == 0)
1944  fc->fddictx->vals[i] = 0;
1945  }
1946  }
1947 
1948  if (removed) {
1949  he->tag = RPMTAG_REQUIRENAME;
1950  he->t = RPM_STRING_ARRAY_TYPE;
1951  he->p.argv = deps;
1952  he->c -= removed;
1953  headerMod(h, he, 0);
1954 
1955  he->tag = RPMTAG_REQUIREVERSION;
1956  he->p.argv = versions;
1957  headerMod(h, he, 0);
1958 
1959  he->tag = RPMTAG_REQUIREFLAGS;
1960  he->t = RPM_UINT32_TYPE;
1961  he->p.ui32p = (uint32_t*)flags;
1962  headerMod(h, he, 0);
1963  }
1964 
1965  return removed;
1966 }
1967 
1968 rpmRC rpmfcGenerateDepends(void * _spec, void * _pkg)
1969 {
1970  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
1971  const Spec spec = (Spec) _spec;
1972  Package pkg = (Package) _pkg;
1973  rpmfi fi = pkg->fi;
1974  rpmfc fc = NULL;
1975  rpmds ds;
1976  int flags = 0x2; /* XXX no filtering, !scareMem */
1977  ARGV_t av;
1978  rpmuint16_t * fmode;
1979  int ac = rpmfiFC(fi);
1980  char buf[BUFSIZ];
1981  const char * N;
1982  const char * EVR;
1983  int genConfigDeps, internaldeps;
1984  rpmRC rc = RPMRC_OK;
1985  int i;
1986  int xx;
1987 
1988  /* Skip packages with no files. */
1989  if (ac <= 0)
1990  return RPMRC_OK;
1991 
1992  /* Skip packages that have dependency generation disabled. */
1993  if (! (pkg->autoReq || pkg->autoProv))
1994  return RPMRC_OK;
1995 
1996  /* If new-fangled dependency generation is disabled ... */
1997  internaldeps = rpmExpandNumeric("%{?_use_internal_dependency_generator}");
1998  if (internaldeps == 0) {
1999  /* ... then generate dependencies using %{__find_requires} et al. */
2000  rc = rpmfcGenerateDependsHelper(spec, pkg, fi);
2001  removeSillyDeps(pkg->header, NULL);
2002  printDeps(pkg->header);
2003  return rc;
2004  }
2005 
2006  /* Generate scriptlet Dependencies. */
2007  if (internaldeps > 1)
2008  xx = rpmfcGenerateScriptletDeps(spec, pkg);
2009 
2010  /* Extract absolute file paths in argv format. */
2011  /* XXX TODO: should use argvFoo ... */
2012  av = (ARGV_t) xcalloc(ac+1, sizeof(*av));
2013  fmode = (rpmuint16_t *) xcalloc(ac+1, sizeof(*fmode));
2014 
2015  genConfigDeps = 0;
2016  fi = rpmfiInit(fi, 0);
2017  if (fi != NULL)
2018  while ((i = rpmfiNext(fi)) >= 0) {
2019  rpmfileAttrs fileAttrs;
2020 
2021  /* Does package have any %config files? */
2022  fileAttrs = (rpmfileAttrs) rpmfiFFlags(fi);
2023  genConfigDeps |= (fileAttrs & RPMFILE_CONFIG);
2024 
2025  av[i] = xstrdup(rpmfiFN(fi));
2026  fmode[i] = rpmfiFMode(fi);
2027  }
2028  av[ac] = NULL;
2029 
2030  fc = rpmfcNew();
2031  fc->skipProv = !pkg->autoProv;
2032  fc->skipReq = !pkg->autoReq;
2033 
2034  { const char * buildRootURL;
2035  const char * buildRoot;
2036  buildRootURL = rpmGenPath(spec->rootURL, "%{?buildroot}", NULL);
2037  (void) urlPath(buildRootURL, &buildRoot);
2038  if (buildRoot && !strcmp(buildRoot, "/")) buildRoot = NULL;
2039  fc->brlen = (buildRoot ? strlen(buildRoot) : 0);
2040  buildRootURL = _free(buildRootURL);
2041  }
2042 
2043  /* Copy (and delete) manually generated dependencies to dictionary. */
2044  if (!fc->skipProv) {
2045  ds = rpmdsNew(pkg->header, RPMTAG_PROVIDENAME, flags);
2046  xx = rpmdsMerge(&fc->provides, ds);
2047  (void)rpmdsFree(ds);
2048  ds = NULL;
2049  he->tag = RPMTAG_PROVIDENAME;
2050  xx = headerDel(pkg->header, he, 0);
2051  he->tag = RPMTAG_PROVIDEVERSION;
2052  xx = headerDel(pkg->header, he, 0);
2053  he->tag = RPMTAG_PROVIDEFLAGS;
2054  xx = headerDel(pkg->header, he, 0);
2055 
2056  /* Add config dependency, Provides: config(N) = EVR */
2057  if (genConfigDeps) {
2058  static evrFlags _Flags = (evrFlags)(RPMSENSE_EQUAL|RPMSENSE_CONFIG);
2059  N = rpmdsN(pkg->ds);
2060 assert(N != NULL);
2061  EVR = rpmdsEVR(pkg->ds);
2062 assert(EVR != NULL);
2063  sprintf(buf, "config(%s)", N);
2064  ds = rpmdsSingle(RPMTAG_PROVIDENAME, buf, EVR, _Flags);
2065  xx = rpmdsMerge(&fc->provides, ds);
2066  (void)rpmdsFree(ds);
2067  ds = NULL;
2068  }
2069  }
2070 
2071  if (!fc->skipReq) {
2072  ds = rpmdsNew(pkg->header, RPMTAG_REQUIRENAME, flags);
2073  xx = rpmdsMerge(&fc->requires, ds);
2074  (void)rpmdsFree(ds);
2075  ds = NULL;
2076  he->tag = RPMTAG_REQUIRENAME;
2077  xx = headerDel(pkg->header, he, 0);
2078  he->tag = RPMTAG_REQUIREVERSION;
2079  xx = headerDel(pkg->header, he, 0);
2080  he->tag = RPMTAG_REQUIREFLAGS;
2081  xx = headerDel(pkg->header, he, 0);
2082 
2083  /* Add config dependency, Requires: config(N) = EVR */
2084  if (genConfigDeps) {
2085  static evrFlags _Flags = (evrFlags)(RPMSENSE_EQUAL|RPMSENSE_CONFIG);
2086  N = rpmdsN(pkg->ds);
2087 assert(N != NULL);
2088  EVR = rpmdsEVR(pkg->ds);
2089 assert(EVR != NULL);
2090  sprintf(buf, "config(%s)", N);
2091  ds = rpmdsSingle(RPMTAG_REQUIRENAME, buf, EVR, _Flags);
2092  xx = rpmdsMerge(&fc->requires, ds);
2093  (void)rpmdsFree(ds);
2094  ds = NULL;
2095  }
2096  }
2097 
2098  /* Build file class dictionary. */
2099  xx = rpmfcClassify(fc, av, fmode);
2100 
2101  /* Build file/package dependency dictionary. */
2102  xx = rpmfcApply(fc);
2103 
2104  /* Add per-file colors(#files) */
2105  he->tag = RPMTAG_FILECOLORS;
2106  he->t = RPM_UINT32_TYPE;
2107  he->p.ui32p = argiData(fc->fcolor);
2108  he->c = argiCount(fc->fcolor);
2109 assert(ac == (int)he->c);
2110  if (he->p.ptr != NULL && he->c > 0) {
2111  rpmuint32_t * fcolors = he->p.ui32p;
2112 
2113  /* XXX Make sure only primary (i.e. Elf32/Elf64) colors are added. */
2114  for (i = 0; i < (int)he->c; i++)
2115  fcolors[i] &= 0x0f;
2116 
2117  xx = headerPut(pkg->header, he, 0);
2118  }
2119 
2120  /* Add classes(#classes) */
2121  he->tag = RPMTAG_CLASSDICT;
2122  he->t = RPM_STRING_ARRAY_TYPE;
2123  he->p.argv = argvData(fc->cdict);
2124  he->c = argvCount(fc->cdict);
2125  if (he->p.ptr != NULL && he->c > 0) {
2126  xx = headerPut(pkg->header, he, 0);
2127  }
2128 
2129  /* Add per-file classes(#files) */
2130  he->tag = RPMTAG_FILECLASS;
2131  he->t = RPM_UINT32_TYPE;
2132  he->p.ui32p = argiData(fc->fcdictx);
2133  he->c = argiCount(fc->fcdictx);
2134 assert(ac == (int)he->c);
2135  if (he->p.ptr != NULL && he->c > 0) {
2136  xx = headerPut(pkg->header, he, 0);
2137  }
2138 
2139  /* Add Provides: */
2140  if (fc->provides != NULL && (he->c = rpmdsCount(fc->provides)) > 0
2141  && !fc->skipProv)
2142  {
2143  he->tag = RPMTAG_PROVIDENAME;
2144  he->t = RPM_STRING_ARRAY_TYPE;
2145  he->p.argv = fc->provides->N;
2146  xx = headerPut(pkg->header, he, 0);
2147 
2148  /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
2149 /*@-nullpass@*/
2150  he->tag = RPMTAG_PROVIDEVERSION;
2151  he->t = RPM_STRING_ARRAY_TYPE;
2152  he->p.argv = fc->provides->EVR;
2153 assert(he->p.ptr != NULL);
2154  xx = headerPut(pkg->header, he, 0);
2155 
2156  he->tag = RPMTAG_PROVIDEFLAGS;
2157  he->t = RPM_UINT32_TYPE;
2158  he->p.ui32p = (rpmuint32_t *) fc->provides->Flags;
2159 assert(he->p.ptr != NULL);
2160  xx = headerPut(pkg->header, he, 0);
2161 /*@=nullpass@*/
2162  }
2163 
2164  /* Add Requires: */
2165  if (fc->requires != NULL && (he->c = rpmdsCount(fc->requires)) > 0
2166  && !fc->skipReq)
2167  {
2168  he->tag = RPMTAG_REQUIRENAME;
2169  he->t = RPM_STRING_ARRAY_TYPE;
2170  he->p.argv = fc->requires->N;
2171 assert(he->p.ptr != NULL);
2172  xx = headerPut(pkg->header, he, 0);
2173 
2174  /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
2175 /*@-nullpass@*/
2176  he->tag = RPMTAG_REQUIREVERSION;
2177  he->t = RPM_STRING_ARRAY_TYPE;
2178  he->p.argv = fc->requires->EVR;
2179 assert(he->p.ptr != NULL);
2180  xx = headerPut(pkg->header, he, 0);
2181 
2182  he->tag = RPMTAG_REQUIREFLAGS;
2183  he->t = RPM_UINT32_TYPE;
2184  he->p.ui32p = (rpmuint32_t *) fc->requires->Flags;
2185 assert(he->p.ptr != NULL);
2186  xx = headerPut(pkg->header, he, 0);
2187 /*@=nullpass@*/
2188  }
2189 
2190  removeSillyDeps(pkg->header, fc);
2191 
2192  /* Add dependency dictionary(#dependencies) */
2193  he->tag = RPMTAG_DEPENDSDICT;
2194  he->t = RPM_UINT32_TYPE;
2195  he->p.ui32p = argiData(fc->ddictx);
2196  he->c = argiCount(fc->ddictx);
2197  if (he->p.ptr != NULL) {
2198  xx = headerPut(pkg->header, he, 0);
2199  }
2200 
2201  /* Add per-file dependency (start,number) pairs (#files) */
2202  he->tag = RPMTAG_FILEDEPENDSX;
2203  he->t = RPM_UINT32_TYPE;
2204  he->p.ui32p = argiData(fc->fddictx);
2205  he->c = argiCount(fc->fddictx);
2206 assert(ac == (int)he->c);
2207  if (he->p.ptr != NULL) {
2208  xx = headerPut(pkg->header, he, 0);
2209  }
2210 
2211  he->tag = RPMTAG_FILEDEPENDSN;
2212  he->t = RPM_UINT32_TYPE;
2213  he->p.ui32p = argiData(fc->fddictn);
2214  he->c = argiCount(fc->fddictn);
2215 assert(ac == (int)he->c);
2216  if (he->p.ptr != NULL) {
2217  xx = headerPut(pkg->header, he, 0);
2218  }
2219 
2220  printDeps(pkg->header);
2221 
2222 if (fc != NULL && _rpmfc_debug) {
2223 char msg[BUFSIZ];
2224 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));
2225 rpmfcPrint(msg, fc, NULL);
2226 }
2227 
2228  /* Clean up. */
2229  fmode = _free(fmode);
2230  fc = rpmfcFree(fc);
2231  av = argvFree(av);
2232 
2233  return rc;
2234 }
2235 
2236 /*@-mustmod@*/
2237 static void rpmfcFini(void * _fc)
2238  /*@modifies _fc @*/
2239 {
2240  rpmfc fc = (rpmfc) _fc;
2241 
2242  fc->fn = argvFree(fc->fn);
2243  fc->fcolor = argiFree(fc->fcolor);
2244  fc->fcdictx = argiFree(fc->fcdictx);
2245  fc->fddictx = argiFree(fc->fddictx);
2246  fc->fddictn = argiFree(fc->fddictn);
2247  fc->cdict = argvFree(fc->cdict);
2248  fc->ddict = argvFree(fc->ddict);
2249  fc->ddictx = argiFree(fc->ddictx);
2250 
2251  (void)rpmdsFree(fc->provides);
2252  fc->provides = NULL;
2253  (void)rpmdsFree(fc->requires);
2254  fc->requires = NULL;
2255 
2256  fc->iob_java = rpmiobFree(fc->iob_java);
2257  fc->iob_perl = rpmiobFree(fc->iob_perl);
2258  fc->iob_python = rpmiobFree(fc->iob_python);
2259  fc->iob_php = rpmiobFree(fc->iob_php);
2260 }
2261 /*@=mustmod@*/
2262 
2263 /*@unchecked@*/ /*@only@*/ /*@null@*/
2265 
2266 static rpmfc rpmfcGetPool(/*@null@*/ rpmioPool pool)
2267  /*@globals _rpmfcPool, fileSystem, internalState @*/
2268  /*@modifies pool, _rpmfcPool, fileSystem, internalState @*/
2269 {
2270  rpmfc fc;
2271 
2272  if (_rpmfcPool == NULL) {
2273  _rpmfcPool = rpmioNewPool("fc", sizeof(*fc), -1, _rpmfc_debug,
2274  NULL, NULL, rpmfcFini);
2275  pool = _rpmfcPool;
2276  }
2277  fc = (rpmfc) rpmioGetPool(pool, sizeof(*fc));
2278  memset(((char *)fc)+sizeof(fc->_item), 0, sizeof(*fc)-sizeof(fc->_item));
2279  return fc;
2280 }
2281 
2283 {
2284  rpmfc fc = rpmfcGetPool(_rpmfcPool);
2285  fc->fn = (ARGV_t) xcalloc(1, sizeof(*fc->fn));
2286  return rpmfcLink(fc);
2287 }
2288