int event_callback(void *data, struct pkg_event *ev) { struct pkg *pkg = NULL, *pkg_new, *pkg_old; int *debug = data; struct pkg_event_conflict *cur_conflict; const char *filename; if (msg_buf == NULL) { msg_buf = sbuf_new_auto(); } /* * If a progressbar has been interrupted by another event, then * we need to add a newline to prevent bad formatting. */ if (progress_started && ev->type != PKG_EVENT_PROGRESS_TICK && !progress_interrupted) { putchar('\n'); progress_interrupted = true; } switch(ev->type) { case PKG_EVENT_ERRNO: warnx("%s(%s): %s", ev->e_errno.func, ev->e_errno.arg, strerror(ev->e_errno.no)); break; case PKG_EVENT_ERROR: warnx("%s", ev->e_pkg_error.msg); break; case PKG_EVENT_NOTICE: if (!quiet) printf("%s\n", ev->e_pkg_notice.msg); break; case PKG_EVENT_DEVELOPER_MODE: warnx("DEVELOPER_MODE: %s", ev->e_pkg_error.msg); break; case PKG_EVENT_UPDATE_ADD: if (quiet || !isatty(STDOUT_FILENO)) break; printf("\rPushing new entries %d/%d", ev->e_upd_add.done, ev->e_upd_add.total); if (ev->e_upd_add.total == ev->e_upd_add.done) printf("\n"); break; case PKG_EVENT_UPDATE_REMOVE: if (quiet || !isatty(STDOUT_FILENO)) break; printf("\rRemoving entries %d/%d", ev->e_upd_remove.done, ev->e_upd_remove.total); if (ev->e_upd_remove.total == ev->e_upd_remove.done) printf("\n"); break; case PKG_EVENT_FETCH_BEGIN: if (quiet) break; filename = strrchr(ev->e_fetching.url, '/'); if (filename != NULL) { filename++; } else { /* * We failed at being smart, so display * the entire url. */ filename = ev->e_fetching.url; } job_status_begin(msg_buf); progress_debit = true; sbuf_printf(msg_buf, "Fetching %s", filename); break; case PKG_EVENT_FETCH_FINISHED: progress_debit = false; break; case PKG_EVENT_INSTALL_BEGIN: if (quiet) break; else { nbdone++; job_status_begin(msg_buf); pkg = ev->e_install_begin.pkg; pkg_sbuf_printf(msg_buf, "Installing %n-%v...\n", pkg, pkg); sbuf_finish(msg_buf); printf("%s", sbuf_data(msg_buf)); } break; case PKG_EVENT_INSTALL_FINISHED: if (quiet) break; pkg = ev->e_install_finished.pkg; if (pkg_has_message(pkg)) { if (messages == NULL) messages = sbuf_new_auto(); pkg_sbuf_printf(messages, "Message for %n-%v:\n%M\n", pkg, pkg, pkg); } break; case PKG_EVENT_EXTRACT_BEGIN: if (quiet) break; else { job_status_begin(msg_buf); pkg = ev->e_install_begin.pkg; pkg_sbuf_printf(msg_buf, "Extracting %n-%v", pkg, pkg); } break; case PKG_EVENT_EXTRACT_FINISHED: break; case PKG_EVENT_ADD_DEPS_BEGIN: ++add_deps_depth; break; case PKG_EVENT_ADD_DEPS_FINISHED: --add_deps_depth; break; case PKG_EVENT_INTEGRITYCHECK_BEGIN: if (quiet) break; printf("Checking integrity..."); break; case PKG_EVENT_INTEGRITYCHECK_FINISHED: if (quiet) break; printf(" done (%d conflicting)\n", ev->e_integrity_finished.conflicting); break; case PKG_EVENT_INTEGRITYCHECK_CONFLICT: if (*debug == 0) break; printf("\nConflict found on path %s between %s and ", ev->e_integrity_conflict.pkg_path, ev->e_integrity_conflict.pkg_uid); cur_conflict = ev->e_integrity_conflict.conflicts; while (cur_conflict) { if (cur_conflict->next) printf("%s, ", cur_conflict->uid); else printf("%s", cur_conflict->uid); cur_conflict = cur_conflict->next; } printf("\n"); break; case PKG_EVENT_DEINSTALL_BEGIN: if (quiet) break; nbdone++; job_status_begin(msg_buf); pkg = ev->e_install_begin.pkg; pkg_sbuf_printf(msg_buf, "Deinstalling %n-%v...\n", pkg, pkg); sbuf_finish(msg_buf); printf("%s", sbuf_data(msg_buf)); break; case PKG_EVENT_DEINSTALL_FINISHED: if (quiet) break; break; case PKG_EVENT_DELETE_FILES_BEGIN: if (quiet) break; else { job_status_begin(msg_buf); pkg = ev->e_install_begin.pkg; pkg_sbuf_printf(msg_buf, "Deleting files for %n-%v", pkg, pkg); } break; case PKG_EVENT_DELETE_FILES_FINISHED: break; case PKG_EVENT_UPGRADE_BEGIN: if (quiet) break; pkg_new = ev->e_upgrade_begin.n; pkg_old = ev->e_upgrade_begin.o; nbdone++; job_status_begin(msg_buf); switch (pkg_version_change_between(pkg_new, pkg_old)) { case PKG_DOWNGRADE: pkg_sbuf_printf(msg_buf, "Downgrading %n from %v to %v...\n", pkg_new, pkg_old, pkg_new); break; case PKG_REINSTALL: pkg_sbuf_printf(msg_buf, "Reinstalling %n-%v...\n", pkg_old, pkg_old); break; case PKG_UPGRADE: pkg_sbuf_printf(msg_buf, "Upgrading %n from %v to %v...\n", pkg_new, pkg_old, pkg_new); break; } sbuf_finish(msg_buf); printf("%s", sbuf_data(msg_buf)); break; case PKG_EVENT_UPGRADE_FINISHED: if (quiet) break; pkg_new = ev->e_upgrade_finished.n; if (pkg_has_message(pkg_new)) { if (messages == NULL) messages = sbuf_new_auto(); pkg_sbuf_printf(messages, "Message for %n-%v:\n %M\n", pkg_new, pkg_new, pkg_new); } break; case PKG_EVENT_LOCKED: pkg = ev->e_locked.pkg; pkg_printf("\n%n-%v is locked and may not be modified\n", pkg, pkg); break; case PKG_EVENT_REQUIRED: pkg = ev->e_required.pkg; pkg_printf("\n%n-%v is required by: %r%{%rn-%rv%| %}", pkg, pkg, pkg); if (ev->e_required.force == 1) fprintf(stderr, ", deleting anyway\n"); else fprintf(stderr, "\n"); break; case PKG_EVENT_ALREADY_INSTALLED: if (quiet) break; pkg = ev->e_already_installed.pkg; pkg_printf("the most recent version of %n-%v is already installed\n", pkg, pkg); break; case PKG_EVENT_NOT_FOUND: printf("Package '%s' was not found in " "the repositories\n", ev->e_not_found.pkg_name); break; case PKG_EVENT_MISSING_DEP: warnx("Missing dependency '%s-%s'", pkg_dep_name(ev->e_missing_dep.dep), pkg_dep_version(ev->e_missing_dep.dep)); break; case PKG_EVENT_NOREMOTEDB: fprintf(stderr, "Unable to open remote database \"%s\". " "Try running '%s update' first.\n", ev->e_remotedb.repo, getprogname()); break; case PKG_EVENT_NOLOCALDB: fprintf(stderr, "Local package database nonexistent!\n"); break; case PKG_EVENT_NEWPKGVERSION: newpkgversion = true; printf("New version of pkg detected; it needs to be " "installed first.\n"); break; case PKG_EVENT_FILE_MISMATCH: pkg = ev->e_file_mismatch.pkg; pkg_fprintf(stderr, "%n-%v: checksum mismatch for %Fn\n", pkg, pkg, ev->e_file_mismatch.file); break; case PKG_EVENT_PLUGIN_ERRNO: warnx("%s: %s(%s): %s", pkg_plugin_get(ev->e_plugin_errno.plugin, PKG_PLUGIN_NAME), ev->e_plugin_errno.func, ev->e_plugin_errno.arg, strerror(ev->e_plugin_errno.no)); break; case PKG_EVENT_PLUGIN_ERROR: warnx("%s: %s", pkg_plugin_get(ev->e_plugin_error.plugin, PKG_PLUGIN_NAME), ev->e_plugin_error.msg); break; case PKG_EVENT_PLUGIN_INFO: if (quiet) break; printf("%s: %s\n", pkg_plugin_get(ev->e_plugin_info.plugin, PKG_PLUGIN_NAME), ev->e_plugin_info.msg); break; case PKG_EVENT_INCREMENTAL_UPDATE: if (!quiet) printf("%s repository update completed. %d packages processed.\n", ev->e_incremental_update.reponame, ev->e_incremental_update.processed); break; case PKG_EVENT_DEBUG: fprintf(stderr, "DBG(%d)[%d]> %s\n", ev->e_debug.level, (int)getpid(), ev->e_debug.msg); break; case PKG_EVENT_QUERY_YESNO: return ( ev->e_query_yesno.deft ? query_yesno(true, ev->e_query_yesno.msg, "[Y/n]") : query_yesno(false, ev->e_query_yesno.msg, "[y/N]") ); break; case PKG_EVENT_QUERY_SELECT: return query_select(ev->e_query_select.msg, ev->e_query_select.items, ev->e_query_select.ncnt, ev->e_query_select.deft); break; case PKG_EVENT_SANDBOX_CALL: return ( event_sandboxed_call(ev->e_sandbox_call.call, ev->e_sandbox_call.fd, ev->e_sandbox_call.userdata) ); break; case PKG_EVENT_SANDBOX_GET_STRING: return ( event_sandboxed_get_string(ev->e_sandbox_call_str.call, ev->e_sandbox_call_str.result, ev->e_sandbox_call_str.len, ev->e_sandbox_call_str.userdata) ); break; case PKG_EVENT_PROGRESS_START: progressbar_start(ev->e_progress_start.msg); break; case PKG_EVENT_PROGRESS_TICK: progressbar_tick(ev->e_progress_tick.current, ev->e_progress_tick.total); break; case PKG_EVENT_BACKUP: sbuf_cat(msg_buf, "Backing up"); sbuf_finish(msg_buf); break; case PKG_EVENT_RESTORE: sbuf_cat(msg_buf, "Restoring"); sbuf_finish(msg_buf); break; default: break; } return 0; }
int exec_check(int argc, char **argv) { struct pkg *pkg = NULL; struct pkgdb_it *it = NULL; struct pkgdb *db = NULL; struct sbuf *msg = NULL; match_t match = MATCH_EXACT; int flags = PKG_LOAD_BASIC; int ret, rc = EX_OK; int ch; bool dcheck = false; bool checksums = false; bool recompute = false; bool reanalyse_shlibs = false; bool noinstall = false; int nbpkgs = 0; int i, processed, total = 0; int verbose = 0; struct option longopts[] = { { "all", no_argument, NULL, 'a' }, { "shlibs", no_argument, NULL, 'B' }, { "case-sensitive", no_argument, NULL, 'C' }, { "dependencies", no_argument, NULL, 'd' }, { "glob", no_argument, NULL, 'g' }, { "case-insensitive", no_argument, NULL, 'i' }, { "dry-run", no_argument, NULL, 'n' }, { "recompute", no_argument, NULL, 'r' }, { "checksums", no_argument, NULL, 's' }, { "verbose", no_argument, NULL, 'v' }, { "regex", no_argument, NULL, 'x' }, { "yes", no_argument, NULL, 'y' }, { NULL, 0, NULL, 0 }, }; struct deps_head dh = STAILQ_HEAD_INITIALIZER(dh); processed = 0; while ((ch = getopt_long(argc, argv, "+aBCdginrsvxy", longopts, NULL)) != -1) { switch (ch) { case 'a': match = MATCH_ALL; break; case 'B': reanalyse_shlibs = true; flags |= PKG_LOAD_FILES; break; case 'C': pkgdb_set_case_sensitivity(true); break; case 'd': dcheck = true; flags |= PKG_LOAD_DEPS; break; case 'g': match = MATCH_GLOB; break; case 'i': pkgdb_set_case_sensitivity(false); break; case 'n': noinstall = true; break; case 'r': recompute = true; flags |= PKG_LOAD_FILES; break; case 's': checksums = true; flags |= PKG_LOAD_FILES; break; case 'v': verbose = 1; break; case 'x': match = MATCH_REGEX; break; case 'y': yes = true; break; default: usage_check(); return (EX_USAGE); } } argc -= optind; argv += optind; /* Default to all packages if no pkg provided */ if (argc == 0 && (dcheck || checksums || recompute || reanalyse_shlibs)) { match = MATCH_ALL; } else if ((argc == 0 && match != MATCH_ALL) || !(dcheck || checksums || recompute || reanalyse_shlibs)) { usage_check(); return (EX_USAGE); } if (recompute || reanalyse_shlibs) ret = pkgdb_access(PKGDB_MODE_READ|PKGDB_MODE_WRITE, PKGDB_DB_LOCAL); else ret = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_LOCAL); if (ret == EPKG_ENODB) { warnx("No packages installed. Nothing to do!"); return (EX_OK); } else if (ret == EPKG_ENOACCESS) { warnx("Insufficient privileges to access the package database"); return (EX_NOPERM); } else if (ret != EPKG_OK) { warnx("Error accessing the package database"); return (EX_SOFTWARE); } ret = pkgdb_open(&db, PKGDB_DEFAULT); if (ret != EPKG_OK) return (EX_IOERR); if (pkgdb_obtain_lock(db, PKGDB_LOCK_ADVISORY) != EPKG_OK) { pkgdb_close(db); warnx("Cannot get an advisory lock on a database, it is locked by another process"); return (EX_TEMPFAIL); } i = 0; nbdone = 0; do { /* XXX: This is really quirky, it would be cleaner to pass * in multiple matches and only run this top-loop once. */ if ((it = pkgdb_query(db, argv[i], match)) == NULL) { rc = EX_IOERR; goto cleanup; } if (msg == NULL) msg = sbuf_new_auto(); if (!verbose) { if (match == MATCH_ALL) progressbar_start("Checking all packages"); else { sbuf_printf(msg, "Checking %s", argv[i]); sbuf_finish(msg); progressbar_start(sbuf_data(msg)); } processed = 0; total = pkgdb_it_count(it); } else { if (match == MATCH_ALL) nbactions = pkgdb_it_count(it); else nbactions = argc; } while (pkgdb_it_next(it, &pkg, flags) == EPKG_OK) { if (!verbose) progressbar_tick(processed, total); else { ++nbdone; job_status_begin(msg); pkg_sbuf_printf(msg, "Checking %n-%v:", pkg, pkg); sbuf_flush(msg); } /* check for missing dependencies */ if (dcheck) { if (verbose) printf(" dependencies..."); nbpkgs += check_deps(db, pkg, &dh, noinstall); if (noinstall && nbpkgs > 0) { rc = EX_UNAVAILABLE; } } if (checksums) { if (verbose) printf(" checksums..."); if (pkg_test_filesum(pkg) != EPKG_OK) { rc = EX_DATAERR; } } if (recompute) { if (pkgdb_upgrade_lock(db, PKGDB_LOCK_ADVISORY, PKGDB_LOCK_EXCLUSIVE) == EPKG_OK) { if (verbose) printf(" recomputing..."); if (pkg_recompute(db, pkg) != EPKG_OK) { rc = EX_DATAERR; } pkgdb_downgrade_lock(db, PKGDB_LOCK_EXCLUSIVE, PKGDB_LOCK_ADVISORY); } else { rc = EX_TEMPFAIL; } } if (reanalyse_shlibs) { if (pkgdb_upgrade_lock(db, PKGDB_LOCK_ADVISORY, PKGDB_LOCK_EXCLUSIVE) == EPKG_OK) { if (verbose) printf(" shared libraries..."); if (pkgdb_reanalyse_shlibs(db, pkg) != EPKG_OK) { pkg_fprintf(stderr, "Failed to " "reanalyse for shlibs: " "%n-%v\n", pkg, pkg); rc = EX_UNAVAILABLE; } pkgdb_downgrade_lock(db, PKGDB_LOCK_EXCLUSIVE, PKGDB_LOCK_ADVISORY); } else { rc = EX_TEMPFAIL; } } if (!verbose) ++processed; else printf(" done\n"); } if (!verbose) progressbar_tick(processed, total); if (msg != NULL) { sbuf_delete(msg); msg = NULL; } if (dcheck && nbpkgs > 0 && !noinstall) { printf("\n>>> Missing package dependencies were detected.\n"); printf(">>> Found %d issue(s) in the package database.\n\n", nbpkgs); if (pkgdb_upgrade_lock(db, PKGDB_LOCK_ADVISORY, PKGDB_LOCK_EXCLUSIVE) == EPKG_OK) { ret = fix_deps(db, &dh, nbpkgs, yes); if (ret == EPKG_OK) check_summary(db, &dh); else if (ret == EPKG_ENODB) { db = NULL; rc = EX_IOERR; } pkgdb_downgrade_lock(db, PKGDB_LOCK_EXCLUSIVE, PKGDB_LOCK_ADVISORY); if (rc == EX_IOERR) goto cleanup; } else { rc = EX_TEMPFAIL; goto cleanup; } } pkgdb_it_free(it); i++; } while (i < argc); cleanup: if (!verbose) progressbar_stop(); if (msg != NULL) sbuf_delete(msg); deps_free(&dh); pkg_free(pkg); pkgdb_release_lock(db, PKGDB_LOCK_ADVISORY); pkgdb_close(db); return (rc); }