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