Functional ELF/SCRIPT dependency generation.
authorjbj <devnull@localhost>
Sat, 19 Oct 2002 22:48:25 +0000 (22:48 +0000)
committerjbj <devnull@localhost>
Sat, 19 Oct 2002 22:48:25 +0000 (22:48 +0000)
CVS patchset: 5790
CVS date: 2002/10/19 22:48:25

build/argv.c
build/argv.h
build/rpmfc.c
build/rpmfc.h
build/tfr.c

index 01af214..2f92fe0 100644 (file)
@@ -21,15 +21,15 @@ void * _free(/*@only@*/ /*@null@*/ /*@out@*/ const void * p)
 void argvPrint(const char * msg, ARGV_t argv, FILE * fp)
 {
     ARGV_t av;
-    int ac;
 
     if (fp == NULL) fp = stderr;
 
     if (msg)
        fprintf(fp, "===================================== %s\n", msg);
 
-    for (ac = 0, av = argv; *av; av++, ac++)
-       fprintf(fp, "%5d: %s\n", ac, *av);
+    if (argv)
+    for (av = argv; *av; av++)
+       fprintf(fp, "%s\n", *av);
 
 }
 
@@ -56,7 +56,15 @@ ARGV_t argvFree(/*@only@*/ /*@null@*/ ARGV_t argv)
     return NULL;
 }
 
