]> pd.if.org Git - zpackage/commitdiff
add zpm-search to look for packages and libraries
authorNathan Wagner <nw@hydaspes.if.org>
Tue, 13 Nov 2018 04:51:51 +0000 (04:51 +0000)
committerNathan Wagner <nw@hydaspes.if.org>
Tue, 13 Nov 2018 04:51:51 +0000 (04:51 +0000)
Makefile
lib/dbquery.c
lib/findpkg.c
lib/jsw/jsw_atree.h
lib/jsw/jsw_hlib.c
lib/vercmp.c
lib/zpm.c
zpm-search.c [new file with mode: 0644]
zpm.h

index d018fd3219b6b8203900c26d5b443abae98a45b5..e845acc1ba1a39a68c1d88dce94ddabf10def339 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -29,7 +29,7 @@ curdir=$(shell pwd)
 ZPKGBIN=zpm-addfile zpm-extract zpm-init zpm-vercmp zpm-stat zpm-hash \
        zpm-findpkg zpm-shell zpm-soneed zpm-foreach-path zpm-parse \
        zpm-script zpm-soname zpm-syncfs zpm-packagehash zpm-verify \
-       zpm-elftype zpm-quote zpm-note
+       zpm-elftype zpm-quote zpm-note zpm-search
 
 SCRIPTS=zpm zpm-install zpm-merge zpm-list zpm-preserve zpm-test zpm-log \
        zpm-contents zpm-uninstall zpm-pathmod zpm-rmpackage zpm-newpackage \
@@ -143,6 +143,9 @@ zpm-foreach-path: zpm-foreach-path.o libzpm.a sqlite/sqlite3.h
 zpm-findpkg: zpm-findpkg.o libzpm.a
        $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lzpm -lelf
 
+zpm-search: zpm-search.o libzpm.a
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lzpm -lelf
+
 zpm-note: zpm-note.o libzpm.a
        $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lzpm -lelf
 
