1 #define _POSIX_C_SOURCE 200809L
9 #include "lib/jsw/jsw_hlib.h"
10 #include "lib/jsw/jsw_atree.h"
13 * find packages, and lib deps
24 char *localdb, *repodir, *pkgdir;
29 int suppressinstalled;
30 int onlylocalinstalled;
35 char *pathcat(char *dir, char *path) {
36 size_t dirlen = 0, pathlen = 0;
39 /* chop off trailing / on dir */
42 while (dirlen && dir[dirlen-1] == '/') {
48 pathlen = strlen(path);
49 while (*path && *path == '/') {
55 cat = malloc(dirlen + pathlen + 2);
57 strncpy(cat, dir, dirlen);
59 strcpy(cat+dirlen+1, path);
64 char *checkfile(char *pkgstr, char *path) {
68 if (!zpm_open(&pkgfile, path)) {
72 pkgid = zpm_findpkg(&pkgfile, pkgstr, NULL);
78 char *checkfileforlib(char *soname, char *path) {
82 if (!zpm_open(&pkgfile, path)) {
86 pkgid = zpm_findlib(&pkgfile, soname, NULL);
88 fprintf(stderr, "sql error: %s\n", pkgfile.errmsg);
95 int find_globs(struct search_ctl *opt) {
105 char *globstr = pathcat(opt->repodir, "*.repo");
106 rv = glob(globstr, globopts, NULL, repos);
109 fprintf(stderr, "glob no mem\n");
112 fprintf(stderr, "glob abort\n");
121 globopts = GLOB_APPEND;
126 char *globstr = pathcat(opt->pkgdir, "*.zpm");
127 rv = glob(globstr, globopts, NULL, repos);
130 fprintf(stderr, "glob no mem\n");
133 fprintf(stderr, "glob abort\n");
148 int find_lib(char *soname, struct search_ctl *opt, struct pkgloc *pkg) {
150 char *installed = 0, *found = 0;
156 installed = zpm_findlib(opt->zpmdb, soname, "status = 'installed'");
158 if (opt->verbose > 1) {
159 fprintf(stderr, "library %s installed via %s\n", soname, installed);
161 /* we're done, the lib is installed */
166 for (i = 0; i < opt->repos.gl_pathc; i++) {
167 if (opt->verbose > 1) {
168 fprintf(stderr, "checking %s for %s\n", opt->repos.gl_pathv[i], soname);
170 found = checkfileforlib(soname, opt->repos.gl_pathv[i]);
172 if (opt->verbose > 1) {
173 fprintf(stderr, "found %s\n", found);
175 rv = zpm_vercmp(found, latest);
179 pkgfile = strdup(opt->repos.gl_pathv[i]);
181 } else if (opt->verbose > 1) {
182 fprintf(stderr, "not found\n");
186 if (latest && pkgfile) {
187 pkg->id = strdup(latest);
195 struct pkgloc *find_package(char *pkgstr, struct search_ctl *opt) {
197 char *installed = 0, *found = 0;
199 struct pkgloc *pkg = 0;
204 installed = zpm_findpkg(opt->zpmdb, pkgstr, "status = 'installed'");
207 pkgfile = opt->zpmdb->path;
209 if (!opt->onlylocalinstalled) {
210 found = zpm_findpkg(opt->zpmdb, pkgstr, NULL);
212 rv = zpm_vercmp(found, latest);
215 pkgfile = opt->zpmdb->path;
222 zpm_foreach_repo(opt->zpmdb, search_repo, pkg)
227 for (i = 0; i < opt->repos.gl_pathc; i++) {
228 if (!opt->matchallpkgfile
229 && !strstr(opt->repos.gl_pathv[i], pkgstr)
230 && !strstr(opt->repos.gl_pathv[i], ".repo")
234 found = checkfile(pkgstr, opt->repos.gl_pathv[i]);
236 rv = zpm_vercmp(found, latest);
239 pkgfile = strdup(opt->repos.gl_pathv[i]);
244 if (latest && pkgfile) {
245 pkg = malloc(sizeof *pkg);
246 pkg->id = strdup(latest);
250 pkg->installed = !strcmp(latest, installed);
257 char *pkglibsneeded = "\
259 select distinct EN.needed as soname, PF.pkgid\
261 join packagefiles_pkgid PF on PF.hash = EN.file\
264 select distinct EL.soname, PF.pkgid\
265 from elflibraries EL\
266 join packagefiles_pkgid PF on PF.hash = EL.file\
268 select distinct PL.soname, PP.soname is not null as selfsatisfied\
270 left join pkgprovides PP on PL.pkgid = PP.pkgid and PL.soname = PP.soname\
274 static int afind_strcmp(const void *a, const void *b) {
278 void checklibs(struct search_ctl *opts,
279 jsw_hash_t *check, jsw_hash_t *forlibs, jsw_hash_t *nfound) {
280 char *pkgid = 0, *pkgfile = 0;
283 /* checked_libs is a list of checked sonames
284 * checked is a list of checked packages
285 * needed is list of libs for package
287 jsw_atree_t *needed = 0, *checked, *checked_libs;
293 checked = jsw_anew(afind_strcmp, (dup_f)strdup, (rel_f)free);
294 checked_libs = jsw_anew(afind_strcmp, (dup_f)strdup, (rel_f)free);
296 while (jsw_hsize(check) > 0) {
302 pkgid = strdup(jsw_hkey(check));
303 pkgfile = strdup(jsw_hitem(check));
305 if (!pkgid || !pkgfile) {
309 jsw_herase(check, pkgid);
311 if (jsw_afind(checked, pkgid)) {
312 /* already checked this one */
313 /* fprintf(stderr, "already checked %s\n", pkgid); */
317 fprintf(stderr, "checking libs for %s\n", pkgid);
318 /* we do this now so we catch self deps */
319 if (!jsw_ainsert(checked, pkgid)) {
320 fprintf(stderr, "checked insert failed\n");
324 if (!jsw_afind(checked, pkgid)) {
325 /* already checked this one */
326 fprintf(stderr, "checked find failed\n");
330 /* get the libraries needed by this package */
331 if (!zpm_open(&src, pkgfile)) {
332 fprintf(stderr, "can't zpm open %s\n", pkgfile);
336 if (needed) jsw_adelete(needed);
337 needed = jsw_anew(afind_strcmp, (dup_f)strdup, (rel_f)free);
338 libs = zpm_libraries_needed(&src, pkgid, needed);
347 for (soname = jsw_atfirst(i, needed); soname; soname = jsw_atnext(i)) {
349 struct pkgloc pkginfo;
351 /* if it's in checked_libs, we've already looked at this one */
352 if (jsw_afind(checked_libs, soname)) {
353 if (opts->verbose > 1) {
354 fprintf(stderr, "already checked %s\n", soname);
359 if (opts->verbose > 1) {
360 fprintf(stderr, "checking for %s\n", soname);
364 /* haven't found this soname */
365 jsw_ainsert(checked_libs, soname);
367 found = find_lib(soname, opts, &pkginfo);
369 if (!jsw_hinsert(nfound, soname, pkgid)) {
370 fprintf(stderr,"insert error\n");
376 /* if not alreacy checked, add to check */
377 if (!jsw_afind(checked, pkginfo.file)) {
378 jsw_hinsert(check,pkginfo.id,pkginfo.file);
380 /* shouldn't be in there already */
381 jsw_hinsert(forlibs, pkginfo.id, pkginfo.file);
385 /* otherwise found == 2, so just continue */
392 void print_pkghash(jsw_hash_t *hash, int json) {
393 const char *pkgid, *file;
398 fmt = json ? "\"%s\": \"%s\"" : "%s:%s";
399 sep = json ? ", " : "\n";
405 if (jsw_hsize(hash) > 0) {
406 for (jsw_hreset(hash); jsw_hitem(hash); jsw_hnext(hash)) {
407 pkgid = jsw_hkey(hash);
408 file = jsw_hitem(hash);
412 printf(fmt, pkgid, file);
415 if (json) printf(" }");
419 int main(int ac, char *av[]) {
421 int findlibs = 0, json = 0;
422 struct pkgloc *found;
423 jsw_hash_t *packages, *check, *forlibs, *nolib;
425 struct search_ctl opt = { 0 };
430 opt.localdb = getenv("ZPMDB");
431 if (!opt.localdb) opt.localdb = "/var/lib/zpm/local.db";
432 opt.pkgdir = getenv("ZPM_PACKAGE_DIR");
433 if (!opt.pkgdir) opt.pkgdir = "/var/lib/zpm/packages";
434 opt.repodir = getenv("ZPM_REPO_DIR");
435 if (!opt.repodir) opt.repodir = "/var/lib/zpm/repo";
438 /* -l also find packages needed for libs
440 * -q quiet - suppress output
442 * -d debug - trace each step
445 * ZPMDB - path to localdb, /var/lib/zpm/local.db
446 * ZPM_REPO_DIR - path to *.repo files, '/var/lib/zpm/repo'
447 * ZPM_PACKAGE_DIRS - : separated paths to *.zpm files,
448 * '/var/lib/zpm/packages'
449 * ZPM_ROOT_DIR :- prepends to above paths
451 * -M (missing) invert the output and only output missing
453 * packages found (suppress with -P)
454 * package strings not found (suppress with -S)
455 * library dependency packages needed and found (suppress with -N)
456 * library dependency packages already installed (suppress with -H)
457 * library dependency packages in install set (suppress with -I)
458 * library dependency sonames not found (suppress with -L)
460 * exit value is 0 if no missing libs and no bad package strings
461 * exit value is non zero otherwise
465 while ((option = getopt(ac, av, "ljqPRDvp:r:d:MiIO")) != -1) {
467 case 'l': findlibs = 1; break;
468 case 'j': json = 1; break;
469 case 'q': output = 0; break;
470 /* show installed files */
471 case 'i': opt.matchinstalled = 1; break;
472 case 'I': opt.suppressinstalled = 1; break;
473 /* only find localdb pkgs if installed */
474 case 'O': opt.onlylocalinstalled = 1; break;
475 case 'd': opt.localdb = optarg; break;
476 case 'p': opt.pkgdir = optarg; break;
477 case 'r': opt.repodir = optarg; break;
478 case 'P': opt.pkgdir = 0; break;
479 case 'R': opt.repodir = 0; break;
480 case 'D': opt.localdb = 0; break;
481 /* matchallpkgfile means look at
482 * all .zpm files, not just ones
483 * that have the pkgid string prefix
485 case 'M': opt.matchallpkgfile = 1; break;
486 case 'v': opt.verbose++; break;
495 if (zpm_open(&localdb, NULL)) {
496 opt.zpmdb = &localdb;
498 fprintf(stderr, "can't open localdb\n");
503 if (!find_globs(&opt)) {
504 fprintf(stderr, "bad globs\n");
508 if (opt.verbose > 1) {
510 fprintf(stderr, "globs:");
511 for (i = 0; i < opt.repos.gl_pathc; i++) {
512 fprintf(stderr, " %s", opt.repos.gl_pathv[i]);
514 fprintf(stderr, "\n");
517 /* direct packages asked for */
518 packages = jsw_hnew(ac,NULL,afind_strcmp,(keydup_f)strdup,
519 (itemdup_f)strdup,free,free);
521 /* packages we need to check for libs */
522 check = jsw_hnew(ac,NULL,afind_strcmp,(keydup_f)strdup,
523 (itemdup_f)strdup,free,free);
525 /* packages we will also need for library dependences */
526 forlibs = jsw_hnew(ac,NULL,afind_strcmp,(keydup_f)strdup,
527 (itemdup_f)strdup,free,free);
529 /* libraries we didn't find */
530 nolib = jsw_hnew(ac,NULL,afind_strcmp,(keydup_f)strdup,
531 (itemdup_f)strdup,free,free);
533 /* packages asked for that we can't find */
534 nfound = jsw_anew(afind_strcmp, (dup_f)strdup, (rel_f)free);
537 for (arg = argn; arg < ac; arg++) {
538 found = find_package(av[arg], &opt);
539 if (found && (opt.matchinstalled || !found->installed)) {
540 if (found->installed && opt.suppressinstalled) {
543 jsw_hinsert(packages, found->id, found->file);
544 jsw_hinsert(check, found->id, found->file);
549 jsw_ainsert(nfound, av[arg]);
554 checklibs(&opt, check, forlibs, nolib);
555 /* remove from forlibs anything already explicitly
561 if (jsw_hsize(packages)) {
562 print_pkghash(packages, json);
564 if (jsw_hsize(forlibs)) {
565 print_pkghash(forlibs, json);
569 if (jsw_hsize(nolib) > 0) {
570 for (jsw_hreset(nolib); jsw_hitem(nolib); jsw_hnext(nolib)) {
571 const char *pkgid, *file;
572 pkgid = jsw_hkey(nolib);
573 file = jsw_hitem(nolib);
574 fprintf(stderr, "no lib found %s:%s\n", pkgid, file);
578 if (jsw_asize(nfound) > 0) {
583 for (pkgstr = jsw_atfirst(i, nfound); pkgstr; pkgstr = jsw_atnext(i)) {
584 fprintf(stderr, "%s: not found\n", pkgstr);
588 return jsw_asize(nfound) > 0 || jsw_hsize(nolib) > 0 ? 1 : 0;