-int argvCount(/*@null@*/ const ARGV_t argv)
+int argiCount(ARGI_t argi)
+{
+    int nvals = 0;
+    if (argi)
+       nvals = argi->nvals;
+    return nvals;
+}
+
+int argvCount(const ARGV_t argv)
 {
     int argc = 0;
     if (argv)
@@ -92,7 +100,7 @@ ARGV_t argvSearch(ARGV_t argv, ARGstr_t val,
     return bsearch(&val, argv, argvCount(argv), sizeof(*argv), compar);
 }
 
-int argiAdd(/*@out@*/ ARGI_t * argip, unsigned ix, int val)
+int argiAdd(/*@out@*/ ARGI_t * argip, int ix, int val)
 {
     ARGI_t argi;
 
@@ -101,6 +109,8 @@ int argiAdd(/*@out@*/ ARGI_t * argip, unsigned ix, int val)
     if (*argip == NULL)
        *argip = xcalloc(1, sizeof(**argip));
     argi = *argip;
+    if (ix < 0)
+       ix = argi->nvals;
     if (ix >= argi->nvals) {
        argi->vals = xrealloc(argi->vals, (ix + 1) * sizeof(*argi->vals));
        memset(argi->vals + argi->nvals, 0,
index 607be34..f54f0ab 100644 (file)
@@ -48,6 +48,13 @@ ARGV_t argvFree(/*@only@*/ /*@null@*/ ARGV_t argv)
        /*@modifies argv @*/;
 
 /**
+ * Return no. of elements in argi array.
+ * @param argi         argi array
+ */
+int argiCount(/*@null@*/ const ARGI_t argi)
+       /*@*/;
+
+/**
  * Return no. of elements in argv array.
  * @param argv         argv array
  */
@@ -82,11 +89,11 @@ ARGV_t argvSearch(ARGV_t argv, ARGstr_t val,
 /**
  * Add an int to an argi array.
  * @retval *argip      argi array
- * @parm ix            argi array index
+ * @parm ix            argi array index (or -1 to append)
  * @param val          int arg to add
  * @return             0 always
  */
-int argiAdd(/*@out@*/ ARGI_t * argip, unsigned ix, int val)
+int argiAdd(/*@out@*/ ARGI_t * argip, int ix, int val)
        /*@modifies *argip @*/;
 
 /**
index c9d02c5..b70c0a2 100644 (file)
@@ -5,8 +5,15 @@
 #include <argv.h>
 #include <rpmfc.h>
 
+#if HAVE_GELF_H
+#include <gelf.h>
+#endif
+
 #include "debug.h"
 
+/*@notchecked@*/
+int _rpmfc_debug;
+
 /**
  */
 /*@unchecked@*/ /*@observer@*/
@@ -88,10 +95,6 @@ static struct rpmfcTokens_s rpmfcTokens[] = {
   { NULL,                      RPMFC_BLACK }
 };
 
-/*@unchecked@*/
-static int fcolorIgnore =
-    (RPMFC_ELF32|RPMFC_ELF64|RPMFC_DIRECTORY|RPMFC_LIBRARY|RPMFC_ARCHIVE|RPMFC_FONT|RPMFC_SCRIPT|RPMFC_IMAGE|RPMFC_WHITE);
-
 int rpmfcColoring(const char * fmstr)
 {
     rpmfcToken fct;
@@ -109,36 +112,70 @@ int rpmfcColoring(const char * fmstr)
 
 void rpmfcPrint(const char * msg, rpmfc fc, FILE * fp)
 {
-    int ac = 0;
     int fcolor;
-    int ix;
+    int ndx;
+    int cx;
+    int dx;
+    int fx;
+
+int nprovides;
+int nrequires;
 
     if (fp == NULL) fp = stderr;
 
     if (msg)
        fprintf(fp, "===================================== %s\n", msg);
 
+nprovides = argvCount(fc->provides);
+nrequires = argvCount(fc->requires);
+
     if (fc)
-    while (1) {
-       if (fc->fn[ac] == NULL)
-           break;
-       if (ac >= fc->fdictx->nvals)
-           break;
-       ix = fc->fdictx->vals[ac];
-       if (ix < 0)
-           break;
+    for (fx = 0; fx < fc->nfiles; fx++) {
+assert(fx < fc->fcdictx->nvals);
+       cx = fc->fcdictx->vals[fx];
+assert(fx < fc->fcolor->nvals);
+       fcolor = fc->fcolor->vals[fx];
+
+       fprintf(fp, "%3d %s", fx, fc->fn[fx]);
+       if (fcolor != RPMFC_BLACK)
+               fprintf(fp, "\t0x%x", fc->fcolor->vals[fx]);
+       else
+               fprintf(fp, "\t%s", fc->cdict[cx]);
+       fprintf(fp, "\n");
+
+       if (fc->fddictx == NULL || fc->fddictn == NULL)
+           continue;
 
-       fcolor = fc->fcolor->vals[ac];
-       if (ix > 0 && !(fcolor & fcolorIgnore)) {
-           fprintf(fp, "%3d %s", ix, fc->fn[ac]);
-           if (fcolor != RPMFC_BLACK)
-               fprintf(fp, "\t0x%x", fc->fcolor->vals[ac]);
-           else
-               fprintf(fp, "\t%s", fc->dict[ix]);
-           fprintf(fp, "\n");
+assert(fx < fc->fddictx->nvals);
+       dx = fc->fddictx->vals[fx];
+assert(fx < fc->fddictn->nvals);
+       ndx = fc->fddictn->vals[fx];
+
+       while (ndx-- > 0) {
+           const char * depval;
+           char deptype;
+           int ix;
+
+           ix = fc->ddictx->vals[dx++];
+           deptype = ((ix >> 24) & 0xff);
+           ix &= 0x00ffffff;
+           depval = NULL;
+           switch (deptype) {
+           default:
+assert(depval);
+               break;
+           case 'P':
+assert(ix < nprovides);
+               depval = fc->provides[ix];
+               break;
+           case 'R':
+assert(ix < nrequires);
+               depval = fc->requires[ix];
+               break;
+           }
+           if (depval)
+               fprintf(fp, "\t%c %s\n", deptype, depval);
        }
-
-       ac++;
     }
 }
 
@@ -146,9 +183,15 @@ rpmfc rpmfcFree(rpmfc fc)
 {
     if (fc) {
        fc->fn = argvFree(fc->fn);
-       fc->fdictx = argiFree(fc->fdictx);
+       fc->fcdictx = argiFree(fc->fcdictx);
        fc->fcolor = argiFree(fc->fcolor);
-       fc->dict = argvFree(fc->dict);
+       fc->cdict = argvFree(fc->cdict);
+       fc->fddictx = argiFree(fc->fddictx);
+       fc->fddictn = argiFree(fc->fddictn);
+       fc->ddict = argvFree(fc->ddict);
+       fc->ddictx = argiFree(fc->ddictx);
+       fc->provides = argvFree(fc->provides);
+       fc->requires = argvFree(fc->requires);
     }
     fc = _free(fc);
     return NULL;
@@ -160,43 +203,338 @@ rpmfc rpmfcNew(void)
     return fc;
 }
 
-static int rpmfcELF(rpmfc fc)
+static int rpmfcSCRIPT(rpmfc fc)
 {
+    const char * fn = fc->fn[fc->ix];;
+    char deptype;
+    char buf[BUFSIZ];
+    FILE * fp;
+    char * s, * se;
+    size_t ns;
+    char * t;
+    int i;
+    struct stat sb, * st = &sb;;
+    int xx;
+
+    /* Only executable scripts are searched. */
+    if (stat(fn, st) < 0)
+       return -1;
+    if (!(st->st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
+       return 0;
+
+    fp = fopen(fn, "r");
+    if (fp == NULL || ferror(fp)) {
+       if (fp) fclose(fp);
+       return -1;
+    }
+
+    /* Look for #! interpreter in first 10 lines. */
+    deptype = 'R';
+    for (i = 0; i < 10; i++) {
+
+       s = fgets(buf, sizeof(buf) - 1, fp);
+       if (s == NULL || ferror(fp) || feof(fp))
+           break;
+       s[sizeof(buf)-1] = '\0';
+       ns = strlen(s);
+       if (!(s[0] == '#' && s[1] == '!'))
+           continue;
+       s += 2;
+       while (*s && strchr(" \t\n\r", *s) != NULL)
+           s++;
+       if (*s == '\0')
+           continue;
+       if (*s != '/')
+           continue;
+
+       for (se = s+1; *se; se++) {
+           if (strchr(" \t\n\r", *se) != NULL)
+               break;
+       }
+       *se = '\0';
+
+       /* Add to package requires. */
+       if (argvSearch(fc->requires, s, NULL) == NULL) {
+           xx = argvAdd(&fc->requires, s);
+           xx = argvSort(fc->requires, NULL);
+       }
+
+       /* Add to file dependencies. */
+       if (ns < (sizeof(buf) - ns - 64)) {
+           t = se + 1;
+           *t = '\0';
+           sprintf(t, "%08d%c %s", fc->ix, deptype, s);
+           if (argvSearch(fc->ddict, t, NULL) == NULL) {
+               xx = argvAdd(&fc->ddict, t);
+               xx = argvSort(fc->ddict, NULL);
+           }
+       }
+       break;
+    }
+
+    (void) fclose(fp);
     return 0;
 }
 
-static int rpmfcSCRIPT(rpmfc fc)
+#define        _permitstr(_a, _b)      (!strncmp((_a), (_b), sizeof(_b)-1))
+static int rpmfcELFpermit(const char *s)
+{
+    if (_permitstr(s, "GLIBCPP_"))     return 1;
+    if (_permitstr(s, "GLIBC_"))       return 1;
+    if (_permitstr(s, "GCC_"))         return 1;
+    if (_permitstr(s, "REDHAT_"))      return 1;
+    return 0;
+}
+#undef _permitstr
+
+static int rpmfcELF(rpmfc fc)
 {
+#if HAVE_GELF_H && HAVE_LIBELF
+    const char * fn = fc->fn[fc->ix];;
+    Elf * elf;
+    Elf_Scn * scn;
+    Elf_Data * data;
+    GElf_Ehdr ehdr_mem, * ehdr;
+    GElf_Shdr shdr_mem, * shdr;
+    GElf_Verdef def_mem, * def;
+    GElf_Verneed need_mem, * need;
+    GElf_Dyn dyn_mem, * dyn;
+    unsigned int auxoffset;
+    unsigned int offset;
+    int fdno;
+    int cnt2;
+    int cnt;
+    char buf[BUFSIZ];
+    const char * s;
+    char deptype;
+    const char * soname = NULL;
+    const char * depval;
+    size_t ns;
+    char * t;
+    int xx;
+
+    fdno = open(fn, O_RDONLY);
+    if (fdno < 0)
+       return fdno;
+
+    (void) elf_version(EV_CURRENT);
+
+    elf = NULL;
+    if ((elf = elf_begin (fdno, ELF_C_READ, NULL)) == NULL
+     || elf_kind(elf) != ELF_K_ELF
+     || (ehdr = gelf_getehdr(elf, &ehdr_mem)) == NULL
+     || !(ehdr->e_type == ET_DYN || ehdr->e_type == ET_EXEC))
+       goto exit;
+
+    /*@-branchstate -uniondef @*/
+    scn = NULL;
+    while ((scn = elf_nextscn(elf, scn)) != NULL) {
+       shdr = gelf_getshdr(scn, &shdr_mem);
+       if (shdr == NULL)
+           break;
+
+       soname = _free(soname);
+       switch (shdr->sh_type) {
+       default:
+           continue;
+           /*@switchbreak@*/ break;
+       case SHT_GNU_verdef:
+           deptype = 'P';
+           data = NULL;
+           while ((data = elf_getdata (scn, data)) != NULL) {
+               offset = 0;
+               for (cnt = shdr->sh_info; --cnt >= 0; ) {
+               
+                   def = gelf_getverdef (data, offset, &def_mem);
+                   if (def == NULL)
+                       break;
+                   auxoffset = offset + def->vd_aux;
+                   for (cnt2 = def->vd_cnt; --cnt2 >= 0; ) {
+                       GElf_Verdaux aux_mem, * aux;
+
+                       aux = gelf_getverdaux (data, auxoffset, &aux_mem);
+                       if (aux == NULL)
+                           break;
+
+                       s = elf_strptr(elf, shdr->sh_link, aux->vda_name);
+                       if (!rpmfcELFpermit(s)) {
+                           soname = _free(soname);
+                           soname = xstrdup(s);
+                           auxoffset += aux->vda_next;
+                           continue;
+                       }
+                       ns = strlen(s);
+
+                       t = buf;
+                       *t = '\0';
+                       sprintf(t, "%08d%c ", fc->ix, deptype);
+                       t += strlen(t);
+                       depval = t;
+                       t = stpcpy( stpcpy( stpcpy( stpcpy(t, soname), "("), s), ")");
+
+                       /* Add to package provides. */
+                       if (argvSearch(fc->provides, depval, NULL) == NULL) {
+                           xx = argvAdd(&fc->provides, depval);
+                           xx = argvSort(fc->provides, NULL);
+                       }
+
+                       /* Add to file dependencies. */
+                       if (ns < (sizeof(buf)-64)) {
+                           if (argvSearch(fc->ddict, buf, NULL) == NULL) {
+                               xx = argvAdd(&fc->ddict, buf);
+                               xx = argvSort(fc->ddict, NULL);
+                           }
+                       }
+
+                       auxoffset += aux->vda_next;
+                   }
+                   offset += def->vd_next;
+               }
+           }
+           /*@switchbreak@*/ break;
+       case SHT_GNU_verneed:
+           deptype = 'R';
+           data = NULL;
+           while ((data = elf_getdata (scn, data)) != NULL) {
+               offset = 0;
+               for (cnt = shdr->sh_info; --cnt >= 0; ) {
+                   need = gelf_getverneed (data, offset, &need_mem);
+                   if (need == NULL)
+                       break;
+
+                   s = elf_strptr(elf, shdr->sh_link, need->vn_file);
+                   soname = _free(soname);
+                   soname = xstrdup(s);
+                   auxoffset = offset + need->vn_aux;
+                   for (cnt2 = need->vn_cnt; --cnt2 >= 0; ) {
+                       GElf_Vernaux aux_mem, * aux;
+
+                       aux = gelf_getvernaux (data, auxoffset, &aux_mem);
+                       if (aux == NULL)
+                           break;
+
+                       s = elf_strptr(elf, shdr->sh_link, aux->vna_name);
+                       if (!rpmfcELFpermit(s)) {
+                           auxoffset += aux->vna_next;
+                           continue;
+                       }
+                       ns = strlen(s);
+
+                       if (soname == NULL)
+                           soname = xstrdup("libc.so.6");
+
+                       t = buf;
+                       *t = '\0';
+                       sprintf(t, "%08d%c ", fc->ix, deptype);
+                       t += strlen(t);
+                       depval = t;
+                       t = stpcpy( stpcpy( stpcpy( stpcpy(t, soname), "("), s), ")");
+
+                       /* Add to package requires. */
+                       if (argvSearch(fc->requires, depval, NULL) == NULL) {
+                           xx = argvAdd(&fc->requires, depval);
+                           xx = argvSort(fc->requires, NULL);
+                       }
+
+                       /* Add to file dependencies. */
+                       if (ns < (sizeof(buf)-64)) {
+                           if (argvSearch(fc->ddict, buf, NULL) == NULL) {
+                               xx = argvAdd(&fc->ddict, buf);
+                               xx = argvSort(fc->ddict, NULL);
+                           }
+                       }
+
+                       auxoffset += aux->vna_next;
+                   }
+                   offset += need->vn_next;
+               }
+           }
+           /*@switchbreak@*/ break;
+       case SHT_DYNAMIC:
+           data = NULL;
+           while ((data = elf_getdata (scn, data)) != NULL) {
+               for (cnt = 0; cnt < (shdr->sh_size / shdr->sh_entsize); ++cnt) {
+                   dyn = gelf_getdyn (data, cnt, &dyn_mem);
+                   t = buf;
+                   *t = '\0';
+                   s = NULL;
+                   switch (dyn->d_tag) {
+                   default:
+                       /*@innercontinue@*/ continue;
+                       /*@notreached@*/ break;
+                   case DT_NEEDED:
+                       /* Add to package requires. */
+                       deptype = 'R';
+                       s = elf_strptr(elf, shdr->sh_link, dyn->d_un.d_val);
+                       if (argvSearch(fc->requires, s, NULL) == NULL) {
+                           xx = argvAdd(&fc->requires, s);
+                           xx = argvSort(fc->requires, NULL);
+                       }
+                       /*@switchbreak@*/ break;
+                   case DT_SONAME:
+                       /* Add to package provides. */
+                       deptype = 'P';
+                       s = elf_strptr(elf, shdr->sh_link, dyn->d_un.d_val);
+                       if (argvSearch(fc->provides, s, NULL) == NULL) {
+                           xx = argvAdd(&fc->provides, s);
+                           xx = argvSort(fc->provides, NULL);
+                       }
+                       /*@switchbreak@*/ break;
+                   }
+                   if (s == NULL)
+                       continue;
+                   ns = strlen(s);
+                   /* Add to file dependencies. */
+                   if (ns < (sizeof(buf)-64)) {
+                       sprintf(t, "%08d%c ", fc->ix, deptype);
+                       t += strlen(t);
+                       t = stpcpy(t, s);
+                       if (argvSearch(fc->ddict, buf, NULL) == NULL) {
+                           xx = argvAdd(&fc->ddict, buf);
+                           xx = argvSort(fc->ddict, NULL);
+                       }
+                   }
+               }
+           }
+           /*@switchbreak@*/ break;
+       }
+    }
+    /*@=branchstate =uniondef @*/
+
+exit:
+    soname = _free(soname);
+    if (elf) (void) elf_end(elf);
+    xx = close(fdno);
     return 0;
+#else
+    return -1;
+#endif
 }
 
-int rpmfcClassify(rpmfc *fcp, ARGV_t argv)
+int rpmfcClassify(rpmfc fc, ARGV_t argv)
 {
-    rpmfc fc;
     char buf[BUFSIZ];
     ARGV_t dav;
+    ARGV_t av;
     const char * s, * se;
     char * t;
     int fcolor;
     int xx;
-    int fknown, fwhite;
-
 
-    if (fcp == NULL || argv == NULL)
+    if (fc == NULL || argv == NULL)
        return 0;
 
-    if (*fcp == NULL)
-       *fcp = rpmfcNew();
-    fc = *fcp;
+    fc->nfiles = argvCount(argv);
+
+    xx = argiAdd(&fc->fddictx, fc->nfiles-1, 0);
+    xx = argiAdd(&fc->fddictn, fc->nfiles-1, 0);
 
     /* Set up the file class dictionary. */
-    xx = argvAdd(&fc->dict, "");
-    xx = argvAdd(&fc->dict, "directory");
+    xx = argvAdd(&fc->cdict, "");
+    xx = argvAdd(&fc->cdict, "directory");
 
-/*@-temptrans@*/
-    fc->av = argv;
-/*@=temptrans@*/
-    while ((s = *fc->av++) != NULL) {
+    av = argv;
+    while ((s = *av++) != NULL) {
        se = s;
        while (*se && !(se[0] == ':' && se[1] == ' '))
            se++;
@@ -213,20 +551,18 @@ int rpmfcClassify(rpmfc *fcp, ARGV_t argv)
        if (fcolor == RPMFC_WHITE || !(fcolor & RPMFC_INCLUDE))
            continue;
 
-       dav = argvSearch(fc->dict, se, NULL);
+       dav = argvSearch(fc->cdict, se, NULL);
        if (dav == NULL) {
-           xx = argvAdd(&fc->dict, se);
-           xx = argvSort(fc->dict, NULL);
+           xx = argvAdd(&fc->cdict, se);
+           xx = argvSort(fc->cdict, NULL);
        }
     }
 
     /* Classify files. */
-/*@-kepttrans@*/
-    fc->av = argv;
-/*@=kepttrans@*/
     fc->ix = 0;
-    fknown = 0;
-    while ((s = *fc->av++) != NULL) {
+    fc->fknown = 0;
+    av = argv;
+    while ((s = *av++) != NULL) {
        se = s;
        while (*se && !(se[0] == ':' && se[1] == ' '))
            se++;
@@ -244,32 +580,103 @@ int rpmfcClassify(rpmfc *fcp, ARGV_t argv)
        if (*se == '\0')
            return -1;
 
-       dav = argvSearch(fc->dict, se, NULL);
+       dav = argvSearch(fc->cdict, se, NULL);
        if (dav) {
-           xx = argiAdd(&fc->fdictx, fc->ix, (dav - fc->dict));
-           fknown++;
+           xx = argiAdd(&fc->fcdictx, fc->ix, (dav - fc->cdict));
+           fc->fknown++;
        } else {
-           xx = argiAdd(&fc->fdictx, fc->ix, 0);
-           fwhite++;
+           xx = argiAdd(&fc->fcdictx, fc->ix, 0);
+           fc->fwhite++;
        }
 
        fcolor = rpmfcColoring(se);
        xx = argiAdd(&fc->fcolor, fc->ix, fcolor);
 
+#ifdef DYING
        if (fcolor & RPMFC_ELF) {
            xx = rpmfcELF(fc);
        } else if (fcolor & RPMFC_SCRIPT) {
            xx = rpmfcSCRIPT(fc);
        }
+#endif
 
        fc->ix++;
     }
-    fc->av = NULL;
 
-/*@-modfilesys@*/
-sprintf(buf, "final: files %d dict[%d] %d%%", argvCount(fc->fn), argvCount(fc->dict), ((100 * fknown)/fc->ix));
-rpmfcPrint(buf, fc, NULL);
-/*@=modfilesys@*/
+    return 0;
+}
+
+typedef struct rpmfcApplyTbl_s {
+    int (*func) (rpmfc fc);
+    int colormask;
+} * rpmfcApplyTbl;
+
+static struct rpmfcApplyTbl_s rpmfcApplyTable[] = {
+    { rpmfcELF,                RPMFC_ELF },
+    { rpmfcSCRIPT,     RPMFC_SCRIPT },
+    { NULL, 0 }
+};
+
+int rpmfcApply(rpmfc fc)
+{
+    const char * s;
+    char * se;
+    ARGV_t dav, davbase;
+    rpmfcApplyTbl fcat;
+    char deptype;
+    int fcolor;
+    int nddict;
+    int previx;
+    unsigned int val;
+    int ix;
+    int i;
+    int xx;
+
+    /* Generate package and per-file dependencies. */
+    for (fc->ix = 0; fc->fn[fc->ix] != NULL; fc->ix++) {
+       fcolor = fc->fcolor->vals[fc->ix];
+       for (fcat = rpmfcApplyTable; fcat->func != NULL; fcat++) {
+           if (!(fcolor & fcat->colormask))
+               continue;
+           xx = (*fcat->func) (fc);
+       }
+    }
+
+    /* Generate per-file indices into package dependencies. */
+    nddict = argvCount(fc->ddict);
+    previx = -1;
+    for (i = 0; i < nddict; i++) {
+       s = fc->ddict[i];
+       ix = strtol(s, &se, 10);
+assert(se);
+       deptype = *se++;
+       se++;
+       
+       davbase = NULL;
+       switch (deptype) {
+       default:
+assert(davbase);
+           break;
+       case 'P':       
+           davbase = fc->provides;
+           break;
+       case 'R':
+           davbase = fc->requires;
+           break;
+       }
+
+       dav = argvSearch(davbase, se, NULL);
+assert(dav);
+       val = (deptype << 24) | ((dav - davbase) & 0x00ffffff);
+       xx = argiAdd(&fc->ddictx, -1, val);
+
+       if (previx != ix) {
+           previx = ix;
+           xx = argiAdd(&fc->fddictx, ix, argiCount(fc->ddictx)-1);
+       }
+       if (fc->fddictn && fc->fddictn->vals)
+           fc->fddictn->vals[ix]++;
+    }
 
     return 0;
 }
index 3f68cc7..dfd4352 100644 (file)
@@ -1,19 +1,28 @@
 #ifndef _H_RPMFC_
 #define _H_RPMFC_
 
+/*@notchecked@*/
+extern int _rpmfc_debug;
+
 typedef struct rpmfc_s * rpmfc;
 
 struct rpmfc_s {
-    ARGV_t av;         /*!< file(1) output lines */
-    int ac;            /*!< no. of lines */
-    int ix;            /*!< current lineno */
-    ARGV_t fn;         /*!< file names */
-    ARGI_t fcolor;     /*!< file colors */
-    ARGI_t fdictx;     /*!< file class dictionary indices */
-    ARGV_t dict;       /*!< file class dictionary */
+    int nfiles;                /*!< no. of files */
+    int fknown;                /*!< no. of classified files */
+    int fwhite;                /*!< no. of "white" files */
+    int ix;            /*!< current file index */
+    ARGV_t fn;         /*!< (#files) file names */
+    ARGI_t fcolor;     /*!< (#files) file colors */
+    ARGI_t fcdictx;    /*!< (#files) file class dictionary indices */
+    ARGI_t fddictx;    /*!< (#files) file depends dictionary start */
+    ARGI_t fddictn;    /*!< (#files) file depends dictionary no. entries */
+    ARGV_t cdict;      /*!< (#classes) file class dictionary */
+    ARGV_t ddict;      /*!< (#dependencies) file depends dictionary */
+    ARGI_t ddictx;     /*!< (#dependencies) file->dependency mapping */
+    ARGV_t provides;   /*!< (#provides) package provides */
+    ARGV_t requires;   /*!< (#requires) package requires */
 };
 
-
 enum FCOLOR_e {
     RPMFC_BLACK                        = 0,
     RPMFC_ELF32                        = (1 <<  0),
@@ -38,6 +47,12 @@ enum FCOLOR_e {
     RPMFC_IMAGE                        = (1 << 22),
     RPMFC_MANPAGE              = (1 << 23),
 
+    RPMFC_PERL                 = (1 << 24),
+    RPMFC_JAVA                 = (1 << 25),
+    RPMFC_PYTHON               = (1 << 26),
+    RPMFC_PHP                  = (1 << 27),
+    RPMFC_TCL                  = (1 << 28),
+
     RPMFC_WHITE                        = (1 << 29),
     RPMFC_INCLUDE              = (1 << 30),
     RPMFC_ERROR                        = (1 << 31)
@@ -78,10 +93,17 @@ rpmfc rpmfcNew(void)
        /*@*/;
 
 /**
+ * Build file class dictionary and mappings.
  */
-int rpmfcClassify(/*@out@*/ rpmfc *fcp, ARGV_t argv)
+int rpmfcClassify(rpmfc fc, ARGV_t argv)
        /*@modifies *fcp @*/;
 
+/**
+ * BUild file/package dependency dictionary and mappings.
+ */
+int rpmfcApply(rpmfc fc)
+       /*@modifies fc @*/;
+
 #ifdef __cplusplus
 }
 #endif
index 0600c38..1b1172a 100644 (file)
 #include <argv.h>
 #include <rpmfc.h>
 
-
-#if HAVE_GELF_H
-
-#include <gelf.h>
-
-#endif
-
 #include "debug.h"
 
-static int rpmfcELF(rpmfc fc)
-{
-#if HAVE_GELF_H && HAVE_LIBELF
-    const char * fn = fc->fn[fc->ix];;
-    Elf * elf;
-    Elf_Scn * scn;
-    Elf_Data * data;
-    GElf_Ehdr ehdr_mem, * ehdr;
-    GElf_Shdr shdr_mem, * shdr;
-    GElf_Verdef def_mem, * def;
-    GElf_Verneed need_mem, * need;
-    GElf_Dyn dyn_mem, * dyn;
-    unsigned int auxoffset;
-    unsigned int offset;
-    int fdno;
-    int cnt2;
-    int cnt;
-
-fprintf(stderr, "*** %s\n", fn);
-    fdno = open(fn, O_RDONLY);
-    if (fdno < 0)
-       return fdno;
-
-    (void) elf_version(EV_CURRENT);
-
-    elf = NULL;
-    if ((elf = elf_begin (fdno, ELF_C_READ, NULL)) == NULL
-     || elf_kind(elf) != ELF_K_ELF
-     || (ehdr = gelf_getehdr(elf, &ehdr_mem)) == NULL
-     || !(ehdr->e_type == ET_DYN || ehdr->e_type == ET_EXEC))
-       goto exit;
-
-    /*@-branchstate -uniondef @*/
-    scn = NULL;
-    while ((scn = elf_nextscn(elf, scn)) != NULL) {
-       shdr = gelf_getshdr(scn, &shdr_mem);
-       if (shdr == NULL)
-           break;
-
-       switch (shdr->sh_type) {
-       default:
-           continue;
-           /*@switchbreak@*/ break;
-       case SHT_GNU_verdef:
-fprintf(stderr, "\tsection %s\n", elf_strptr(elf, ehdr->e_shstrndx, shdr->sh_name));
-           data = NULL;
-           while ((data = elf_getdata (scn, data)) != NULL) {
-               offset = 0;
-               for (cnt = shdr->sh_info; --cnt >= 0; ) {
-               
-                   def = gelf_getverdef (data, offset, &def_mem);
-                   if (def == NULL)
-                       break;
-                   auxoffset = offset + def->vd_aux;
-                   for (cnt2 = def->vd_cnt; --cnt2 >= 0; ) {
-                       GElf_Verdaux aux_mem, * aux;
-
-                       aux = gelf_getverdaux (data, auxoffset, &aux_mem);
-                       if (aux == NULL)
-                           break;
-fprintf(stderr, "\t\tverdef: %s\n", elf_strptr(elf, shdr->sh_link, aux->vda_name));
-
-                       auxoffset += aux->vda_next;
-                   }
-                   offset += def->vd_next;
-               }
-           }
-           /*@switchbreak@*/ break;
-       case SHT_GNU_verneed:
-fprintf(stderr, "\tsection %s\n", elf_strptr(elf, ehdr->e_shstrndx, shdr->sh_name));
-           data = NULL;
-           while ((data = elf_getdata (scn, data)) != NULL) {
-               offset = 0;
-               for (cnt = shdr->sh_info; --cnt >= 0; ) {
-                   need = gelf_getverneed (data, offset, &need_mem);
-                   if (need == NULL)
-                       break;
-                   auxoffset = offset + need->vn_aux;
-                   for (cnt2 = need->vn_cnt; --cnt2 >= 0; ) {
-                       GElf_Vernaux aux_mem, * aux;
-
-                       aux = gelf_getvernaux (data, auxoffset, &aux_mem);
-                       if (aux == NULL)
-                           break;
-fprintf(stderr, "\t\tverneed: %s\n", elf_strptr(elf, shdr->sh_link, aux->vna_name));
-
-                       auxoffset += aux->vna_next;
-                   }
-                   offset += need->vn_next;
-               }
-           }
-           /*@switchbreak@*/ break;
-       case SHT_DYNAMIC:
-fprintf(stderr, "\tsection %s\n", elf_strptr(elf, ehdr->e_shstrndx, shdr->sh_name));
-           data = NULL;
-           while ((data = elf_getdata (scn, data)) != NULL) {
-               for (cnt = 0; cnt < (shdr->sh_size / shdr->sh_entsize); ++cnt) {
-                   dyn = gelf_getdyn (data, cnt, &dyn_mem);
-                   switch (dyn->d_tag) {
-                   default:
-                       /*@innercontinue@*/ continue;
-                       /*@notreached@*/ break;
-                   case DT_NEEDED:
-fprintf(stderr, "\t\tneeded: %s\n", elf_strptr(elf, shdr->sh_link, dyn->d_un.d_val));
-                       /*@switchbreak@*/ break;
-                   case DT_SONAME:
-fprintf(stderr, "\t\tsoname: %s\n", elf_strptr(elf, shdr->sh_link, dyn->d_un.d_val));
-                       /*@switchbreak@*/ break;
-                   }
-               }
-           }
-           /*@switchbreak@*/ break;
-       }
-    }
-    /*@=branchstate =uniondef @*/
-
-exit:
-    if (elf) (void) elf_end(elf);
-    return 0;
-#else
-    return -1;
-#endif
-}
+static int print_provides;
+static int print_requires;
 
 static struct poptOption optionsTable[] = {
 
@@ -143,6 +15,14 @@ static struct poptOption optionsTable[] = {
        N_("Common options for all rpm modes and executables:"),
        NULL }, 
 
+ { "rpmfcdebug", 'd', POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN, &_rpmfc_debug, -1,
+        NULL, NULL },
+
+ { "provides", 'P', POPT_ARG_VAL, &print_provides, -1,
+        NULL, NULL },
+ { "requires", 'R', POPT_ARG_VAL, &print_requires, -1,
+        NULL, NULL },
+
    POPT_AUTOALIAS
    POPT_AUTOHELP
    POPT_TABLEEND
@@ -162,7 +42,7 @@ main(int argc, char *const argv[])
     const char * s;
     int ec = 1;
     int xx;
-int fcolor;
+char buf[BUFSIZ];
 
     optCon = rpmcliInit(argc, argv, optionsTable);
     if (optCon == NULL)
@@ -194,18 +74,25 @@ int fcolor;
     xx = argvSplit(&xav, getStringBuf(sb), "\n");
     sb = freeStringBuf(sb);
 
-    xx = argvSort(xav, argvCmp);
+    xx = argvSort(xav, NULL);
+
+    /* Build file class dictionary. */
+    fc = rpmfcNew();
+    xx = rpmfcClassify(fc, xav);
+
+    /* Build file/package dependency dictionary. */
+    xx = rpmfcApply(fc);
+
+if (_rpmfc_debug) {
+sprintf(buf, "final: files %d cdict[%d] %d%% ddictx[%d]", fc->nfiles, argvCount(fc->cdict), ((100 * fc->fknown)/fc->nfiles), argiCount(fc->ddictx));
+rpmfcPrint(buf, fc, NULL);
+}
 
-    fc = NULL;
-    xx = rpmfcClassify(&fc, xav);
+    if (print_provides)
+       argvPrint(NULL, fc->provides, stdout);
+    if (print_requires)
+       argvPrint(NULL, fc->requires, stdout);
 
-    for (fc->ix = 0; fc->fn[fc->ix] != NULL; fc->ix++) {
-       fcolor = fc->fcolor->vals[fc->ix];
-       if (fcolor & RPMFC_ELF) {
-           xx = rpmfcELF(fc);
-           continue;
-       }
-    }
     fc = rpmfcFree(fc);
 
     xav = argvFree(xav);