lib/rpmfc.c

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

Generated on Fri Sep 7 01:07:23 2007 for rpm by  doxygen 1.5.1