]> pd.if.org Git - zpackage/blobdiff - zpm-search.c
add zpm-search to look for packages and libraries
[zpackage] / zpm-search.c
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;
+}