+++ /dev/null
-#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;
- int installed;
-};
-
-struct search_ctl {
- char *localdb, *repodir, *pkgdir;
- struct zpm *zpmdb;
- glob_t repos;
- int matchallpkgfile;
- int matchinstalled;
- int suppressinstalled;
- int onlylocalinstalled;
- int verbose;
- int dbrepos;
-};
-
-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;
-}
-
-char *checkfile(char *pkgstr, char *path) {
- struct zpm pkgfile;
- char *pkgid = 0;
-
- if (!zpm_open(&pkgfile, path)) {
- return NULL;
- }
-
- pkgid = zpm_findpkg(&pkgfile, pkgstr, 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, NULL);
- if (pkgfile.error) {
- fprintf(stderr, "sql error: %s\n", pkgfile.errmsg);
- }
- zpm_close(&pkgfile);
-
- return pkgid;
-}
-
-int find_globs(struct search_ctl *opt) {
- glob_t *repos;
- int rv;
-
- repos = &opt->repos;
- repos->gl_offs = 0;
-
- int globopts = 0;
-
- if (opt->repodir) {
- char *globstr = pathcat(opt->repodir, "*.repo");
- rv = glob(globstr, globopts, NULL, repos);
- switch (rv) {
- case GLOB_NOSPACE:
- fprintf(stderr, "glob no mem\n");
- return 0;
- case GLOB_ABORTED:
- fprintf(stderr, "glob abort\n");
- return 0;
- case GLOB_NOMATCH:
- break;
- case 0:
- break;
- default:
- break;
- }
- globopts = GLOB_APPEND;
- free(globstr);
- }
-
- if (opt->pkgdir) {
- char *globstr = pathcat(opt->pkgdir, "*.zpm");
- rv = glob(globstr, globopts, NULL, repos);
- switch (rv) {
- case GLOB_NOSPACE:
- fprintf(stderr, "glob no mem\n");
- return 0;
- case GLOB_ABORTED:
- fprintf(stderr, "glob abort\n");
- return 0;
- case GLOB_NOMATCH:
- break;
- case 0:
- break;
- default:
- break;
- }
- free(globstr);
- }
-
- return 1;
-}
-
-int find_lib(char *soname, struct search_ctl *opt, struct pkgloc *pkg) {
- char *latest = 0;
- char *installed = 0, *found = 0;
- char *pkgfile = 0;
- int rv;
- unsigned int i;
-
- if (opt->localdb) {
- installed = zpm_findlib(opt->zpmdb, soname, "status = 'installed'");
- if (installed) {
- if (opt->verbose > 1) {
- fprintf(stderr, "library %s installed via %s\n", soname, installed);
- }
- /* we're done, the lib is installed */
- return 2;
- }
- }
-
- for (i = 0; i < opt->repos.gl_pathc; i++) {
- if (opt->verbose > 1) {
- fprintf(stderr, "checking %s for %s\n", opt->repos.gl_pathv[i], soname);
- }
- found = checkfileforlib(soname, opt->repos.gl_pathv[i]);
- if (found) {
- if (opt->verbose > 1) {
- fprintf(stderr, "found %s\n", found);
- }
- rv = zpm_vercmp(found, latest);
- if (rv == 1) {
- latest = found;
- free(pkgfile);
- pkgfile = strdup(opt->repos.gl_pathv[i]);
- }
- } else if (opt->verbose > 1) {
- fprintf(stderr, "not found\n");
- }
- }
-
- if (latest && pkgfile) {
- pkg->id = strdup(latest);
- pkg->file = pkgfile;
- return 1;
- }
-
- return 0;
-}
-
-struct pkgloc *find_package(char *pkgstr, struct search_ctl *opt) {
- char *latest = 0;
- char *installed = 0, *found = 0;
- char *pkgfile = 0;
- struct pkgloc *pkg = 0;
- int rv;
- unsigned int i;
-
- if (opt->localdb) {
- installed = zpm_findpkg(opt->zpmdb, pkgstr, "status = 'installed'");
- if (installed) {
- latest = installed;
- pkgfile = opt->zpmdb->path;
- }
- if (!opt->onlylocalinstalled) {
- found = zpm_findpkg(opt->zpmdb, pkgstr, NULL);
- if (found) {
- rv = zpm_vercmp(found, latest);
- if (rv == 1) {
- latest = found;
- pkgfile = opt->zpmdb->path;
- }
- }
- }
-
-#if 0
- if (opt->dbrepos) {
- zpm_foreach_repo(opt->zpmdb, search_repo, pkg)
- }
-#endif
- }
-
- for (i = 0; i < opt->repos.gl_pathc; i++) {
- if (!opt->matchallpkgfile
- && !strstr(opt->repos.gl_pathv[i], pkgstr)
- && !strstr(opt->repos.gl_pathv[i], ".repo")
- ) {
- continue;
- }
- found = checkfile(pkgstr, opt->repos.gl_pathv[i]);
- if (found) {
- rv = zpm_vercmp(found, latest);
- if (rv == 1) {
- latest = found;
- pkgfile = strdup(opt->repos.gl_pathv[i]);
- }
- }
- }
-
- if (latest && pkgfile) {
- pkg = malloc(sizeof *pkg);
- pkg->id = strdup(latest);
- pkg->file = pkgfile;
- pkg->installed = 0;
- if (installed) {
- pkg->installed = !strcmp(latest, installed);
- }
- }
-
- 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\
- ";
-
-static int afind_strcmp(const void *a, const void *b) {
- return strcmp(a, b);
-}
-
-void checklibs(struct search_ctl *opts,
- 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(afind_strcmp, (dup_f)strdup, (rel_f)free);
- checked_libs = jsw_anew(afind_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 */
- /* fprintf(stderr, "already checked %s\n", pkgid); */
- continue;
- }
-
- fprintf(stderr, "checking libs for %s\n", pkgid);
- /* we do this now so we catch self deps */
- if (!jsw_ainsert(checked, pkgid)) {
- fprintf(stderr, "checked insert failed\n");
- exit(EXIT_FAILURE);
- }
-
- if (!jsw_afind(checked, pkgid)) {
- /* already checked this one */
- fprintf(stderr, "checked find failed\n");
- exit(EXIT_FAILURE);
- }
-
- /* 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(afind_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)) {
- if (opts->verbose > 1) {
- fprintf(stderr, "already checked %s\n", soname);
- }
- continue;
- }
-#if 0
- if (opts->verbose > 1) {
- fprintf(stderr, "checking for %s\n", soname);
- }
-#endif
-
- /* haven't found this soname */
- jsw_ainsert(checked_libs, soname);
-
- found = find_lib(soname, opts, &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);
- free(pkginfo.file);
- free(pkginfo.id);
- }
- /* otherwise found == 2, so just continue */
- }
- }
- free(pkgid);
- free(pkgfile);
-}
-
-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 option, argn;
- int findlibs = 0, json = 0;
- struct pkgloc *found;
- jsw_hash_t *packages, *check, *forlibs, *nolib;
- jsw_atree_t *nfound;
- struct search_ctl opt = { 0 };
- struct zpm localdb;
-
- opt.dbrepos = 1;
-
- opt.localdb = getenv("ZPMDB");
- if (!opt.localdb) opt.localdb = "/var/lib/zpm/local.db";
- opt.pkgdir = getenv("ZPM_PACKAGE_DIR");
- if (!opt.pkgdir) opt.pkgdir = "/var/lib/zpm/packages";
- opt.repodir = getenv("ZPM_REPO_DIR");
- if (!opt.repodir) opt.repodir = "/var/lib/zpm/repo";
-
-
- /* -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/repo'
- * 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 ((option = getopt(ac, av, "ljqPRDvp:r:d:MiIO")) != -1) {
- switch (option) {
- case 'l': findlibs = 1; break;
- case 'j': json = 1; break;
- case 'q': output = 0; break;
- /* show installed files */
- case 'i': opt.matchinstalled = 1; break;
- case 'I': opt.suppressinstalled = 1; break;
- /* only find localdb pkgs if installed */
- case 'O': opt.onlylocalinstalled = 1; break;
- case 'd': opt.localdb = optarg; break;
- case 'p': opt.pkgdir = optarg; break;
- case 'r': opt.repodir = optarg; break;
- case 'P': opt.pkgdir = 0; break;
- case 'R': opt.repodir = 0; break;
- case 'D': opt.localdb = 0; break;
- /* matchallpkgfile means look at
- * all .zpm files, not just ones
- * that have the pkgid string prefix
- */
- case 'M': opt.matchallpkgfile = 1; break;
- case 'v': opt.verbose++; break;
- default:
- exit(EXIT_FAILURE);
- break;
- }
- }
- argn = optind;
-
- if (opt.localdb) {
- if (zpm_open(&localdb, NULL)) {
- opt.zpmdb = &localdb;
- } else {
- fprintf(stderr, "can't open localdb\n");
- return 2;
- }
- }
-
- if (!find_globs(&opt)) {
- fprintf(stderr, "bad globs\n");
- return 3;
- }
-
- if (opt.verbose > 1) {
- unsigned int i;
- fprintf(stderr, "globs:");
- for (i = 0; i < opt.repos.gl_pathc; i++) {
- fprintf(stderr, " %s", opt.repos.gl_pathv[i]);
- }
- fprintf(stderr, "\n");
- }
-
- /* direct packages asked for */
- packages = jsw_hnew(ac,NULL,afind_strcmp,(keydup_f)strdup,
- (itemdup_f)strdup,free,free);
-
- /* packages we need to check for libs */
- check = jsw_hnew(ac,NULL,afind_strcmp,(keydup_f)strdup,
- (itemdup_f)strdup,free,free);
-
- /* packages we will also need for library dependences */
- forlibs = jsw_hnew(ac,NULL,afind_strcmp,(keydup_f)strdup,
- (itemdup_f)strdup,free,free);
-
- /* libraries we didn't find */
- nolib = jsw_hnew(ac,NULL,afind_strcmp,(keydup_f)strdup,
- (itemdup_f)strdup,free,free);
-
- /* packages asked for that we can't find */
- nfound = jsw_anew(afind_strcmp, (dup_f)strdup, (rel_f)free);
-
- int arg;
- for (arg = argn; arg < ac; arg++) {
- found = find_package(av[arg], &opt);
- if (found && (opt.matchinstalled || !found->installed)) {
- if (found->installed && opt.suppressinstalled) {
- continue;
- }
- 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(&opt, check, forlibs, nolib);
- /* remove from forlibs anything already explicitly
- * in packages
- */
- }
-
- if (output) {
- if (jsw_hsize(packages)) {
- print_pkghash(packages, json);
- }
- if (jsw_hsize(forlibs)) {
- 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: not found\n", pkgstr);
- }
- }
-
- return jsw_asize(nfound) > 0 || jsw_hsize(nolib) > 0 ? 1 : 0;
-}