• 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 }

Generated on Mon Nov 29 2010 05:18:44 for rpm by  doxygen 1.7.2