rpm 5.2.1

lib/rpmfc.c

Go to the documentation of this file.
00001 #include "system.h"
00002 
00003 #include <signal.h>     /* getOutputFrom() */
00004 
00005 #include <rpmio.h>
00006 #include <rpmiotypes.h>         /* XXX fnpyKey */
00007 #include <rpmlog.h>
00008 #include <rpmurl.h>
00009 #include <rpmmg.h>
00010 #include <argv.h>
00011 #define _MIRE_INTERNAL
00012 #include <mire.h>
00013 
00014 #include <rpmtag.h>
00015 #define _RPMEVR_INTERNAL
00016 #include <rpmbuild.h>
00017 
00018 #define _RPMNS_INTERNAL
00019 #include <rpmns.h>
00020 
00021 #define _RPMFC_INTERNAL
00022 #include <rpmfc.h>
00023 
00024 #define _RPMDS_INTERNAL
00025 #include <rpmds.h>
00026 #include <rpmfi.h>
00027 
00028 #include "debug.h"
00029 
00030 /*@access rpmds @*/
00031 /*@access miRE @*/
00032 
00033 /*@unchecked@*/
00034 static int _filter_values = 1;
00035 /*@unchecked@*/
00036 static int _filter_execs = 1;
00037 
00040 static int rpmfcExpandAppend(/*@out@*/ ARGV_t * argvp, const ARGV_t av)
00041         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
00042         /*@modifies *argvp, rpmGlobalMacroContext, internalState @*/
00043         /*@requires maxRead(argvp) >= 0 @*/
00044 {
00045     ARGV_t argv = *argvp;
00046     int argc = argvCount(argv);
00047     int ac = argvCount(av);
00048     int i;
00049 
00050     argv = xrealloc(argv, (argc + ac + 1) * sizeof(*argv));
00051     for (i = 0; i < ac; i++)
00052         argv[argc + i] = rpmExpand(av[i], NULL);
00053     argv[argc + ac] = NULL;
00054     *argvp = argv;
00055     return 0;
00056 }
00057 
00068 /*@null@*/
00069 static rpmiob getOutputFrom(/*@null@*/ const char * dir, ARGV_t argv,
00070                         const char * writePtr, size_t writeBytesLeft,
00071                         int failNonZero)
00072         /*@globals h_errno, fileSystem, internalState@*/
00073         /*@modifies fileSystem, internalState@*/
00074 {
00075     pid_t child, reaped;
00076     int toProg[2];
00077     int fromProg[2];
00078     int status;
00079     void *oldhandler;
00080     rpmiob iob = NULL;
00081     int done;
00082 
00083     /*@-type@*/ /* FIX: cast? */
00084     oldhandler = signal(SIGPIPE, SIG_IGN);
00085     /*@=type@*/
00086 
00087     toProg[0] = toProg[1] = 0;
00088     fromProg[0] = fromProg[1] = 0;
00089     if (pipe(toProg) < 0 || pipe(fromProg) < 0) {
00090         rpmlog(RPMLOG_ERR, _("Couldn't create pipe for %s: %m\n"), argv[0]);
00091         return NULL;
00092     }
00093     
00094     if (!(child = fork())) {
00095         (void) close(toProg[1]);
00096         (void) close(fromProg[0]);
00097         
00098         (void) dup2(toProg[0], STDIN_FILENO);   /* Make stdin the in pipe */
00099         (void) dup2(fromProg[1], STDOUT_FILENO); /* Make stdout the out pipe */
00100 
00101         (void) close(toProg[0]);
00102         (void) close(fromProg[1]);
00103 
00104         if (dir) {
00105             (void) Chdir(dir);
00106         }
00107         
00108         rpmlog(RPMLOG_DEBUG, D_("\texecv(%s) pid %d\n"),
00109                         argv[0], (unsigned)getpid());
00110 
00111         unsetenv("MALLOC_CHECK_");
00112         (void) execvp(argv[0], (char *const *)argv);
00113         /* XXX this error message is probably not seen. */
00114         rpmlog(RPMLOG_ERR, _("Couldn't exec %s: %s\n"),
00115                 argv[0], strerror(errno));
00116         _exit(EXIT_FAILURE);
00117     }
00118     if (child < 0) {
00119         rpmlog(RPMLOG_ERR, _("Couldn't fork %s: %s\n"),
00120                 argv[0], strerror(errno));
00121         return NULL;
00122     }
00123 
00124     (void) close(toProg[0]);
00125     (void) close(fromProg[1]);
00126 
00127     /* Do not block reading or writing from/to prog. */
00128     (void) fcntl(fromProg[0], F_SETFL, O_NONBLOCK);
00129     (void) fcntl(toProg[1], F_SETFL, O_NONBLOCK);
00130     
00131     iob = rpmiobNew(0);
00132 
00133     do {
00134         fd_set ibits, obits;
00135         struct timeval tv;
00136         int nfd;
00137         ssize_t nbr;
00138         ssize_t nbw;
00139         int rc;
00140 
00141         done = 0;
00142 top:
00143         FD_ZERO(&ibits);
00144         FD_ZERO(&obits);
00145         if (fromProg[0] >= 0) {
00146             FD_SET(fromProg[0], &ibits);
00147         }
00148         if (toProg[1] >= 0) {
00149             FD_SET(toProg[1], &obits);
00150         }
00151         /* XXX values set to limit spinning with perl doing ~100 forks/sec. */
00152         tv.tv_sec = 0;
00153         tv.tv_usec = 10000;
00154         nfd = ((fromProg[0] > toProg[1]) ? fromProg[0] : toProg[1]);
00155         if ((rc = select(nfd, &ibits, &obits, NULL, &tv)) < 0) {
00156             if (errno == EINTR)
00157                 goto top;
00158             break;
00159         }
00160 
00161         /* Write any data to program */
00162         if (toProg[1] >= 0 && FD_ISSET(toProg[1], &obits)) {
00163           if (writePtr && writeBytesLeft > 0) {
00164             if ((nbw = write(toProg[1], writePtr,
00165                     ((size_t)1024<writeBytesLeft) ? (size_t)1024 : writeBytesLeft)) < 0)
00166             {
00167                 if (errno != EAGAIN) {
00168                     perror("getOutputFrom()");
00169                     exit(EXIT_FAILURE);
00170                 }
00171                 nbw = 0;
00172             }
00173             writeBytesLeft -= nbw;
00174             writePtr += nbw;
00175           } else if (toProg[1] >= 0) {  /* close write fd */
00176             (void) close(toProg[1]);
00177             toProg[1] = -1;
00178           }
00179         }
00180         
00181         /* Read any data from prog */
00182         {   char buf[BUFSIZ+1];
00183             while ((nbr = read(fromProg[0], buf, sizeof(buf)-1)) > 0) {
00184                 buf[nbr] = '\0';
00185                 iob = rpmiobAppend(iob, buf, 0);
00186             }
00187         }
00188 
00189         /* terminate on (non-blocking) EOF or error */
00190         done = (nbr == 0 || (nbr < 0 && errno != EAGAIN));
00191 
00192     } while (!done);
00193 
00194     /* Clean up */
00195     if (toProg[1] >= 0)
00196         (void) close(toProg[1]);
00197     if (fromProg[0] >= 0)
00198         (void) close(fromProg[0]);
00199 /*@-type@*/ /* FIX: cast? */
00200     (void) signal(SIGPIPE, oldhandler);
00201 /*@=type@*/
00202 
00203     /* Collect status from prog */
00204     reaped = waitpid(child, &status, 0);
00205     rpmlog(RPMLOG_DEBUG, D_("\twaitpid(%d) rc %d status %x\n"),
00206         (unsigned)child, (unsigned)reaped, status);
00207 
00208     if (failNonZero && (!WIFEXITED(status) || WEXITSTATUS(status))) {
00209         const char *cmd = argvJoin(argv);
00210         int rc = (WIFEXITED(status) ? WEXITSTATUS(status) : -1);
00211 
00212         rpmlog(RPMLOG_ERR, _("Command \"%s\" failed, exit(%d)\n"), cmd, rc);
00213         cmd = _free(cmd);
00214         iob = rpmiobFree(iob);
00215         return NULL;
00216     }
00217     if (writeBytesLeft) {
00218         rpmlog(RPMLOG_ERR, _("failed to write all data to %s\n"), argv[0]);
00219         iob = rpmiobFree(iob);
00220         return NULL;
00221     }
00222     return iob;
00223 }
00224 
00225 int rpmfcExec(ARGV_t av, rpmiob iob_stdin, rpmiob * iob_stdoutp,
00226                 int failnonzero)
00227 {
00228     const char * s = NULL;
00229     ARGV_t xav = NULL;
00230     ARGV_t pav = NULL;
00231     int pac = 0;
00232     int ec = -1;
00233     rpmiob iob = NULL;
00234     const char * buf_stdin = NULL;
00235     size_t buf_stdin_len = 0;
00236     int xx;
00237 
00238     if (iob_stdoutp)
00239         *iob_stdoutp = NULL;
00240     if (!(av && *av))
00241         goto exit;
00242 
00243     /* Find path to executable with (possible) args. */
00244     s = rpmExpand(av[0], NULL);
00245     if (!(s && *s))
00246         goto exit;
00247 
00248     /* Parse args buried within expanded executable. */
00249     pac = 0;
00250     xx = poptParseArgvString(s, &pac, (const char ***)&pav);
00251     if (!(xx == 0 && pac > 0 && pav != NULL))
00252         goto exit;
00253 
00254     /* Build argv, appending args to the executable args. */
00255     xav = NULL;
00256     xx = argvAppend(&xav, pav);
00257     if (av[1])
00258         xx = rpmfcExpandAppend(&xav, av + 1);
00259 
00260     if (iob_stdin != NULL) {
00261         buf_stdin = rpmiobStr(iob_stdin);
00262         buf_stdin_len = rpmiobLen(iob_stdin);
00263     }
00264 
00265     /* Read output from exec'd helper. */
00266     iob = getOutputFrom(NULL, xav, buf_stdin, buf_stdin_len, failnonzero);
00267 
00268     if (iob_stdoutp != NULL) {
00269         *iob_stdoutp = iob;
00270         iob = NULL;     /* XXX don't free */
00271     }
00272 
00273     ec = 0;
00274 
00275 exit:
00276     iob = rpmiobFree(iob);
00277     xav = argvFree(xav);
00278     pav = _free(pav);   /* XXX popt mallocs in single blob. */
00279     s = _free(s);
00280     return ec;
00281 }
00282 
00285 static int rpmfcSaveArg(/*@out@*/ ARGV_t * argvp, const char * key)
00286         /*@modifies *argvp @*/
00287         /*@requires maxSet(argvp) >= 0 @*/
00288 {
00289     int rc = 0;
00290 
00291     if (argvSearch(*argvp, key, NULL) == NULL) {
00292         rc = argvAdd(argvp, key);
00293         rc = argvSort(*argvp, NULL);
00294     }
00295     return rc;
00296 }
00297 
00300 static char * rpmfcFileDep(/*@returned@*/ char * buf, size_t ix,
00301                 /*@null@*/ rpmds ds)
00302         /*@globals internalState @*/
00303         /*@modifies buf, internalState @*/
00304         /*@requires maxSet(buf) >= 0 @*/
00305 {
00306     rpmTag tagN = rpmdsTagN(ds);
00307     char deptype = 'X';
00308 
00309     buf[0] = '\0';
00310     switch (tagN) {
00311     default:
00312 assert(0);
00313         /*@notreached@*/ break;
00314     case RPMTAG_PROVIDENAME:
00315         deptype = 'P';
00316         break;
00317     case RPMTAG_REQUIRENAME:
00318         deptype = 'R';
00319         break;
00320     }
00321 /*@-nullpass@*/
00322     if (ds != NULL)
00323         sprintf(buf, "%08u%c %s %s 0x%08x", (unsigned)ix, deptype,
00324                 rpmdsN(ds), rpmdsEVR(ds), rpmdsFlags(ds));
00325 /*@=nullpass@*/
00326     return buf;
00327 };
00328 
00329 /*@null@*/
00330 static void * rpmfcExpandRegexps(const char * str, int * nmirep)
00331         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
00332         /*@modifies *nmirep, rpmGlobalMacroContext, internalState @*/
00333 {
00334     ARGV_t av = NULL;
00335     int ac = 0;
00336     miRE mire = NULL;
00337     int nmire = 0;
00338     const char * s;
00339     int xx;
00340     int i;
00341 
00342     s = rpmExpand(str, NULL);
00343     if (s) {
00344         xx = poptParseArgvString(s, &ac, (const char ***)&av);
00345         s = _free(s);
00346     }
00347     if (ac == 0 || av == NULL || *av == NULL)
00348         goto exit;
00349 
00350     for (i = 0; i < ac; i++) {
00351         xx = mireAppend(RPMMIRE_REGEX, 0, av[i], NULL, &mire, &nmire);
00352         /* XXX add REG_NOSUB? better error msg?  */
00353         if (xx) {
00354             rpmlog(RPMLOG_NOTICE, 
00355                         _("Compilation of pattern '%s'"
00356                         " (expanded from '%s') failed. Skipping ...\n"),
00357                         av[i], str);
00358             nmire--;    /* XXX does this actually skip?!? */
00359         }
00360     }
00361     if (nmire == 0)
00362         mire = mireFree(mire);
00363 
00364 exit:
00365     av = _free(av);
00366     if (nmirep)
00367         *nmirep = nmire;
00368     return mire;
00369 }
00370 
00371 static int rpmfcMatchRegexps(void * mires, int nmire,
00372                 const char * str, char deptype)
00373         /*@modifies mires @*/
00374 {
00375     miRE mire = mires;
00376     int xx;
00377     int i;
00378 
00379     for (i = 0; i < nmire; i++) {
00380         rpmlog(RPMLOG_DEBUG, D_("Checking %c: '%s'\n"), deptype, str);
00381         if ((xx = mireRegexec(mire + i, str, 0)) < 0)
00382             continue;
00383         rpmlog(RPMLOG_NOTICE, _("Skipping %c: '%s'\n"), deptype, str);
00384         return 1;
00385     }
00386     return 0;
00387 }
00388 
00389 /*@null@*/
00390 static void * rpmfcFreeRegexps(/*@only@*/ void * mires, int nmire)
00391         /*@modifies mires @*/
00392 {
00393     miRE mire = mires;
00394 /*@-refcounttrans@*/
00395     return mireFreeAll(mire, nmire);
00396 /*@=refcounttrans@*/
00397 }
00398 
00406 static int rpmfcHelper(rpmfc fc, unsigned char deptype, const char * nsdep)
00407         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00408         /*@modifies fc, rpmGlobalMacroContext, fileSystem, internalState @*/
00409 {
00410     miRE mire = NULL;
00411     int nmire = 0;
00412     const char * fn = fc->fn[fc->ix];
00413     char buf[BUFSIZ];
00414     rpmiob iob_stdout = NULL;
00415     rpmiob iob_stdin;
00416     const char *av[2];
00417     rpmds * depsp, ds;
00418     const char * N;
00419     const char * EVR;
00420     rpmTag tagN;
00421     evrFlags Flags;
00422     evrFlags dsContext;
00423     ARGV_t pav;
00424     const char * s;
00425     int pac;
00426     int xx;
00427     int i;
00428 
00429     switch (deptype) {
00430     default:
00431         return -1;
00432         /*@notreached@*/ break;
00433     case 'P':
00434         if (fc->skipProv)
00435             return 0;
00436         xx = snprintf(buf, sizeof(buf), "%%{?__%s_provides}", nsdep);
00437         depsp = &fc->provides;
00438         dsContext = RPMSENSE_FIND_PROVIDES;
00439         tagN = RPMTAG_PROVIDENAME;
00440         mire = fc->Pmires;
00441         nmire = fc->Pnmire;
00442         break;
00443     case 'R':
00444         if (fc->skipReq)
00445             return 0;
00446         xx = snprintf(buf, sizeof(buf), "%%{?__%s_requires}", nsdep);
00447         depsp = &fc->requires;
00448         dsContext = RPMSENSE_FIND_REQUIRES;
00449         tagN = RPMTAG_REQUIRENAME;
00450         mire = fc->Rmires;
00451         nmire = fc->Rnmire;
00452         break;
00453     }
00454     buf[sizeof(buf)-1] = '\0';
00455     av[0] = buf;
00456     av[1] = NULL;
00457 
00458     iob_stdin = rpmiobNew(0);
00459     iob_stdin = rpmiobAppend(iob_stdin, fn, 1);
00460     iob_stdout = NULL;
00461     xx = rpmfcExec(av, iob_stdin, &iob_stdout, 0);
00462     iob_stdin = rpmiobFree(iob_stdin);
00463 
00464     if (xx == 0 && iob_stdout != NULL) {
00465         pav = NULL;
00466         xx = argvSplit(&pav, rpmiobStr(iob_stdout), " \t\n\r");
00467         pac = argvCount(pav);
00468         if (pav)
00469         for (i = 0; i < pac; i++) {
00470             N = pav[i];
00471             EVR = "";
00472             Flags = dsContext;
00473             if (pav[i+1] && strchr("=<>", *pav[i+1])) {
00474                 i++;
00475                 for (s = pav[i]; *s; s++) {
00476                     switch(*s) {
00477                     default:
00478 assert(*s != '\0');
00479                         /*@switchbreak@*/ break;
00480                     case '=':
00481                         Flags |= RPMSENSE_EQUAL;
00482                         /*@switchbreak@*/ break;
00483                     case '<':
00484                         Flags |= RPMSENSE_LESS;
00485                         /*@switchbreak@*/ break;
00486                     case '>':
00487                         Flags |= RPMSENSE_GREATER;
00488                         /*@switchbreak@*/ break;
00489                     }
00490                 }
00491                 i++;
00492                 EVR = pav[i];
00493 assert(EVR != NULL);
00494             }
00495 
00496             if (_filter_values && rpmfcMatchRegexps(mire, nmire, N, deptype))
00497                 continue;
00498 
00499             /* Add tracking dependency for versioned Provides: */
00500             if (!fc->tracked && deptype == 'P' && *EVR != '\0') {
00501                 ds = rpmdsSingle(RPMTAG_REQUIRENAME,
00502                         "rpmlib(VersionedDependencies)", "3.0.3-1",
00503                         RPMSENSE_RPMLIB|(RPMSENSE_LESS|RPMSENSE_EQUAL));
00504                 xx = rpmdsMerge(&fc->requires, ds);
00505                 (void)rpmdsFree(ds);
00506                 ds = NULL;
00507                 fc->tracked = 1;
00508             }
00509 
00510             ds = rpmdsSingle(tagN, N, EVR, Flags);
00511 
00512             /* Add to package dependencies. */
00513             xx = rpmdsMerge(depsp, ds);
00514 
00515             /* Add to file dependencies. */
00516             xx = rpmfcSaveArg(&fc->ddict, rpmfcFileDep(buf, fc->ix, ds));
00517 
00518             (void)rpmdsFree(ds);
00519             ds = NULL;
00520         }
00521 
00522         pav = argvFree(pav);
00523     }
00524     iob_stdout = rpmiobFree(iob_stdout);
00525 
00526     return 0;
00527 }
00528 
00531 /*@-nullassign@*/
00532 /*@unchecked@*/ /*@observer@*/
00533 static struct rpmfcTokens_s rpmfcTokens[] = {
00534   { "directory",                RPMFC_DIRECTORY|RPMFC_INCLUDE },
00535 
00536   { " shared object",           RPMFC_LIBRARY },
00537   { " executable",              RPMFC_EXECUTABLE },
00538   { " statically linked",       RPMFC_STATIC },
00539   { " not stripped",            RPMFC_NOTSTRIPPED },
00540   { " archive",                 RPMFC_ARCHIVE },
00541 
00542   { "MIPS, N32 MIPS32",         RPMFC_ELFMIPSN32|RPMFC_INCLUDE },
00543   { "ELF 32-bit",               RPMFC_ELF32|RPMFC_INCLUDE },
00544   { "ELF 64-bit",               RPMFC_ELF64|RPMFC_INCLUDE },
00545 
00546   { " script",                  RPMFC_SCRIPT },
00547   { " text",                    RPMFC_TEXT },
00548   { " document",                RPMFC_DOCUMENT },
00549 
00550   { " compressed",              RPMFC_COMPRESSED },
00551 
00552   { "troff or preprocessor input",      RPMFC_MANPAGE|RPMFC_INCLUDE },
00553   { "GNU Info",                 RPMFC_MANPAGE|RPMFC_INCLUDE },
00554 
00555   { "perl script text",         RPMFC_PERL|RPMFC_INCLUDE },
00556   { "Perl5 module source text", RPMFC_PERL|RPMFC_MODULE|RPMFC_INCLUDE },
00557 
00558   { "PHP script text",          RPMFC_PHP|RPMFC_INCLUDE },
00559 
00560   /* XXX "a /usr/bin/python -t script text executable" */
00561   /* XXX "python 2.3 byte-compiled" */
00562   { " /usr/bin/python",         RPMFC_PYTHON|RPMFC_INCLUDE },
00563   { "python ",                  RPMFC_PYTHON|RPMFC_INCLUDE },
00564 
00565   { "libtool library ",         RPMFC_LIBTOOL|RPMFC_INCLUDE },
00566   { "pkgconfig ",               RPMFC_PKGCONFIG|RPMFC_INCLUDE },
00567 
00568   { "Bourne ",                  RPMFC_BOURNE|RPMFC_INCLUDE },
00569   { "Bourne-Again ",            RPMFC_BOURNE|RPMFC_INCLUDE },
00570 
00571   { "Java ",                    RPMFC_JAVA|RPMFC_INCLUDE },
00572 
00573   { "Mono/.Net assembly",       RPMFC_MONO|RPMFC_INCLUDE },
00574 
00575   { "current ar archive",       RPMFC_STATIC|RPMFC_LIBRARY|RPMFC_ARCHIVE|RPMFC_INCLUDE },
00576 
00577   { "Zip archive data",         RPMFC_COMPRESSED|RPMFC_ARCHIVE|RPMFC_INCLUDE },
00578   { "tar archive",              RPMFC_ARCHIVE|RPMFC_INCLUDE },
00579   { "cpio archive",             RPMFC_ARCHIVE|RPMFC_INCLUDE },
00580   { "RPM v3",                   RPMFC_ARCHIVE|RPMFC_INCLUDE },
00581   { "RPM v4",                   RPMFC_ARCHIVE|RPMFC_INCLUDE },
00582 
00583   { " image",                   RPMFC_IMAGE|RPMFC_INCLUDE },
00584   { " font",                    RPMFC_FONT|RPMFC_INCLUDE },
00585   { " Font",                    RPMFC_FONT|RPMFC_INCLUDE },
00586 
00587   { " commands",                RPMFC_SCRIPT|RPMFC_INCLUDE },
00588   { " script",                  RPMFC_SCRIPT|RPMFC_INCLUDE },
00589 
00590   { "empty",                    RPMFC_WHITE|RPMFC_INCLUDE },
00591 
00592   { "HTML",                     RPMFC_WHITE|RPMFC_INCLUDE },
00593   { "SGML",                     RPMFC_WHITE|RPMFC_INCLUDE },
00594   { "XML",                      RPMFC_WHITE|RPMFC_INCLUDE },
00595 
00596   { " program text",            RPMFC_WHITE|RPMFC_INCLUDE },
00597   { " source",                  RPMFC_WHITE|RPMFC_INCLUDE },
00598   { "GLS_BINARY_LSB_FIRST",     RPMFC_WHITE|RPMFC_INCLUDE },
00599   { " DB ",                     RPMFC_WHITE|RPMFC_INCLUDE },
00600 
00601   { "ASCII English text",       RPMFC_WHITE|RPMFC_INCLUDE },
00602   { "ASCII text",               RPMFC_WHITE|RPMFC_INCLUDE },
00603   { "ISO-8859 text",            RPMFC_WHITE|RPMFC_INCLUDE },
00604 
00605   { "symbolic link to",         RPMFC_SYMLINK },
00606   { "socket",                   RPMFC_DEVICE },
00607   { "special",                  RPMFC_DEVICE },
00608 
00609   { "ASCII",                    RPMFC_WHITE },
00610   { "ISO-8859",                 RPMFC_WHITE },
00611 
00612   { "data",                     RPMFC_WHITE },
00613 
00614   { "application",              RPMFC_WHITE },
00615   { "boot",                     RPMFC_WHITE },
00616   { "catalog",                  RPMFC_WHITE },
00617   { "code",                     RPMFC_WHITE },
00618   { "file",                     RPMFC_WHITE },
00619   { "format",                   RPMFC_WHITE },
00620   { "message",                  RPMFC_WHITE },
00621   { "program",                  RPMFC_WHITE },
00622 
00623   { "broken symbolic link to ", RPMFC_WHITE|RPMFC_ERROR },
00624   { "can't read",               RPMFC_WHITE|RPMFC_ERROR },
00625   { "can't stat",               RPMFC_WHITE|RPMFC_ERROR },
00626   { "executable, can't read",   RPMFC_WHITE|RPMFC_ERROR },
00627   { "core file",                RPMFC_WHITE|RPMFC_ERROR },
00628 
00629   { NULL,                       RPMFC_BLACK }
00630 };
00631 /*@=nullassign@*/
00632 
00633 int rpmfcColoring(const char * fmstr)
00634 {
00635     rpmfcToken fct;
00636     int fcolor = RPMFC_BLACK;
00637 
00638     for (fct = rpmfcTokens; fct->token != NULL; fct++) {
00639         if (strstr(fmstr, fct->token) == NULL)
00640             continue;
00641         fcolor |= fct->colors;
00642         if (fcolor & RPMFC_INCLUDE)
00643             return fcolor;
00644     }
00645     return fcolor;
00646 }
00647 
00648 void rpmfcPrint(const char * msg, rpmfc fc, FILE * fp)
00649 {
00650     int fcolor;
00651     int ndx;
00652     int cx;
00653     int dx;
00654     size_t fx;
00655 
00656 unsigned nprovides;
00657 unsigned nrequires;
00658 
00659     if (fp == NULL) fp = stderr;
00660 
00661     if (msg)
00662         fprintf(fp, "===================================== %s\n", msg);
00663 
00664 nprovides = rpmdsCount(fc->provides);
00665 nrequires = rpmdsCount(fc->requires);
00666 
00667     if (fc)
00668     for (fx = 0; fx < fc->nfiles; fx++) {
00669 assert(fx < fc->fcdictx->nvals);
00670         cx = fc->fcdictx->vals[fx];
00671 assert(fx < fc->fcolor->nvals);
00672         fcolor = fc->fcolor->vals[fx];
00673 
00674         fprintf(fp, "%3d %s", (int)fx, fc->fn[fx]);
00675         if (fcolor != RPMFC_BLACK)
00676                 fprintf(fp, "\t0x%x", fc->fcolor->vals[fx]);
00677         else
00678                 fprintf(fp, "\t%s", fc->cdict[cx]);
00679         fprintf(fp, "\n");
00680 
00681         if (fc->fddictx == NULL || fc->fddictn == NULL)
00682             continue;
00683 
00684 assert(fx < fc->fddictx->nvals);
00685         dx = fc->fddictx->vals[fx];
00686 assert(fx < fc->fddictn->nvals);
00687         ndx = fc->fddictn->vals[fx];
00688 
00689         while (ndx-- > 0) {
00690             const char * depval;
00691             unsigned char deptype;
00692             unsigned ix;
00693 
00694             ix = fc->ddictx->vals[dx++];
00695             deptype = ((ix >> 24) & 0xff);
00696             ix &= 0x00ffffff;
00697             depval = NULL;
00698             switch (deptype) {
00699             default:
00700 assert(depval != NULL);
00701                 /*@switchbreak@*/ break;
00702             case 'P':
00703                 if (nprovides > 0) {
00704 assert(ix < nprovides);
00705                     (void) rpmdsSetIx(fc->provides, ix-1);
00706                     if (rpmdsNext(fc->provides) >= 0)
00707                         depval = rpmdsDNEVR(fc->provides);
00708                 }
00709                 /*@switchbreak@*/ break;
00710             case 'R':
00711                 if (nrequires > 0) {
00712 assert(ix < nrequires);
00713                     (void) rpmdsSetIx(fc->requires, ix-1);
00714                     if (rpmdsNext(fc->requires) >= 0)
00715                         depval = rpmdsDNEVR(fc->requires);
00716                 }
00717                 /*@switchbreak@*/ break;
00718             }
00719             if (depval)
00720                 fprintf(fp, "\t%s\n", depval);
00721         }
00722     }
00723 }
00724 
00730 static int rpmfcSCRIPT(rpmfc fc)
00731         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00732         /*@modifies fc, rpmGlobalMacroContext, fileSystem, internalState @*/
00733 {
00734     const char * fn = fc->fn[fc->ix];
00735     const char * bn;
00736     rpmds ds;
00737     char buf[BUFSIZ];
00738     FILE * fp;
00739     char * s, * se;
00740     int i;
00741     int is_executable;
00742     int xx;
00743 
00744     /* Extract dependencies only from files with executable bit set. */
00745     {   struct stat sb, * st = &sb;
00746         if (stat(fn, st) != 0)
00747             return -1;
00748         is_executable = (int)(st->st_mode & (S_IXUSR|S_IXGRP|S_IXOTH));
00749     }
00750 
00751     fp = fopen(fn, "r");
00752     if (fp == NULL || ferror(fp)) {
00753         if (fp) (void) fclose(fp);
00754         return -1;
00755     }
00756 
00757     /* Look for #! interpreter in first 10 lines. */
00758     for (i = 0; i < 10; i++) {
00759 
00760         s = fgets(buf, sizeof(buf) - 1, fp);
00761         if (s == NULL || ferror(fp) || feof(fp))
00762             break;
00763         s[sizeof(buf)-1] = '\0';
00764         if (!(s[0] == '#' && s[1] == '!'))
00765             continue;
00766         s += 2;
00767 
00768         while (*s && strchr(" \t\n\r", *s) != NULL)
00769             s++;
00770         if (*s == '\0')
00771             continue;
00772         if (*s != '/')
00773             continue;
00774 
00775         for (se = s+1; *se; se++) {
00776             if (strchr(" \t\n\r", *se) != NULL)
00777                 /*@innerbreak@*/ break;
00778         }
00779         *se = '\0';
00780         se++;
00781 
00782         if (!_filter_values
00783          || (!fc->skipReq
00784           && !rpmfcMatchRegexps(fc->Rmires, fc->Rnmire, s, 'R')))
00785         if (is_executable) {
00786             /* Add to package requires. */
00787             ds = rpmdsSingle(RPMTAG_REQUIRENAME, s, "", RPMSENSE_FIND_REQUIRES);
00788             xx = rpmdsMerge(&fc->requires, ds);
00789 
00790             /* Add to file requires. */
00791             xx = rpmfcSaveArg(&fc->ddict, rpmfcFileDep(se, fc->ix, ds));
00792 
00793             (void)rpmdsFree(ds);
00794             ds = NULL;
00795         }
00796 
00797         /* Set color based on interpreter name. */
00798         /* XXX magic token should have already done this?!? */
00799 /*@-moduncon@*/
00800         bn = basename(s);
00801 /*@=moduncon@*/
00802         if (!strcmp(bn, "perl"))
00803             fc->fcolor->vals[fc->ix] |= RPMFC_PERL;
00804         else if (!strncmp(bn, "python", sizeof("python")-1))
00805             fc->fcolor->vals[fc->ix] |= RPMFC_PYTHON;
00806         else if (!strncmp(bn, "php", sizeof("php")-1))
00807             fc->fcolor->vals[fc->ix] |= RPMFC_PHP;
00808 
00809         break;
00810     }
00811 
00812     (void) fclose(fp);
00813 
00814     if (fc->fcolor->vals[fc->ix] & RPMFC_PERL) {
00815         if (strncmp(fn, "/usr/share/doc/", sizeof("/usr/share/doc/")-1)) {
00816             if (fc->fcolor->vals[fc->ix] & RPMFC_MODULE)
00817                 xx = rpmfcHelper(fc, 'P', "perl");
00818             if (is_executable || (fc->fcolor->vals[fc->ix] & RPMFC_MODULE))
00819                 xx = rpmfcHelper(fc, 'R', "perl");
00820         }
00821     } else
00822     if (fc->fcolor->vals[fc->ix] & RPMFC_PYTHON) {
00823         xx = rpmfcHelper(fc, 'P', "python");
00824 #ifdef  NOTYET
00825         if (is_executable)
00826 #endif
00827             xx = rpmfcHelper(fc, 'R', "python");
00828     } else
00829     if (fc->fcolor->vals[fc->ix] & RPMFC_LIBTOOL) {
00830         xx = rpmfcHelper(fc, 'P', "libtool");
00831 #ifdef  NOTYET
00832         if (is_executable)
00833 #endif
00834             xx = rpmfcHelper(fc, 'R', "libtool");
00835     } else
00836     if (fc->fcolor->vals[fc->ix] & RPMFC_PKGCONFIG) {
00837         xx = rpmfcHelper(fc, 'P', "pkgconfig");
00838 #ifdef  NOTYET
00839         if (is_executable)
00840 #endif
00841             xx = rpmfcHelper(fc, 'R', "pkgconfig");
00842     } else
00843     if (fc->fcolor->vals[fc->ix] & RPMFC_BOURNE) {
00844 #ifdef  NOTYET
00845         xx = rpmfcHelper(fc, 'P', "executable");
00846 #endif
00847         if (is_executable)
00848             xx = rpmfcHelper(fc, 'R', "executable");
00849     } else
00850     if (fc->fcolor->vals[fc->ix] & RPMFC_PHP) {
00851         xx = rpmfcHelper(fc, 'P', "php");
00852         if (is_executable)
00853             xx = rpmfcHelper(fc, 'R', "php");
00854     } else
00855     if (fc->fcolor->vals[fc->ix] & RPMFC_MONO) {
00856         xx = rpmfcHelper(fc, 'P', "mono");
00857         if (is_executable)
00858             xx = rpmfcHelper(fc, 'R', "mono");
00859     }
00860     return 0;
00861 }
00862 
00869 static int rpmfcMergePR(void * context, rpmds ds)
00870         /*@globals fileSystem, internalState @*/
00871         /*@modifies ds, fileSystem, internalState @*/
00872 {
00873     rpmfc fc = context;
00874     char buf[BUFSIZ];
00875     int rc = 0;
00876 
00877 if (_rpmfc_debug < 0)
00878 fprintf(stderr, "*** rpmfcMergePR(%p, %p) %s\n", context, ds, tagName(rpmdsTagN(ds)));
00879     switch(rpmdsTagN(ds)) {
00880     default:
00881         rc = -1;
00882         break;
00883     case RPMTAG_PROVIDENAME:
00884         if (!_filter_values
00885          || (!fc->skipProv
00886           && !rpmfcMatchRegexps(fc->Pmires, fc->Pnmire, ds->N[0], 'P')))
00887         {
00888             /* Add to package provides. */
00889             rc = rpmdsMerge(&fc->provides, ds);
00890 
00891             /* Add to file dependencies. */
00892             buf[0] = '\0';
00893             rc = rpmfcSaveArg(&fc->ddict, rpmfcFileDep(buf, fc->ix, ds));
00894         }
00895         break;
00896     case RPMTAG_REQUIRENAME:
00897         if (!_filter_values
00898          || (!fc->skipReq
00899           && !rpmfcMatchRegexps(fc->Rmires, fc->Rnmire, ds->N[0], 'R')))
00900         {
00901             /* Add to package requires. */
00902             rc = rpmdsMerge(&fc->requires, ds);
00903 
00904             /* Add to file dependencies. */
00905             buf[0] = '\0';
00906             rc = rpmfcSaveArg(&fc->ddict, rpmfcFileDep(buf, fc->ix, ds));
00907         }
00908         break;
00909     }
00910     return rc;
00911 }
00912 
00918 static int rpmfcELF(rpmfc fc)
00919         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00920         /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
00921 {
00922     const char * fn = fc->fn[fc->ix];
00923     int flags = 0;
00924 
00925     if (fc->skipProv)
00926         flags |= RPMELF_FLAG_SKIPPROVIDES;
00927     if (fc->skipReq)
00928         flags |= RPMELF_FLAG_SKIPREQUIRES;
00929 
00930     return rpmdsELF(fn, flags, rpmfcMergePR, fc);
00931 }
00932 
00933 typedef struct rpmfcApplyTbl_s {
00934     int (*func) (rpmfc fc);
00935     int colormask;
00936 } * rpmfcApplyTbl;
00937 
00941 /*@-nullassign@*/
00942 /*@unchecked@*/
00943 static struct rpmfcApplyTbl_s rpmfcApplyTable[] = {
00944     { rpmfcELF,         RPMFC_ELF },
00945     { rpmfcSCRIPT,      (RPMFC_SCRIPT|RPMFC_PERL|RPMFC_PYTHON|RPMFC_LIBTOOL|RPMFC_PKGCONFIG|RPMFC_BOURNE|RPMFC_JAVA|RPMFC_PHP|RPMFC_MONO) },
00946     { NULL, 0 }
00947 };
00948 /*@=nullassign@*/
00949 
00950 rpmRC rpmfcApply(rpmfc fc)
00951 {
00952     rpmfcApplyTbl fcat;
00953     const char * s;
00954     char * se;
00955     rpmds ds;
00956     const char * fn;
00957     const char * N;
00958     const char * EVR;
00959     evrFlags Flags;
00960     unsigned char deptype;
00961     int nddict;
00962     int previx;
00963     unsigned int val;
00964     int dix;
00965     int ix;
00966     int i;
00967     int xx;
00968     int skipping;
00969 
00970     miRE mire;
00971     int skipProv = fc->skipProv;
00972     int skipReq = fc->skipReq;
00973     int j;
00974 
00975     if (_filter_execs) {
00976         fc->Pnmire = 0;
00977         fc->PFnmire = 0;
00978         fc->Rnmire = 0;
00979         fc->RFnmire = 0;
00980     
00981         fc->PFmires = rpmfcExpandRegexps("%{__noautoprovfiles}", &fc->PFnmire);
00982         fc->RFmires = rpmfcExpandRegexps("%{__noautoreqfiles}", &fc->RFnmire);
00983         fc->Pmires = rpmfcExpandRegexps("%{__noautoprov}", &fc->Pnmire);
00984         fc->Rmires = rpmfcExpandRegexps("%{__noautoreq}", &fc->Rnmire);
00985         rpmlog(RPMLOG_DEBUG, D_("%i _noautoprov patterns.\n"), fc->Pnmire);
00986         rpmlog(RPMLOG_DEBUG, D_("%i _noautoreq patterns.\n"), fc->Rnmire);
00987     }
00988 
00989 /* Make sure something didn't go wrong previously! */
00990 assert(fc->fn != NULL);
00991     /* Generate package and per-file dependencies. */
00992     for (fc->ix = 0; fc->fn[fc->ix] != NULL; fc->ix++) {
00993 
00994         /* XXX Insure that /usr/lib{,64}/python files are marked RPMFC_PYTHON */
00995         /* XXX HACK: classification by path is intrinsically stupid. */
00996         {   fn = strstr(fc->fn[fc->ix], "/usr/lib");
00997             if (fn) {
00998                 fn += sizeof("/usr/lib")-1;
00999                 if ((fn[0] == '3' && fn[1] == '2') || 
01000                         (fn[0] == '6' && fn[1] == '4'))
01001                     fn += 2;
01002                 if (!strncmp(fn, "/python", sizeof("/python")-1))
01003                     fc->fcolor->vals[fc->ix] |= RPMFC_PYTHON;
01004             }
01005         }
01006 
01007         if (fc->fcolor->vals[fc->ix])
01008         for (fcat = rpmfcApplyTable; fcat->func != NULL; fcat++) {
01009             if (!(fc->fcolor->vals[fc->ix] & fcat->colormask))
01010                 /*@innercontinue@*/ continue;
01011 
01012             if (_filter_execs) {
01013                 fc->skipProv = skipProv;
01014                 fc->skipReq = skipReq;
01015                 if ((mire = fc->PFmires) != NULL)
01016                 for (j = 0; j < fc->PFnmire; j++, mire++) {
01017                     fn = fc->fn[fc->ix] + fc->brlen;
01018                     if ((xx = mireRegexec(mire, fn, 0)) < 0)
01019                         /*@innercontinue@*/ continue;
01020                     rpmlog(RPMLOG_NOTICE, _("skipping %s provides detection\n"),
01021                                 fn);
01022                     fc->skipProv = 1;
01023                     /*@innerbreak@*/ break;
01024                 }
01025                 if ((mire = fc->RFmires) != NULL)
01026                 for (j = 0; j < fc->RFnmire; j++, mire++) {
01027                     fn = fc->fn[fc->ix] + fc->brlen;
01028                     if ((xx = mireRegexec(mire, fn, 0)) < 0)
01029                         /*@innercontinue@*/ continue;
01030                     rpmlog(RPMLOG_NOTICE, _("skipping %s requires detection\n"),
01031                                 fn);
01032                     fc->skipReq = 1;
01033                     /*@innerbreak@*/ break;
01034                 }
01035             }
01036 
01037             xx = (*fcat->func) (fc);
01038         }
01039     }
01040 
01041     if (_filter_execs) {
01042         fc->PFmires = rpmfcFreeRegexps(fc->PFmires, fc->PFnmire);
01043         fc->RFmires = rpmfcFreeRegexps(fc->RFmires, fc->RFnmire);
01044         fc->Pmires = rpmfcFreeRegexps(fc->Pmires, fc->Pnmire);
01045         fc->Rmires = rpmfcFreeRegexps(fc->Rmires, fc->Rnmire);
01046     }
01047     fc->skipProv = skipProv;
01048     fc->skipReq = skipReq;
01049 
01050     /* Generate per-file indices into package dependencies. */
01051     nddict = argvCount(fc->ddict);
01052     previx = -1;
01053     for (i = 0; i < nddict; i++) {
01054         s = fc->ddict[i];
01055 
01056         /* Parse out (file#,deptype,N,EVR,Flags) */
01057         ix = strtol(s, &se, 10);
01058 assert(se != NULL);
01059         deptype = *se++;
01060         se++;
01061         N = se;
01062         while (*se && *se != ' ')
01063             se++;
01064         *se++ = '\0';
01065         EVR = se;
01066         while (*se && *se != ' ')
01067             se++;
01068         *se++ = '\0';
01069         Flags = strtol(se, NULL, 16);
01070 
01071         dix = -1;
01072         skipping = 0;
01073         switch (deptype) {
01074         default:
01075             /*@switchbreak@*/ break;
01076         case 'P':       
01077             skipping = fc->skipProv;
01078             ds = rpmdsSingle(RPMTAG_PROVIDENAME, N, EVR, Flags);
01079             dix = rpmdsFind(fc->provides, ds);
01080             (void)rpmdsFree(ds);
01081             ds = NULL;
01082             /*@switchbreak@*/ break;
01083         case 'R':
01084             skipping = fc->skipReq;
01085             ds = rpmdsSingle(RPMTAG_REQUIRENAME, N, EVR, Flags);
01086             dix = rpmdsFind(fc->requires, ds);
01087             (void)rpmdsFree(ds);
01088             ds = NULL;
01089             /*@switchbreak@*/ break;
01090         }
01091 
01092 /* XXX assertion incorrect while generating -debuginfo deps. */
01093 #if 0
01094 assert(dix >= 0);
01095 #else
01096         if (dix < 0)
01097             continue;
01098 #endif
01099 
01100         val = (deptype << 24) | (dix & 0x00ffffff);
01101         xx = argiAdd(&fc->ddictx, -1, val);
01102 
01103         if (previx != ix) {
01104             previx = ix;
01105             xx = argiAdd(&fc->fddictx, ix, argiCount(fc->ddictx)-1);
01106         }
01107         if (fc->fddictn && fc->fddictn->vals && !skipping)
01108             fc->fddictn->vals[ix]++;
01109     }
01110 
01111     return RPMRC_OK;
01112 }
01113 
01114 rpmRC rpmfcClassify(rpmfc fc, ARGV_t argv, rpmuint16_t * fmode)
01115 {
01116     ARGV_t fcav = NULL;
01117     ARGV_t dav;
01118     rpmmg mg = NULL;
01119     const char * s, * se;
01120     size_t slen;
01121     int fcolor;
01122     int xx;
01123     const char * magicfile = NULL;
01124 
01125     if (fc == NULL || argv == NULL)
01126         return RPMRC_OK;
01127 
01128     magicfile = rpmExpand("%{?_rpmfc_magic_path}", NULL);
01129     if (magicfile == NULL || *magicfile == '\0')
01130         magicfile = _free(magicfile);
01131     mg = rpmmgNew(magicfile, 0);
01132 assert(mg != NULL);     /* XXX figger a proper return path. */
01133 
01134     fc->nfiles = argvCount(argv);
01135 
01136     /* Initialize the per-file dictionary indices. */
01137     xx = argiAdd(&fc->fddictx, fc->nfiles-1, 0);
01138     xx = argiAdd(&fc->fddictn, fc->nfiles-1, 0);
01139 
01140     /* Build (sorted) file class dictionary. */
01141     xx = argvAdd(&fc->cdict, "");
01142     xx = argvAdd(&fc->cdict, "directory");
01143 
01144     for (fc->ix = 0; fc->ix < fc->nfiles; fc->ix++) {
01145         const char * ftype;
01146         int freeftype;
01147         rpmuint16_t mode = (fmode ? fmode[fc->ix] : 0);
01148         int urltype;
01149 
01150         ftype = "";     freeftype = 0;
01151         urltype = urlPath(argv[fc->ix], &s);
01152 assert(s != NULL && *s == '/');
01153         slen = strlen(s);
01154 
01155         switch (mode & S_IFMT) {
01156         case S_IFCHR:   ftype = "character special";    /*@switchbreak@*/ break;
01157         case S_IFBLK:   ftype = "block special";        /*@switchbreak@*/ break;
01158 #if defined(S_IFIFO)
01159         case S_IFIFO:   ftype = "fifo (named pipe)";    /*@switchbreak@*/ break;
01160 #endif
01161 #if defined(S_IFSOCK)
01162 /*@-unrecog@*/
01163         case S_IFSOCK:  ftype = "socket";               /*@switchbreak@*/ break;
01164 /*@=unrecog@*/
01165 #endif
01166         case S_IFDIR:
01167         case S_IFLNK:
01168         case S_IFREG:
01169         default:
01170 
01171 #define _suffix(_s, _x) \
01172     (slen >= sizeof(_x) && !strcmp((_s)+slen-(sizeof(_x)-1), (_x)))
01173 
01174             /* XXX all files with extension ".pm" are perl modules for now. */
01175             if (_suffix(s, ".pm"))
01176                 ftype = "Perl5 module source text";
01177 
01178             /* XXX all files with extension ".jar" are java archives for now. */
01179             else if (_suffix(s, ".jar"))
01180                 ftype = "Java archive file";
01181 
01182             /* XXX all files with extension ".class" are java class files for now. */
01183             else if (_suffix(s, ".class"))
01184                 ftype = "Java class file";
01185 
01186             /* XXX all files with extension ".la" are libtool for now. */
01187             else if (_suffix(s, ".la"))
01188                 ftype = "libtool library file";
01189 
01190             /* XXX all files with extension ".pc" are pkgconfig for now. */
01191             else if (_suffix(s, ".pc"))
01192                 ftype = "pkgconfig file";
01193 
01194             /* XXX all files with extension ".php" are PHP for now. */
01195             else if (_suffix(s, ".php"))
01196                 ftype = "PHP script text";
01197 
01198             /* XXX skip all files in /dev/ which are (or should be) %dev dummies. */
01199             else if (slen >= fc->brlen+sizeof("/dev/") && !strncmp(s+fc->brlen, "/dev/", sizeof("/dev/")-1))
01200                 ftype = "";
01201             else if (magicfile) {
01202                 ftype = rpmmgFile(mg, s);
01203 assert(ftype != NULL);  /* XXX never happens, rpmmgFile() returns "" */
01204                 freeftype = 1;
01205             }
01206             /*@switchbreak@*/ break;
01207         }
01208 
01209         se = ftype;
01210 
01211 if (_rpmfc_debug)       /* XXX noisy */
01212         rpmlog(RPMLOG_DEBUG, "%s: %s\n", s, se);
01213 
01214         /* Save the path. */
01215         xx = argvAdd(&fc->fn, s);
01216 
01217         /* Save the file type string. */
01218         xx = argvAdd(&fcav, se);
01219 
01220         /* Add (filtered) entry to sorted class dictionary. */
01221         fcolor = rpmfcColoring(se);
01222         xx = argiAdd(&fc->fcolor, (int)fc->ix, fcolor);
01223 
01224         if (fcolor != RPMFC_WHITE && (fcolor & RPMFC_INCLUDE))
01225             xx = rpmfcSaveArg(&fc->cdict, se);
01226 
01227 /*@-modobserver -observertrans @*/      /* XXX mixed types in variable */
01228         if (freeftype)
01229             ftype = _free(ftype);
01230 /*@=modobserver =observertrans @*/
01231     }
01232 
01233     /* Build per-file class index array. */
01234     fc->fknown = 0;
01235     for (fc->ix = 0; fc->ix < fc->nfiles; fc->ix++) {
01236         se = fcav[fc->ix];
01237 assert(se != NULL);
01238 
01239         dav = argvSearch(fc->cdict, se, NULL);
01240         if (dav) {
01241             xx = argiAdd(&fc->fcdictx, (int)fc->ix, (dav - fc->cdict));
01242             fc->fknown++;
01243         } else {
01244             xx = argiAdd(&fc->fcdictx, (int)fc->ix, 0);
01245             fc->fwhite++;
01246         }
01247     }
01248 
01249     fcav = argvFree(fcav);
01250 
01251     mg = rpmmgFree(mg);
01252     rpmlog(RPMLOG_DEBUG,
01253                 D_("categorized %d files into %d classes (using %s).\n"),
01254                 fc->nfiles, argvCount(fc->cdict), magicfile);
01255     magicfile = _free(magicfile);
01256 
01257     return RPMRC_OK;
01258 }
01259 
01262 typedef struct DepMsg_s * DepMsg_t;
01263 
01266 struct DepMsg_s {
01267 /*@observer@*/ /*@null@*/
01268     const char * msg;
01269 /*@observer@*/
01270     const char * argv[4];
01271     rpmTag ntag;
01272     rpmTag vtag;
01273     rpmTag ftag;
01274     int mask;
01275     int xor;
01276 };
01277 
01280 /*@-nullassign@*/
01281 /*@unchecked@*/
01282 static struct DepMsg_s depMsgs[] = {
01283   { "Provides",         { "%{?__find_provides}", NULL, NULL, NULL },
01284         RPMTAG_PROVIDENAME, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS,
01285         0, -1 },
01286   { "Requires(interp)", { NULL, "interp", NULL, NULL },
01287         RPMTAG_REQUIRENAME, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS,
01288         _notpre(RPMSENSE_INTERP), 0 },
01289   { "Requires(rpmlib)", { NULL, "rpmlib", NULL, NULL },
01290         -1, -1, RPMTAG_REQUIREFLAGS,
01291         _notpre(RPMSENSE_RPMLIB), 0 },
01292   { "Requires(verify)", { NULL, "verify", NULL, NULL },
01293         -1, -1, RPMTAG_REQUIREFLAGS,
01294         RPMSENSE_SCRIPT_VERIFY, 0 },
01295   { "Requires(pre)",    { NULL, "pre", NULL, NULL },
01296         -1, -1, RPMTAG_REQUIREFLAGS,
01297         _notpre(RPMSENSE_SCRIPT_PRE), 0 },
01298   { "Requires(post)",   { NULL, "post", NULL, NULL },
01299         -1, -1, RPMTAG_REQUIREFLAGS,
01300         _notpre(RPMSENSE_SCRIPT_POST), 0 },
01301   { "Requires(preun)",  { NULL, "preun", NULL, NULL },
01302         -1, -1, RPMTAG_REQUIREFLAGS,
01303         _notpre(RPMSENSE_SCRIPT_PREUN), 0 },
01304   { "Requires(postun)", { NULL, "postun", NULL, NULL },
01305         -1, -1, RPMTAG_REQUIREFLAGS,
01306         _notpre(RPMSENSE_SCRIPT_POSTUN), 0 },
01307   { "Requires",         { "%{?__find_requires}", NULL, NULL, NULL },
01308         -1, -1, RPMTAG_REQUIREFLAGS,    /* XXX inherit name/version arrays */
01309         RPMSENSE_FIND_REQUIRES|RPMSENSE_TRIGGERIN|RPMSENSE_TRIGGERUN|RPMSENSE_TRIGGERPOSTUN|RPMSENSE_TRIGGERPREIN, 0 },
01310   { "Conflicts",        { "%{?__find_conflicts}", NULL, NULL, NULL },
01311         RPMTAG_CONFLICTNAME, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS,
01312         0, -1 },
01313   { "Obsoletes",        { "%{?__find_obsoletes}", NULL, NULL, NULL },
01314         RPMTAG_OBSOLETENAME, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS,
01315         0, -1 },
01316   { NULL,               { NULL, NULL, NULL, NULL },     0, 0, 0, 0, 0 }
01317 };
01318 /*@=nullassign@*/
01319 
01320 /*@unchecked@*/
01321 static DepMsg_t DepMsgs = depMsgs;
01322 
01327 static void printDeps(Header h)
01328         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01329         /*@modifies h, rpmGlobalMacroContext, fileSystem, internalState @*/
01330 {
01331     DepMsg_t dm;
01332     rpmds ds = NULL;
01333     int flags = 0x2;    /* XXX no filtering, !scareMem */
01334     const char * DNEVR;
01335     evrFlags Flags;
01336     int bingo = 0;
01337 
01338     for (dm = DepMsgs; dm->msg != NULL; dm++) {
01339         if ((int)dm->ntag != -1) {
01340             (void)rpmdsFree(ds);
01341             ds = NULL;
01342             ds = rpmdsNew(h, dm->ntag, flags);
01343         }
01344         if (dm->ftag == 0)
01345             continue;
01346 
01347         ds = rpmdsInit(ds);
01348         if (ds == NULL)
01349             continue;   /* XXX can't happen */
01350 
01351         bingo = 0;
01352         while (rpmdsNext(ds) >= 0) {
01353 
01354             Flags = rpmdsFlags(ds);
01355         
01356             if (!((Flags & dm->mask) ^ dm->xor))
01357                 /*@innercontinue@*/ continue;
01358             if (bingo == 0) {
01359                 rpmlog(RPMLOG_NOTICE, "%s:", (dm->msg ? dm->msg : ""));
01360                 bingo = 1;
01361             }
01362             if ((DNEVR = rpmdsDNEVR(ds)) == NULL)
01363                 /*@innercontinue@*/ continue;   /* XXX can't happen */
01364             rpmlog(RPMLOG_NOTICE, " %s", DNEVR+2);
01365         }
01366         if (bingo)
01367             rpmlog(RPMLOG_NOTICE, "\n");
01368     }
01369     (void)rpmdsFree(ds);
01370     ds = NULL;
01371 }
01372 
01375 static rpmRC rpmfcGenerateDependsHelper(const Spec spec, Package pkg, rpmfi fi)
01376         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01377         /*@modifies fi, rpmGlobalMacroContext, fileSystem, internalState @*/
01378 {
01379     rpmiob iob_stdin;
01380     rpmiob iob_stdout;
01381     DepMsg_t dm;
01382     int failnonzero = 0;
01383     rpmRC rc = RPMRC_OK;
01384 
01385     /*
01386      * Create file manifest buffer to deliver to dependency finder.
01387      */
01388     iob_stdin = rpmiobNew(0);
01389     fi = rpmfiInit(fi, 0);
01390     if (fi != NULL)
01391     while (rpmfiNext(fi) >= 0)
01392         iob_stdin = rpmiobAppend(iob_stdin, rpmfiFN(fi), 1);
01393 
01394     for (dm = DepMsgs; dm->msg != NULL; dm++) {
01395         rpmTag tag;
01396         rpmsenseFlags tagflags;
01397         char * s;
01398         int xx;
01399 
01400         tag = (dm->ftag > 0) ? dm->ftag : dm->ntag;
01401         tagflags = 0;
01402         s = NULL;
01403 
01404         switch(tag) {
01405         case RPMTAG_PROVIDEFLAGS:
01406             if (!pkg->autoProv)
01407                 continue;
01408             failnonzero = 1;
01409             tagflags = RPMSENSE_FIND_PROVIDES;
01410             /*@switchbreak@*/ break;
01411         case RPMTAG_REQUIREFLAGS:
01412             if (!pkg->autoReq)
01413                 continue;
01414             failnonzero = 0;
01415             tagflags = RPMSENSE_FIND_REQUIRES;
01416             /*@switchbreak@*/ break;
01417         default:
01418             continue;
01419             /*@notreached@*/ /*@switchbreak@*/ break;
01420         }
01421 
01422         xx = rpmfcExec(dm->argv, iob_stdin, &iob_stdout, failnonzero);
01423         if (xx == -1)
01424             continue;
01425 
01426         s = rpmExpand(dm->argv[0], NULL);
01427         rpmlog(RPMLOG_NOTICE, _("Finding  %s: %s\n"), dm->msg,
01428                 (s ? s : ""));
01429         s = _free(s);
01430 
01431         if (iob_stdout == NULL) {
01432             rpmlog(RPMLOG_ERR, _("Failed to find %s:\n"), dm->msg);
01433             rc = RPMRC_FAIL;
01434             break;
01435         }
01436 
01437         /* Parse dependencies into header */
01438         if (spec->_parseRCPOT)
01439             rc = spec->_parseRCPOT(spec, pkg, rpmiobStr(iob_stdout), tag,
01440                                 0, tagflags);
01441         iob_stdout = rpmiobFree(iob_stdout);
01442 
01443         if (rc) {
01444             rpmlog(RPMLOG_ERR, _("Failed to find %s:\n"), dm->msg);
01445             break;
01446         }
01447     }
01448 
01449     iob_stdin = rpmiobFree(iob_stdin);
01450 
01451     return rc;
01452 }
01453 
01456 /*@-nullassign@*/
01457 /*@unchecked@*/
01458 static struct DepMsg_s scriptMsgs[] = {
01459   { "Requires(pre)",    { "%{?__scriptlet_requires}", NULL, NULL, NULL },
01460         RPMTAG_PREINPROG, RPMTAG_PREIN, RPMTAG_REQUIREFLAGS,
01461         RPMSENSE_SCRIPT_PRE, 0 },
01462   { "Requires(post)",   { "%{?__scriptlet_requires}", NULL, NULL, NULL },
01463         RPMTAG_POSTINPROG, RPMTAG_POSTIN, RPMTAG_REQUIREFLAGS,
01464         RPMSENSE_SCRIPT_POST, 0 },
01465   { "Requires(preun)",  { "%{?__scriptlet_requires}", NULL, NULL, NULL },
01466         RPMTAG_PREUNPROG, RPMTAG_PREUN, RPMTAG_REQUIREFLAGS,
01467         RPMSENSE_SCRIPT_PREUN, 0 },
01468   { "Requires(postun)", { "%{?__scriptlet_requires}", NULL, NULL, NULL },
01469         RPMTAG_POSTUNPROG, RPMTAG_POSTUN, RPMTAG_REQUIREFLAGS,
01470         RPMSENSE_SCRIPT_POSTUN, 0 },
01471   { NULL,               { NULL, NULL, NULL, NULL },     0, 0, 0, 0, 0 }
01472 };
01473 /*@=nullassign@*/
01474 
01475 /*@unchecked@*/
01476 static DepMsg_t ScriptMsgs = scriptMsgs;
01477 
01480 static int rpmfcGenerateScriptletDeps(const Spec spec, Package pkg)
01481         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01482         /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
01483 {
01484     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
01485     rpmiob iob_stdin = rpmiobNew(0);
01486     rpmiob iob_stdout = NULL;
01487     DepMsg_t dm;
01488     int failnonzero = 0;
01489     int rc = 0;
01490     int xx;
01491 
01492     for (dm = ScriptMsgs; dm->msg != NULL; dm++) {
01493         int tag, tagflags;
01494         char * s;
01495 
01496         tag = dm->ftag;
01497         tagflags = RPMSENSE_FIND_REQUIRES | dm->mask;
01498 
01499         /* Retrieve scriptlet interpreter. */
01500         he->tag = dm->ntag;
01501         xx = headerGet(pkg->header, he, 0);
01502         if (!xx || he->p.str == NULL)
01503             continue;
01504         xx = strcmp(he->p.str, "/bin/sh") && strcmp(he->p.str, "/bin/bash");
01505         he->p.ptr = _free(he->p.ptr);
01506         if (xx)
01507             continue;
01508 
01509         /* Retrieve scriptlet body. */
01510         he->tag = dm->vtag;
01511         xx = headerGet(pkg->header, he, 0);
01512         if (!xx || he->p.str == NULL)
01513             continue;
01514         iob_stdin = rpmiobEmpty(iob_stdin);
01515         iob_stdin = rpmiobAppend(iob_stdin, he->p.str, 1);
01516         iob_stdin = rpmiobRTrim(iob_stdin);
01517         he->p.ptr = _free(he->p.ptr);
01518 
01519         xx = rpmfcExec(dm->argv, iob_stdin, &iob_stdout, failnonzero);
01520         if (xx == -1)
01521             continue;
01522 
01523         /* Parse dependencies into header */
01524         s = rpmiobStr(iob_stdout);
01525         if (s != NULL && *s != '\0') {
01526             char * se = s;
01527             /* XXX Convert "executable(/path/to/file)" to "/path/to/file". */
01528             while ((se = strstr(se, "executable(/")) != NULL) {
01529 /*@-modobserver@*/      /* FIX: rpmiobStr should not be observer */
01530                 se = stpcpy(se,     "           ");
01531                 *se = '/';      /* XXX stpcpy truncates the '/' */
01532 /*@=modobserver@*/
01533                 se = strchr(se, ')');
01534                 if (se == NULL)
01535                     /*@innerbreak@*/ break;
01536                 *se++ = ' ';
01537             }
01538             if (spec->_parseRCPOT)
01539                 rc = spec->_parseRCPOT(spec, pkg, s, tag, 0, tagflags);
01540         }
01541         iob_stdout = rpmiobFree(iob_stdout);
01542 
01543     }
01544 
01545     iob_stdin = rpmiobFree(iob_stdin);
01546 
01547     return rc;
01548 }
01549 
01550 rpmRC rpmfcGenerateDepends(void * specp, void * pkgp)
01551 {
01552     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
01553     const Spec spec = specp;
01554     Package pkg = pkgp;
01555     rpmfi fi = pkg->cpioList;
01556     rpmfc fc = NULL;
01557     rpmds ds;
01558     int flags = 0x2;    /* XXX no filtering, !scareMem */
01559     ARGV_t av;
01560     rpmuint16_t * fmode;
01561     int ac = rpmfiFC(fi);
01562     char buf[BUFSIZ];
01563     const char * N;
01564     const char * EVR;
01565     int genConfigDeps, internaldeps;
01566     rpmRC rc = RPMRC_OK;
01567     int i;
01568     int xx;
01569 
01570     /* Skip packages with no files. */
01571     if (ac <= 0)
01572         return RPMRC_OK;
01573 
01574     /* Skip packages that have dependency generation disabled. */
01575     if (! (pkg->autoReq || pkg->autoProv))
01576         return RPMRC_OK;
01577 
01578     /* If new-fangled dependency generation is disabled ... */
01579     internaldeps = rpmExpandNumeric("%{?_use_internal_dependency_generator}");
01580     if (internaldeps == 0) {
01581         /* ... then generate dependencies using %{__find_requires} et al. */
01582         rc = rpmfcGenerateDependsHelper(spec, pkg, fi);
01583         printDeps(pkg->header);
01584         return rc;
01585     }
01586 
01587     /* Generate scriptlet Dependencies. */
01588     if (internaldeps > 1)
01589         xx = rpmfcGenerateScriptletDeps(spec, pkg);
01590 
01591     /* Extract absolute file paths in argv format. */
01592     /* XXX TODO: should use argvFoo ... */
01593     av = xcalloc(ac+1, sizeof(*av));
01594     fmode = xcalloc(ac+1, sizeof(*fmode));
01595 
01596     genConfigDeps = 0;
01597     fi = rpmfiInit(fi, 0);
01598     if (fi != NULL)
01599     while ((i = rpmfiNext(fi)) >= 0) {
01600         rpmfileAttrs fileAttrs;
01601 
01602         /* Does package have any %config files? */
01603         fileAttrs = rpmfiFFlags(fi);
01604         genConfigDeps |= (fileAttrs & RPMFILE_CONFIG);
01605 
01606         av[i] = xstrdup(rpmfiFN(fi));
01607         fmode[i] = rpmfiFMode(fi);
01608     }
01609     av[ac] = NULL;
01610 
01611     fc = rpmfcNew();
01612     fc->skipProv = !pkg->autoProv;
01613     fc->skipReq = !pkg->autoReq;
01614     fc->tracked = 0;
01615 
01616     {   const char * buildRootURL;
01617         const char * buildRoot;
01618         buildRootURL = rpmGenPath(spec->rootURL, "%{?buildroot}", NULL);
01619         (void) urlPath(buildRootURL, &buildRoot);
01620         if (buildRoot && !strcmp(buildRoot, "/")) buildRoot = NULL;
01621         fc->brlen = (buildRoot ? strlen(buildRoot) : 0);
01622         buildRootURL = _free(buildRootURL);
01623     }
01624 
01625     /* Copy (and delete) manually generated dependencies to dictionary. */
01626     if (!fc->skipProv) {
01627         ds = rpmdsNew(pkg->header, RPMTAG_PROVIDENAME, flags);
01628         xx = rpmdsMerge(&fc->provides, ds);
01629         (void)rpmdsFree(ds);
01630         ds = NULL;
01631         he->tag = RPMTAG_PROVIDENAME;
01632         xx = headerDel(pkg->header, he, 0);
01633         he->tag = RPMTAG_PROVIDEVERSION;
01634         xx = headerDel(pkg->header, he, 0);
01635         he->tag = RPMTAG_PROVIDEFLAGS;
01636         xx = headerDel(pkg->header, he, 0);
01637 
01638         /* Add config dependency, Provides: config(N) = EVR */
01639         if (genConfigDeps) {
01640             N = rpmdsN(pkg->ds);
01641 assert(N != NULL);
01642             EVR = rpmdsEVR(pkg->ds);
01643 assert(EVR != NULL);
01644             sprintf(buf, "config(%s)", N);
01645             ds = rpmdsSingle(RPMTAG_PROVIDENAME, buf, EVR,
01646                         (RPMSENSE_EQUAL|RPMSENSE_CONFIG));
01647             xx = rpmdsMerge(&fc->provides, ds);
01648             (void)rpmdsFree(ds);
01649             ds = NULL;
01650         }
01651     }
01652 
01653     if (!fc->skipReq) {
01654         ds = rpmdsNew(pkg->header, RPMTAG_REQUIRENAME, flags);
01655         xx = rpmdsMerge(&fc->requires, ds);
01656         (void)rpmdsFree(ds);
01657         ds = NULL;
01658         he->tag = RPMTAG_REQUIRENAME;
01659         xx = headerDel(pkg->header, he, 0);
01660         he->tag = RPMTAG_REQUIREVERSION;
01661         xx = headerDel(pkg->header, he, 0);
01662         he->tag = RPMTAG_REQUIREFLAGS;
01663         xx = headerDel(pkg->header, he, 0);
01664 
01665         /* Add config dependency,  Requires: config(N) = EVR */
01666         if (genConfigDeps) {
01667             N = rpmdsN(pkg->ds);
01668 assert(N != NULL);
01669             EVR = rpmdsEVR(pkg->ds);
01670 assert(EVR != NULL);
01671             sprintf(buf, "config(%s)", N);
01672             ds = rpmdsSingle(RPMTAG_REQUIRENAME, buf, EVR,
01673                         (RPMSENSE_EQUAL|RPMSENSE_CONFIG));
01674             xx = rpmdsMerge(&fc->requires, ds);
01675             (void)rpmdsFree(ds);
01676             ds = NULL;
01677         }
01678     }
01679 
01680     /* Build file class dictionary. */
01681     xx = rpmfcClassify(fc, av, fmode);
01682 
01683     /* Build file/package dependency dictionary. */
01684     xx = rpmfcApply(fc);
01685 
01686     /* Add per-file colors(#files) */
01687     he->tag = RPMTAG_FILECOLORS;
01688     he->t = RPM_UINT32_TYPE;
01689     he->p.ui32p = argiData(fc->fcolor);
01690     he->c = argiCount(fc->fcolor);
01691 assert(ac == (int)he->c);
01692     if (he->p.ptr != NULL && he->c > 0) {
01693         rpmuint32_t * fcolors = he->p.ui32p;
01694 
01695         /* XXX Make sure only primary (i.e. Elf32/Elf64) colors are added. */
01696         for (i = 0; i < (int)he->c; i++)
01697             fcolors[i] &= 0x0f;
01698 
01699         xx = headerPut(pkg->header, he, 0);
01700     }
01701 
01702     /* Add classes(#classes) */
01703     he->tag = RPMTAG_CLASSDICT;
01704     he->t = RPM_STRING_ARRAY_TYPE;
01705     he->p.argv = argvData(fc->cdict);
01706     he->c = argvCount(fc->cdict);
01707     if (he->p.ptr != NULL && he->c > 0) {
01708         xx = headerPut(pkg->header, he, 0);
01709     }
01710 
01711     /* Add per-file classes(#files) */
01712     he->tag = RPMTAG_FILECLASS;
01713     he->t = RPM_UINT32_TYPE;
01714     he->p.ui32p = argiData(fc->fcdictx);
01715     he->c = argiCount(fc->fcdictx);
01716 assert(ac == (int)he->c);
01717     if (he->p.ptr != NULL && he->c > 0) {
01718         xx = headerPut(pkg->header, he, 0);
01719     }
01720 
01721     /* Add Provides: */
01722     if (fc->provides != NULL && (he->c = rpmdsCount(fc->provides)) > 0
01723      && !fc->skipProv)
01724     {
01725         he->tag = RPMTAG_PROVIDENAME;
01726         he->t = RPM_STRING_ARRAY_TYPE;
01727         he->p.argv = fc->provides->N;
01728         xx = headerPut(pkg->header, he, 0);
01729 
01730         /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
01731 /*@-nullpass@*/
01732         he->tag = RPMTAG_PROVIDEVERSION;
01733         he->t = RPM_STRING_ARRAY_TYPE;
01734         he->p.argv = fc->provides->EVR;
01735 assert(he->p.ptr != NULL);
01736         xx = headerPut(pkg->header, he, 0);
01737 
01738         he->tag = RPMTAG_PROVIDEFLAGS;
01739         he->t = RPM_UINT32_TYPE;
01740         he->p.ui32p = (rpmuint32_t *) fc->provides->Flags;
01741 assert(he->p.ptr != NULL);
01742         xx = headerPut(pkg->header, he, 0);
01743 /*@=nullpass@*/
01744     }
01745 
01746     /* Add Requires: */
01747     if (fc->requires != NULL && (he->c = rpmdsCount(fc->requires)) > 0
01748      && !fc->skipReq)
01749     {
01750         he->tag = RPMTAG_REQUIRENAME;
01751         he->t = RPM_STRING_ARRAY_TYPE;
01752         he->p.argv = fc->requires->N;
01753 assert(he->p.ptr != NULL);
01754         xx = headerPut(pkg->header, he, 0);
01755 
01756         /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
01757 /*@-nullpass@*/
01758         he->tag = RPMTAG_REQUIREVERSION;
01759         he->t = RPM_STRING_ARRAY_TYPE;
01760         he->p.argv = fc->requires->EVR;
01761 assert(he->p.ptr != NULL);
01762         xx = headerPut(pkg->header, he, 0);
01763 
01764         he->tag = RPMTAG_REQUIREFLAGS;
01765         he->t = RPM_UINT32_TYPE;
01766         he->p.ui32p = (rpmuint32_t *) fc->requires->Flags;
01767 assert(he->p.ptr != NULL);
01768         xx = headerPut(pkg->header, he, 0);
01769 /*@=nullpass@*/
01770     }
01771 
01772     /* Add dependency dictionary(#dependencies) */
01773     he->tag = RPMTAG_DEPENDSDICT;
01774     he->t = RPM_UINT32_TYPE;
01775     he->p.ui32p = argiData(fc->ddictx);
01776     he->c = argiCount(fc->ddictx);
01777     if (he->p.ptr != NULL) {
01778         xx = headerPut(pkg->header, he, 0);
01779     }
01780 
01781     /* Add per-file dependency (start,number) pairs (#files) */
01782     he->tag = RPMTAG_FILEDEPENDSX;
01783     he->t = RPM_UINT32_TYPE;
01784     he->p.ui32p = argiData(fc->fddictx);
01785     he->c = argiCount(fc->fddictx);
01786 assert(ac == (int)he->c);
01787     if (he->p.ptr != NULL) {
01788         xx = headerPut(pkg->header, he, 0);
01789     }
01790 
01791     he->tag = RPMTAG_FILEDEPENDSN;
01792     he->t = RPM_UINT32_TYPE;
01793     he->p.ui32p = argiData(fc->fddictn);
01794     he->c = argiCount(fc->fddictn);
01795 assert(ac == (int)he->c);
01796     if (he->p.ptr != NULL) {
01797         xx = headerPut(pkg->header, he, 0);
01798     }
01799 
01800     printDeps(pkg->header);
01801 
01802 if (fc != NULL && _rpmfc_debug) {
01803 char msg[BUFSIZ];
01804 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));
01805 rpmfcPrint(msg, fc, NULL);
01806 }
01807 
01808     /* Clean up. */
01809     fmode = _free(fmode);
01810     fc = rpmfcFree(fc);
01811     av = argvFree(av);
01812 
01813     return rc;
01814 }
01815 
01816 /*@-mustmod@*/
01817 static void rpmfcFini(void * _fc)
01818         /*@modifies _fc @*/
01819 {
01820     rpmfc fc = _fc;
01821 
01822     fc->fn = argvFree(fc->fn);
01823     fc->fcolor = argiFree(fc->fcolor);
01824     fc->fcdictx = argiFree(fc->fcdictx);
01825     fc->fddictx = argiFree(fc->fddictx);
01826     fc->fddictn = argiFree(fc->fddictn);
01827     fc->cdict = argvFree(fc->cdict);
01828     fc->ddict = argvFree(fc->ddict);
01829     fc->ddictx = argiFree(fc->ddictx);
01830 
01831     (void)rpmdsFree(fc->provides);
01832     fc->provides = NULL;
01833     (void)rpmdsFree(fc->requires);
01834     fc->requires = NULL;
01835 
01836     fc->iob_java = rpmiobFree(fc->iob_java);
01837     fc->iob_perl = rpmiobFree(fc->iob_perl);
01838     fc->iob_python = rpmiobFree(fc->iob_python);
01839     fc->iob_php = rpmiobFree(fc->iob_php);
01840 }
01841 /*@=mustmod@*/
01842 
01843 /*@unchecked@*/ /*@only@*/ /*@null@*/
01844 rpmioPool _rpmfcPool = NULL;
01845 
01846 static rpmfc rpmfcGetPool(/*@null@*/ rpmioPool pool)
01847         /*@globals _rpmfcPool, fileSystem, internalState @*/
01848         /*@modifies pool, _rpmfcPool, fileSystem, internalState @*/
01849 {
01850     rpmfc fc;
01851 
01852     if (_rpmfcPool == NULL) {
01853         _rpmfcPool = rpmioNewPool("fc", sizeof(*fc), -1, _rpmfc_debug,
01854                         NULL, NULL, rpmfcFini);
01855         pool = _rpmfcPool;
01856     }
01857     return (rpmfc) rpmioGetPool(pool, sizeof(*fc));
01858 }
01859 
01860 rpmfc rpmfcNew(void)
01861 {
01862     rpmfc fc = rpmfcGetPool(_rpmfcPool);
01863     return rpmfcLink(fc);
01864 }
01865