rpm 5.2.1

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

- File List
- Globals

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