index cba95378ae2a258c8351b9f3ac07191bc46ce337..11131645d9b4d388c7229665515b588492a4164e 100644 (file)
@@ -35,6 +35,7 @@ sqlite3_stmt *zpm_dbqueryv(struct zpm *zpm, char *query, va_list args) {
        rv = sqlite3_prepare_v2(db, sql, strlen(sql), &st, NULL);
        if (rv != SQLITE_OK) {
                SQLERROR(sqlite3_errmsg(db));
+               fprintf(stderr, "sql (%d): %s\n", rv, sql);
                zpm->error = rv;
                return 0;
        }
@@ -94,11 +95,18 @@ char *zpm_db_string(struct zpm *zpm, char *query, ...) {
 
        rv = sqlite3_step(st);
 
-       if (rv == SQLITE_ROW) {
+       switch (rv) {
+               case SQLITE_ROW:
                result = (char *)sqlite3_column_text(st, 0);
                if (result) {
                        result = strdup(result);
                }
+               break;
+               case SQLITE_DONE: break;
+               default:
+                                 zpm->error = 1;
+                                 zpm_seterror(zpm, "db error: %s", sqlite3_errstr(rv));
+                                 break;
        }
 
        sqlite3_finalize(st);
index cbf70042c413baa4671a36005b83f6987d1459f3..6ea843cbecad5f39d6d5d280055734f23702a78e 100644 (file)
@@ -8,6 +8,7 @@
 #include "zpm.h"
 
 #include "sqlite3.h"
+#include "lib/jsw/jsw_atree.h"
 
 #define DMARK fprintf(stderr, "mark %s %s:%d\n", __FILE__, __func__, __LINE__)
 
@@ -34,11 +35,102 @@ void zpm_sqlite_error(struct zpm *zpm) {
        zpm->errmsg = strdup((const char *)sqlite3_errmsg(zpm->db));
 }
 
+char *zpm_findlib(struct zpm *zpm, char *soname, char *where) {
+       char *select = "select pkgid, package, version, release from packagefiles_status join elflibraries on file = hash";
+       char *group = "order by package, version collate vercmp desc, cast(release as integer)";
+       sqlite3_str *sql;
+       char *query, *pkgid = 0;
+
+       /* null pkgstr find "best" package
+        * best is shortest complete package if any are complete
+        * shortest incomplete if any are incomplete
+        * where more than one version is in those sets, best is
+        * latest as determined by vercmp
+        */
+
+       sql = sqlite3_str_new(zpm->db);
+
+       sqlite3_str_appendall(sql, select);
+       sqlite3_str_appendf(sql, " where soname = %Q", soname);
+
+       if (where) {
+               sqlite3_str_appendall(sql, " and ");
+               sqlite3_str_appendall(sql, where);
+       }
+
+       sqlite3_str_appendall(sql, " ");
+       sqlite3_str_appendall(sql, group);
+       sqlite3_str_appendall(sql, " limit 1;");
+
+       if (sqlite3_str_errcode(sql)) {
+               zpm->error = 1;
+               sqlite3_free(sqlite3_str_finish(sql));
+               return 0;
+       }
+
+       query = sqlite3_str_finish(sql);
+
+       pkgid = zpm_db_string(zpm, query);;
+
+       sqlite3_free(query);
+
+       return pkgid;
+}
+
+int zpm_libraries_needed(struct zpm *zpm, char *pkgid, jsw_atree_t *list) {
+       char *pkglibsneeded = "\
+                              with pkglibs as (\
+                                              select distinct EN.needed as soname, PF.pkgid\
+                                              from elfneeded EN\
+                                              join packagefiles_pkgid PF on PF.hash = EN.file\
+                                              ),\
+                              pkgprovides as (\
+                                              select distinct EL.soname, PF.pkgid\
+                                              from elflibraries EL\
+                                              join packagefiles_pkgid PF on PF.hash = EL.file\
+                                             )\
+                              select distinct PL.soname, PP.soname is not null as selfsatisfied\
+                              from pkglibs PL\
+                              left join pkgprovides PP on PL.pkgid = PP.pkgid and PL.soname = PP.soname\
+                              where PL.pkgid = %Q\
+                              ";
+
+       sqlite3_stmt *st;
+       int count = 0;
+       int rv;
+
+       st = zpm_dbquery(zpm, pkglibsneeded, pkgid);
+
+       while ((rv = sqlite3_step(st)) == SQLITE_ROW) {
+               char *soname;
+               int self;
+
+               soname = (char *)sqlite3_column_text(st, 0);
+               /* TODO check and skip self sats */
+               self = sqlite3_column_int(st,1);
+               if (self) {
+                       continue;
+               }
+               count++;
+
+               /* if it's in needed, we've already looked at this one */
+               if (list && !jsw_afind(list, soname)) {
+                       jsw_ainsert(list, soname);
+               }
+       }
+
+       sqlite3_finalize(st);
+       return count;
+}
+
 char *zpm_findpkg(struct zpm *zpm, char *pkgstr, char *where) {
        char *select = "select pkgid, package, version, release from packages_pkgid";
+#if 0
        char *group = "group by package having max( version||'-'||release collate vercmp) order by length(package), package, version||'-'||release collate vercmp";
-
-//     char *order = "order by package, version collate vercmp, cast(release as integer)";
+#else
+       char *group = "order by package, version collate vercmp desc, cast(release as integer)";
+       //group = "order by package, version , cast(release as integer)";
+#endif
        sqlite3_str *sql;
        char *query, *pkgid = 0;
 
index 54e4fd8ce520da77abd6e49a646939eec3632a5f..f0fe7d9562719f9a2d6fe7ea9fcd2e7153780ee1 100644 (file)
@@ -27,12 +27,18 @@ typedef struct jsw_atree jsw_atree_t;
 typedef struct jsw_atrav jsw_atrav_t;
 
 /* User-defined item handling */
+#if 0
 typedef int   (*cmp_f) ( const void *p1, const void *p2 );
+#endif
 typedef void *(*dup_f) ( void *p );
 typedef void  (*rel_f) ( void *p );
 
 /* Andersson tree functions */
-jsw_atree_t *jsw_anew ( cmp_f cmp, dup_f dup, rel_f rel );
+jsw_atree_t *jsw_anew (
+               int (cmp)(const void *, const void *),
+               void *(dup)(void *),
+               void (rel)(void *)
+               );
 void         jsw_adelete ( jsw_atree_t *tree );
 void        *jsw_afind ( jsw_atree_t *tree, void *data );
 int          jsw_ainsert ( jsw_atree_t *tree, void *data );
index 4cd9f8fce969629f2f4d2f0649f59783c6553ed4..a43140538eb0cdce47da2d8ac214454be65e4bfb 100644 (file)
@@ -8,6 +8,7 @@
 */
 #include <stdlib.h>
 #include <string.h>
+#include <stdio.h>
 
 #include "jsw_hlib.h"
 
@@ -206,8 +207,9 @@ int jsw_hinsert ( jsw_hash_t *htab, void *key, void *item )
   jsw_node_t *new_item;
 
   /* Disallow duplicate keys */
-  if ( jsw_hfind ( htab, key ) != NULL )
+  if ( jsw_hfind ( htab, key ) != NULL ) {
     return 0;
+  }
 
   /* Attempt to create a new item */
   dupkey = htab->keydup ( key );
@@ -215,8 +217,9 @@ int jsw_hinsert ( jsw_hash_t *htab, void *key, void *item )
 
   new_item = new_node ( dupkey, dupitem, NULL );
 
-  if ( new_item == NULL )
+  if ( new_item == NULL ) {
     return 0;
+  }
 
   /* Create a chain if the bucket is empty */
   if ( htab->table[h] == NULL ) {
index e6a415ca4b883bd7196a518fd7f045a3d8e00597..cfc7edd27519e9e1f58924ecbb5ff51e9d937a45 100644 (file)
@@ -101,6 +101,16 @@ int zpm_vercmp(const char *vsa, const char *vsb) {
        int an, bn;
        int cmp;
 
+       if (vsa && !vsb) {
+               return 1;
+       }
+       if (vsb && !vsa) {
+               return -1;
+       }
+       if (!vsa && !vsb) {
+               return 0;
+       }
+
        init_ver(&a, vsa);
        init_ver(&b, vsb);
        do {
index 55118419b705090d928f280d2842a00ff61d3465..3f1cb2b04060dccc3e6cd15c0351a9256c6e131f 100644 (file)
--- a/lib/zpm.c
+++ b/lib/zpm.c
@@ -266,6 +266,14 @@ int zpm_open(struct zpm *zpm, char *path) {
 
        zpm_clearmem(zpm);
 
+       if (!path) {
+               path = getenv("ZPMDB");
+       }
+
+       if (!path) {
+               path = "/var/lib/zpm/local.db";
+       }
+
        rc = sqlite3_open_v2(path, &db, SQLITE_OPEN_READWRITE, NULL);
        if (rc) {
                SQLERROR(sqlite3_errmsg(db));
diff --git a/zpm-search.c b/zpm-search.c
new file mode 100644 (file)
index 0000000..ff6d730
--- /dev/null
@@ -0,0 +1,516 @@
+#define _POSIX_C_SOURCE 200809L
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <glob.h>
+
+#include "zpm.h"
+#include "lib/jsw/jsw_hlib.h"
+#include "lib/jsw/jsw_atree.h"
+
+/*
+ * find packages, and lib deps
+ */
+
+struct pkgloc {
+       char *id;
+       char *file;
+       int info;
+};
+
+char *checkfile(char *pkgstr, char *path) {
+       struct zpm pkgfile;
+       char *pkgid = 0;
+
+       if (!zpm_open(&pkgfile, path)) {
+               return NULL;
+       }
+       
+       pkgid = zpm_findpkg(&pkgfile, pkgstr, "hash is not null");
+       zpm_close(&pkgfile);
+
+       return pkgid;
+}
+
+char *checkfileforlib(char *soname, char *path) {
+       struct zpm pkgfile;
+       char *pkgid = 0;
+
+       if (!zpm_open(&pkgfile, path)) {
+               return NULL;
+       }
+       
+       pkgid = zpm_findlib(&pkgfile, soname, "hash is not null");
+       if (pkgfile.error) {
+               fprintf(stderr, "sql error: %s\n", pkgfile.errmsg);
+       }
+       zpm_close(&pkgfile);
+
+       return pkgid;
+}
+
+int find_lib(char *soname, struct pkgloc *pkg) {
+       char *latest = 0;
+       char *installed = 0, *found = 0;
+       char *pkgfile = 0;
+       int rv;
+       struct zpm localdb;
+
+       if (zpm_open(&localdb, NULL)) {
+               installed = zpm_findlib(&localdb, soname, "status = 'installed'");
+               zpm_close(&localdb);
+
+               if (installed) {
+                       /* we're done, the lib is installed */
+                       return 2;
+               }
+       } else {
+               fprintf(stderr, "can't open localdb\n");
+       }
+
+       glob_t repos;
+       repos.gl_offs = 0;
+       rv = glob("/var/lib/zpm/repos/*.repo", 0, NULL, &repos);
+       switch (rv) {
+               case GLOB_NOSPACE:
+                       fprintf(stderr, "glob no mem\n");
+                       exit(EXIT_FAILURE); break;
+               case GLOB_ABORTED:
+                       fprintf(stderr, "glob abort\n");
+                       exit(EXIT_FAILURE); break;
+               case GLOB_NOMATCH:
+                       break;
+               case 0:
+                                  break;
+               default:
+                                  break;
+       }
+
+       unsigned i;
+       for (i = 0; i < repos.gl_pathc; i++) {
+               found = checkfileforlib(soname, repos.gl_pathv[i]);
+               if (found) {
+                       rv = zpm_vercmp(found, latest);
+                       if (rv == 1) {
+                               latest = found;
+                               free(pkgfile);
+                               pkgfile = strdup(repos.gl_pathv[i]);
+                       }
+               }
+       }
+
+       globfree(&repos);
+       repos.gl_offs = 0;
+
+       char *pkgdir = "/home/zoranix/zrepo/packages";
+       char *pkgglob = 0;
+
+       size_t globlen = strlen(pkgdir)+7;
+       pkgglob = malloc(globlen+1);
+       snprintf(pkgglob, globlen, "%s/*.zpm", pkgdir);
+       rv = glob(pkgglob, 0, NULL, &repos);
+       free(pkgglob);
+
+       switch (rv) {
+               case GLOB_NOSPACE:
+                       exit(EXIT_FAILURE); break;
+               case GLOB_ABORTED:
+                       exit(EXIT_FAILURE); break;
+               case GLOB_NOMATCH: break;
+               case 0:
+                                  break;
+               default:
+                                  break;
+       }
+
+       for (i = 0; i < repos.gl_pathc; i++) {
+               found = checkfileforlib(soname, repos.gl_pathv[i]);
+               if (found) {
+                       rv = zpm_vercmp(found, latest);
+                       if (rv == 1) {
+                               latest = found;
+                               free(pkgfile);
+                               pkgfile = strdup(repos.gl_pathv[i]);
+                       }
+               }
+       }
+
+       if (latest && pkgfile) {
+               pkg->id = strdup(latest);
+               pkg->file = pkgfile;
+               return 1;
+       }
+
+       return 0;
+}
+
+struct pkgloc *find_package(char *pkgstr) {
+       char *latest = 0;
+       char *installed = 0, *found = 0;
+       char *pkgfile;
+       struct pkgloc *pkg = 0;
+       int rv;
+       struct zpm localdb;
+
+       if (zpm_open(&localdb, NULL)) {
+               installed = zpm_findpkg(&localdb, pkgstr, "status = 'installed'");
+               if (installed) {
+                       latest = installed;
+               }
+               found = zpm_findpkg(&localdb, pkgstr, NULL);
+               if (found) {
+                       rv = zpm_vercmp(found, latest);
+                       if (rv == 1) {
+                               latest = found;
+                               pkgfile = localdb.path;
+                       }
+               }
+               zpm_close(&localdb);
+       } else {
+               fprintf(stderr, "can't open localdb\n");
+       }
+
+       glob_t repos;
+       repos.gl_offs = 0;
+       rv = glob("/var/lib/zpm/repos/*.repo", 0, NULL, &repos);
+       switch (rv) {
+               case GLOB_NOSPACE:
+                       fprintf(stderr, "glob no mem\n");
+                       exit(EXIT_FAILURE); break;
+               case GLOB_ABORTED:
+                       fprintf(stderr, "glob abort\n");
+                       exit(EXIT_FAILURE); break;
+               case GLOB_NOMATCH:
+                       break;
+               case 0:
+                                  break;
+               default:
+                                  break;
+       }
+
+       unsigned i;
+       for (i = 0; i < repos.gl_pathc; i++) {
+               found = checkfile(pkgstr, repos.gl_pathv[i]);
+               if (found) {
+                       rv = zpm_vercmp(found, latest);
+                       if (rv == 1) {
+                               latest = found;
+                               pkgfile = repos.gl_pathv[i];
+                       }
+               }
+       }
+
+       globfree(&repos);
+       repos.gl_offs = 0;
+
+       char *pkgdir = "/home/zoranix/zrepo/packages";
+       char *pkgglob = 0;
+
+       size_t globlen = strlen(pkgdir)+strlen(pkgstr)+7;
+       pkgglob = malloc(globlen+1);
+       snprintf(pkgglob, globlen, "%s/%s*.zpm", pkgdir, pkgstr);
+
+       rv = glob(pkgglob, 0, NULL, &repos);
+       switch (rv) {
+               case GLOB_NOSPACE:
+                       exit(EXIT_FAILURE); break;
+               case GLOB_ABORTED:
+                       exit(EXIT_FAILURE); break;
+               case GLOB_NOMATCH: break;
+               case 0:
+                                  break;
+               default:
+                                  break;
+       }
+
+       for (i = 0; i < repos.gl_pathc; i++) {
+               found = checkfile(pkgstr, repos.gl_pathv[i]);
+               if (found) {
+                       rv = zpm_vercmp(found, latest);
+                       if (rv == 1) {
+                               latest = found;
+                               pkgfile = strdup(repos.gl_pathv[i]);
+                       }
+               }
+       }
+
+       if (latest && pkgfile) {
+               pkg = malloc(sizeof *pkg);
+               pkg->id = strdup(latest);
+               pkg->file = pkgfile;
+       }
+
+       return pkg;
+}
+
+char *pkglibsneeded = "\
+with pkglibs as (\
+               select distinct EN.needed as soname, PF.pkgid\
+               from elfneeded EN\
+               join packagefiles_pkgid PF on PF.hash = EN.file\
+               ),\
+     pkgprovides as (\
+                    select distinct EL.soname, PF.pkgid\
+                    from elflibraries EL\
+                    join packagefiles_pkgid PF on PF.hash = EL.file\
+                   )\
+     select distinct PL.soname, PP.soname is not null as selfsatisfied\
+     from pkglibs PL\
+     left join pkgprovides PP on PL.pkgid = PP.pkgid and PL.soname = PP.soname\
+     where PL.pkgid = %Q\
+     ";
+
+void checklibs(jsw_hash_t *check, jsw_hash_t *forlibs, jsw_hash_t *nfound) {
+       char *pkgid = 0, *pkgfile = 0;
+       struct zpm src;
+
+       /* checked_libs is a list of checked sonames
+        * checked is a list of checked packages
+        * needed is list of libs for package
+        */
+       jsw_atree_t *needed = 0, *checked, *checked_libs;
+
+       int libs;
+       jsw_atrav_t *i;
+       char *soname;
+       
+       checked = jsw_anew((cmp_f)strcmp, (dup_f)strdup, (rel_f)free);
+       checked_libs = jsw_anew((cmp_f)strcmp, (dup_f)strdup, (rel_f)free);
+
+       while (jsw_hsize(check) > 0) {
+               free(pkgid);
+               free(pkgfile);
+
+               jsw_hreset(check);
+
+               pkgid = strdup(jsw_hkey(check));
+               pkgfile = strdup(jsw_hitem(check));
+
+               if (!pkgid || !pkgfile) {
+                       break;
+               }
+
+               jsw_herase(check, pkgid);
+
+               if (jsw_afind(checked, pkgid)) {
+                       /* already checked this one */
+                       continue;
+               }
+
+               /* we do this now so we catch self deps */
+               jsw_ainsert(checked, pkgid);
+
+               /* get the libraries needed by this package */
+               if (!zpm_open(&src, pkgfile)) {
+                       fprintf(stderr, "can't zpm open %s\n", pkgfile);
+                       break;
+               }
+
+               if (needed) jsw_adelete(needed);
+               needed = jsw_anew((cmp_f)strcmp, (dup_f)strdup, (rel_f)free);
+               libs = zpm_libraries_needed(&src, pkgid, needed);
+               zpm_close(&src);
+
+               if (libs == 0) {
+                       continue;
+               }
+
+               i = jsw_atnew();
+
+               for (soname = jsw_atfirst(i, needed); soname; soname = jsw_atnext(i)) {
+                       int found;
+                       struct pkgloc pkginfo;
+
+                       /* if it's in checked_libs, we've already looked at this one */
+                       if (jsw_afind(checked_libs, soname)) {
+                               continue;
+                       }
+
+                       /* haven't found this soname */
+                       jsw_ainsert(checked_libs, soname);
+
+                       found = find_lib(soname, &pkginfo);
+                       if (!found) {
+                               if (!jsw_hinsert(nfound, soname, pkgid)) {
+                                       fprintf(stderr,"insert error\n");
+                               }
+                               continue;
+                       }
+
+                       if (found == 1) {
+                               /* if not alreacy checked, add to check */
+                               if (!jsw_afind(checked, pkginfo.file)) {
+                                       jsw_hinsert(check,pkginfo.id,pkginfo.file);
+                               }
+                               /* shouldn't be in there already */
+                               jsw_hinsert(forlibs, pkginfo.id, pkginfo.file);
+                       } 
+                       /* otherwise found == 2, so just continue */
+                       if (found) {
+                               free(pkginfo.file);
+                               free(pkginfo.id);
+                       }
+               }
+       }
+       free(pkgid);
+       free(pkgfile);
+}
+
+char *pathcat(char *dir, char *path) {
+       size_t dirlen = 0, pathlen = 0;
+       char *cat;
+
+       /* chop off trailing / on dir */
+       if (dir) {
+               dirlen = strlen(dir);
+               while (dirlen && dir[dirlen-1] == '/') {
+                       dirlen--;
+               }
+       }
+
+       if (path) {
+               pathlen = strlen(path);
+               while (*path && *path == '/') {
+                       path++;
+                       pathlen--;
+               }
+       }
+
+       cat = malloc(dirlen + pathlen + 2);
+       if (cat) {
+               strncpy(cat, dir, dirlen);
+               cat[dirlen] = '/';
+               strcpy(cat+dirlen+1, path);
+       }
+       return cat;
+}
+
+void print_pkghash(jsw_hash_t *hash, int json) {
+       const char *pkgid, *file;
+       char *fmt;
+       char *sep;
+       int count = 0;
+
+       fmt = json ? "\"%s\": \"%s\"" : "%s:%s";
+       sep = json ? ", " : "\n";
+
+       if (json) {
+               printf("{ ");
+       }
+
+       if (jsw_hsize(hash) > 0) {
+               for (jsw_hreset(hash); jsw_hitem(hash); jsw_hnext(hash)) {
+                       pkgid = jsw_hkey(hash);
+                       file = jsw_hitem(hash);
+                       if (count++) {
+                               printf("%s", sep);
+                       }
+                       printf(fmt, pkgid, file);
+               }
+       }
+       if (json) printf(" }");
+       printf("\n");
+}
+
+int main(int ac, char *av[]) {
+       int opt, argn;
+       int findlibs = 0, json = 0;
+       struct pkgloc *found;
+       jsw_hash_t *packages, *check, *forlibs, *nolib;
+       jsw_atree_t *nfound;
+
+       /* -l also find packages needed for libs
+        * -j output json
+        *  -q quiet - suppress output
+        *  -v verbose - 
+        *  -d debug - trace each step
+        *
+        *  environment:
+        *  ZPMDB - path to localdb, /var/lib/zpm/local.db
+        *  ZPM_REPO_DIR - path to *.repo files, '/var/lib/zpm/repos'
+        *  ZPM_PACKAGE_DIRS - : separated paths to *.zpm files,
+        *  '/var/lib/zpm/packages'
+        *  ZPM_ROOT_DIR :- prepends to above paths
+        *
+        *  -M (missing) invert the output and only output missing
+        *  outputs
+        *  packages found (suppress with -P)
+        *  package strings not found (suppress with -S)
+        *  library dependency packages needed and found (suppress with -N)
+        *  library dependency packages already installed (suppress with -H)
+        *  library dependency packages in install set (suppress with -I)
+        *  library dependency sonames not found (suppress with -L)
+        *
+        *  exit value is 0 if no missing libs and no bad package strings
+        *  exit value is non zero otherwise
+        */
+
+       int output = 1;
+       while ((opt = getopt(ac, av, "lj")) != -1) {
+               switch (opt) {
+                       case 'l': findlibs = 1; break;
+                       case 'j': json = 1; break;
+                       case 'q': output = 0;
+                       default:
+                                 exit(EXIT_FAILURE);
+                                 break;
+               }
+       }
+       argn = optind;
+
+       packages = jsw_hnew(ac,NULL,(cmp_f)strcmp,(keydup_f)strdup,
+                       (itemdup_f)strdup,free,free);
+       check = jsw_hnew(ac,NULL,(cmp_f)strcmp,(keydup_f)strdup,
+                       (itemdup_f)strdup,free,free);
+       forlibs = jsw_hnew(ac,NULL,(cmp_f)strcmp,(keydup_f)strdup,
+                       (itemdup_f)strdup,free,free);
+       nolib = jsw_hnew(ac,NULL,(cmp_f)strcmp,(keydup_f)strdup,
+                       (itemdup_f)strdup,free,free);
+       nfound = jsw_anew((cmp_f)strcmp, (dup_f)strdup, (rel_f)free);
+
+       int arg;
+       for (arg = argn; arg < ac; arg++) {
+               found = find_package(av[arg]);
+               if (found) {
+                       jsw_hinsert(packages, found->id, found->file);
+                       jsw_hinsert(check, found->id, found->file);
+                       free(found->id);
+                       free(found->file);
+                       free(found);
+               } else {
+                       jsw_ainsert(nfound, av[arg]);
+               }
+
+       }
+
+       if (findlibs) {
+               checklibs(check, forlibs, nolib);
+       }
+
+       if (output) {
+               print_pkghash(packages, json);
+               print_pkghash(forlibs, json);
+       }
+
+       if (jsw_hsize(nolib) > 0) {
+               for (jsw_hreset(nolib); jsw_hitem(nolib); jsw_hnext(nolib)) {
+                       const char *pkgid, *file;
+                       pkgid = jsw_hkey(nolib);
+                       file = jsw_hitem(nolib);
+                       fprintf(stderr, "no lib found %s:%s\n", pkgid, file);
+               }
+       }
+
+       if (jsw_asize(nfound) > 0) {
+               jsw_atrav_t *i;
+               i = jsw_atnew();
+               char *pkgstr;
+
+               for (pkgstr = jsw_atfirst(i, nfound); pkgstr; pkgstr = jsw_atnext(i)) {
+                       fprintf(stderr, "%s:\n", pkgstr);
+               }
+       }
+
+       return jsw_asize(nfound) > 0 || jsw_hsize(nolib) > 0 ? 1 : 0;
+}
diff --git a/zpm.h b/zpm.h
index 106314e958356e40de4fbcea04f67bb42a35571b..f8ce56bf598609efb4388da4379c1c8e722e8a3f 100644 (file)
--- a/zpm.h
+++ b/zpm.h
@@ -9,6 +9,7 @@
 #include <sys/types.h>
 
 #include <sqlite3.h>
+#include <lib/jsw/jsw_atree.h>
 
 #define ZPM_HASH_STRLEN 64
 
@@ -53,7 +54,7 @@ struct zpm_tag {
 
 struct zpm_package {
        struct zpm *zpm;
-       struct jsw_hash *ht;
+       struct jsw_hash_t *ht;
 
        /* char pointers are just pointers into the hash table */
        /* integers/times and such are passed through atoi */
@@ -77,6 +78,8 @@ struct zpm_package {
 
 int zpm_parse_package(char *pstr, char *name, char *ver, int *rel);
 char *zpm_findpkg(struct zpm *zpm, char *pkgstr, char *where);
+char *zpm_findlib(struct zpm *zpm, char *soname, char *where);
+int zpm_libraries_needed(struct zpm *zpm, char *pkgid, jsw_atree_t *list); 
 int zpm_quote(char *value, char *dest, size_t n);
 
 struct zpm_file {