static void add_missing_dep(struct pkg_dep *d, struct deps_head *dh, int *nbpkgs) { struct deps_entry *e = NULL; const char *origin = NULL; assert(d != NULL); /* do not add duplicate entries in the queue */ origin = pkg_dep_get(d, PKG_DEP_ORIGIN); STAILQ_FOREACH(e, dh, next) if (strcmp(e->origin, origin) == 0) return; if ((e = calloc(1, sizeof(struct deps_entry))) == NULL) err(1, "calloc(deps_entry)"); e->name = strdup(pkg_dep_get(d, PKG_DEP_NAME)); e->version = strdup(pkg_dep_get(d, PKG_DEP_VERSION)); e->origin = strdup(pkg_dep_get(d, PKG_DEP_ORIGIN)); (*nbpkgs)++; STAILQ_INSERT_TAIL(dh, e, next); }
/* * Converts a pkg_dep into a (partial) package ID. * * The result may be NULL and should be freed using g_free. */ static gchar * dep_to_package_id(struct pkg_dep *dep) { const char *name; const char *version; assert(dep != NULL); name = pkg_dep_get(dep, PKG_DEP_NAME); version = pkg_dep_get(dep, PKG_DEP_VERSION); return pk_package_id_build(name, version, "", ""); }
static void print_recursive_rdeps(kh_pkgs_t *head, struct pkg *p, struct sbuf *sb, kh_pkgs_t *seen, bool top) { struct pkg_dep *dep = NULL; int ret; khint_t k, h; while(pkg_rdeps(p, &dep) == EPKG_OK) { const char *name = pkg_dep_get(dep, PKG_DEP_NAME); k = kh_get_pkgs(seen, name); if (k == kh_end(seen)) { h = kh_get_pkgs(head, name); if (h != kh_end(head)) { kh_put_pkgs(seen, name, &ret); if (!top) sbuf_cat(sb, ", "); sbuf_cat(sb, name); print_recursive_rdeps(head, kh_val(head, h), sb, seen, false); top = false; } } } }
static int check_deps(struct pkgdb *db, struct pkg *p, struct deps_head *dh) { struct pkg_dep *dep = NULL; char *name, *version, *origin; int nbpkgs = 0; assert(db != NULL); assert(p != NULL); name = version = origin = NULL; pkg_get(p, PKG_NAME, &name, PKG_VERSION, &version, PKG_ORIGIN, &origin); while (pkg_deps(p, &dep) == EPKG_OK) { /* do we have a missing dependency? */ if (pkg_is_installed(db, pkg_dep_get(dep, PKG_DEP_ORIGIN)) != EPKG_OK) { printf("%s has a missing dependency: %s\n", origin, pkg_dep_get(dep, PKG_DEP_ORIGIN)), add_missing_dep(dep, dh, &nbpkgs); } } return (nbpkgs); }
static void format_str(struct pkg *pkg, struct sbuf *dest, const char *qstr, void *data) { char size[7]; const char *tmp; bool automatic; int64_t flatsize; lic_t licenselogic; sbuf_clear(dest); while (qstr[0] != '\0') { if (qstr[0] == '%') { qstr++; switch (qstr[0]) { case 'n': pkg_get(pkg, PKG_NAME, &tmp); sbuf_cat(dest, tmp); break; case 'v': pkg_get(pkg, PKG_VERSION, &tmp); sbuf_cat(dest, tmp); break; case 'o': pkg_get(pkg, PKG_ORIGIN, &tmp); sbuf_cat(dest, tmp); break; case 'p': pkg_get(pkg, PKG_PREFIX, &tmp); sbuf_cat(dest, tmp); break; case 'm': pkg_get(pkg, PKG_MAINTAINER, &tmp); sbuf_cat(dest, tmp); break; case 'c': pkg_get(pkg, PKG_COMMENT, &tmp); sbuf_cat(dest, tmp); break; case 'w': pkg_get(pkg, PKG_WWW, &tmp); sbuf_cat(dest, tmp); break; case 'a': pkg_get(pkg, PKG_AUTOMATIC, &automatic); sbuf_printf(dest, "%d", automatic); break; case 's': qstr++; pkg_get(pkg, PKG_FLATSIZE, &flatsize); if (qstr[0] == 'h') { humanize_number(size, sizeof(size), flatsize, "B", HN_AUTOSCALE, 0); sbuf_cat(dest, size); } else if (qstr[0] == 'b') { sbuf_printf(dest, "%" PRId64, flatsize); } break; case '?': qstr++; switch (qstr[0]) { case 'd': sbuf_printf(dest, "%d", !pkg_list_is_empty(pkg, PKG_DEPS)); break; case 'r': sbuf_printf(dest, "%d", !pkg_list_is_empty(pkg, PKG_RDEPS)); break; case 'C': sbuf_printf(dest, "%d", !pkg_list_is_empty(pkg, PKG_CATEGORIES)); break; case 'F': sbuf_printf(dest, "%d", !pkg_list_is_empty(pkg, PKG_FILES)); break; case 'O': sbuf_printf(dest, "%d", !pkg_list_is_empty(pkg, PKG_OPTIONS)); break; case 'D': sbuf_printf(dest, "%d", !pkg_list_is_empty(pkg, PKG_DIRS)); break; case 'L': sbuf_printf(dest, "%d", !pkg_list_is_empty(pkg, PKG_LICENSES)); break; case 'U': sbuf_printf(dest, "%d", !pkg_list_is_empty(pkg, PKG_USERS)); break; case 'G': sbuf_printf(dest, "%d", !pkg_list_is_empty(pkg, PKG_GROUPS)); break; } break; case 'l': pkg_get(pkg, PKG_LICENSE_LOGIC, &licenselogic); switch (licenselogic) { case LICENSE_SINGLE: sbuf_cat(dest, "single"); break; case LICENSE_OR: sbuf_cat(dest, "or"); break; case LICENSE_AND: sbuf_cat(dest, "and"); break; } break; case 'd': qstr++; if (qstr[0] == 'n') sbuf_cat(dest, pkg_dep_get((struct pkg_dep *)data, PKG_DEP_NAME)); else if (qstr[0] == 'o') sbuf_cat(dest, pkg_dep_get((struct pkg_dep *)data, PKG_DEP_ORIGIN)); else if (qstr[0] == 'v') sbuf_cat(dest, pkg_dep_get((struct pkg_dep *)data, PKG_DEP_VERSION)); break; case 'r': qstr++; if (qstr[0] == 'n') sbuf_cat(dest, pkg_dep_get((struct pkg_dep *)data, PKG_DEP_NAME)); else if (qstr[0] == 'o') sbuf_cat(dest, pkg_dep_get((struct pkg_dep *)data, PKG_DEP_ORIGIN)); else if (qstr[0] == 'v') sbuf_cat(dest, pkg_dep_get((struct pkg_dep *)data, PKG_DEP_VERSION)); break; case 'C': sbuf_cat(dest, pkg_category_name((struct pkg_category *)data)); break; case 'F': qstr++; if (qstr[0] == 'p') sbuf_cat(dest, pkg_file_get((struct pkg_file *)data, PKG_FILE_PATH)); else if (qstr[0] == 's') sbuf_cat(dest, pkg_file_get((struct pkg_file *)data, PKG_FILE_SUM)); break; case 'S': sbuf_cat(dest, pkg_script_data((struct pkg_script *)data)); break; case 'O': qstr++; if (qstr[0] == 'k') sbuf_cat(dest, pkg_option_opt((struct pkg_option *)data)); else if (qstr[0] == 'v') sbuf_cat(dest, pkg_option_value((struct pkg_option *)data)); break; case 'D': sbuf_cat(dest, pkg_dir_path((struct pkg_dir *)data)); break; case 'L': sbuf_cat(dest, pkg_license_name((struct pkg_license *)data)); break; case 'U': sbuf_cat(dest, pkg_user_name((struct pkg_user *)data)); break; case 'G': sbuf_cat(dest, pkg_group_name((struct pkg_group *)data)); break; case '%': sbuf_putc(dest, '%'); break; } } else if (qstr[0] == '\\') { qstr++; switch (qstr[0]) { case 'n': sbuf_putc(dest, '\n'); break; case 'a': sbuf_putc(dest, '\a'); break; case 'b': sbuf_putc(dest, '\b'); break; case 'f': sbuf_putc(dest, '\f'); break; case 'r': sbuf_putc(dest, '\r'); break; case '\\': sbuf_putc(dest, '\\'); break; case 't': sbuf_putc(dest, '\t'); break; } } else { sbuf_putc(dest, qstr[0]); } qstr++; } sbuf_finish(dest); }
int print_info(struct pkg * const pkg, unsigned int opt) { struct pkg_dep *dep = NULL; struct pkg_file *file = NULL; struct pkg_category *cat = NULL; struct pkg_license *lic = NULL; struct pkg_option *option = NULL; bool multirepos_enabled = false; char *m; char size[7]; const char *name, *version, *prefix, *origin, *reponame, *repourl; const char *maintainer, *www, *comment, *desc; int64_t flatsize, newflatsize, newpkgsize; lic_t licenselogic; pkg_config_bool(PKG_CONFIG_MULTIREPOS, &multirepos_enabled); pkg_get(pkg, PKG_NAME, &name, PKG_VERSION, &version, PKG_PREFIX, &prefix, PKG_ORIGIN, &origin, PKG_REPONAME, &reponame, PKG_REPOURL, &repourl, PKG_MAINTAINER, &maintainer, PKG_WWW, &www, PKG_COMMENT, &comment, PKG_DESC, &desc, PKG_FLATSIZE, &flatsize, PKG_NEW_FLATSIZE, &newflatsize, PKG_NEW_PKGSIZE, &newpkgsize, PKG_LICENSE_LOGIC, &licenselogic); if (opt & INFO_RAW) { pkg_emit_manifest(pkg, &m); printf("%s\n", m); free(m); } else if (opt & INFO_FULL) { printf("%-15s: %s\n", "Name", name); printf("%-15s: %s\n", "Version", version); printf("%-15s: %s\n", "Origin", origin); printf("%-15s: %s\n", "Prefix", prefix); if ((pkg_type(pkg) == PKG_REMOTE) && multirepos_enabled) printf("%-15s: %s [%s]\n", "Repository", reponame, repourl); if (!pkg_list_is_empty(pkg, PKG_CATEGORIES)) { printf("%-15s:", "Categories"); while (pkg_categories(pkg, &cat) == EPKG_OK) printf(" %s", pkg_category_name(cat)); printf("\n"); } if (!pkg_list_is_empty(pkg, PKG_LICENSES)) { printf("%-15s:", "Licenses"); while (pkg_licenses(pkg, &lic) == EPKG_OK) { printf(" %s", pkg_license_name(lic)); if (licenselogic != 1) printf(" %c", licenselogic); else printf(" "); } printf("\b \n"); } printf("%-15s: %s\n", "Maintainer", maintainer); printf("%-15s: %s\n", "WWW", www); printf("%-15s: %s\n", "Comment", comment); if (!pkg_list_is_empty(pkg, PKG_OPTIONS)) { printf("%-15s: \n", "Options"); while (pkg_options(pkg, &option) == EPKG_OK) printf("\t%s: %s\n", pkg_option_opt(option), pkg_option_value(option)); } if (pkg_type(pkg) == PKG_INSTALLED || pkg_type(pkg) == PKG_FILE) { humanize_number(size, sizeof(size), flatsize, "B", HN_AUTOSCALE, 0); printf("%-15s: %s\n", "Flat size", size); } else { humanize_number(size, sizeof(size), newflatsize, "B", HN_AUTOSCALE, 0); printf("%-15s: %s\n", "Flat size", size); humanize_number(size, sizeof(size), newpkgsize, "B", HN_AUTOSCALE, 0); printf("%-15s: %s\n", "Pkg size", size); } printf("%-15s: \n%s\n", "Description", desc); printf("\n"); } else if (opt & INFO_PRINT_DEP) { if (!(opt & INFO_QUIET)) printf("%s-%s depends on:\n", name, version); while (pkg_deps(pkg, &dep) == EPKG_OK) { printf("%s-%s\n", pkg_dep_get(dep, PKG_DEP_NAME), pkg_dep_get(dep, PKG_DEP_VERSION)); } if (!(opt & INFO_QUIET)) printf("\n"); } else if (opt & INFO_PRINT_RDEP) { if (!(opt & INFO_QUIET)) printf("%s-%s is required by:\n", name, version); while (pkg_rdeps(pkg, &dep) == EPKG_OK) { printf("%s-%s\n", pkg_dep_get(dep, PKG_DEP_NAME), pkg_dep_get(dep, PKG_DEP_VERSION)); } if (!(opt & INFO_QUIET)) printf("\n"); } else if (opt & INFO_LIST_FILES) { if (!(opt & INFO_QUIET)) printf("%s-%s owns the following files:\n", name, version); while (pkg_files(pkg, &file) == EPKG_OK) { printf("%s\n", pkg_file_get(file, PKG_FILE_PATH)); } if (!(opt & INFO_QUIET)) printf("\n"); } else if (opt & INFO_SIZE) { if (pkg_type(pkg) == PKG_INSTALLED) { humanize_number(size, sizeof(size), flatsize, "B", HN_AUTOSCALE, 0); printf("%s-%s size is: %s\n", name, version, size); } else { humanize_number(size, sizeof(size), newflatsize, "B", HN_AUTOSCALE, 0); printf("%s-%s flat size is: %s\n", name, version, size); humanize_number(size, sizeof(size), newpkgsize, "B", HN_AUTOSCALE, 0); printf("%s-%s package size is: %s\n", name, version, size); } } else if (opt & INFO_ORIGIN) { if (opt & INFO_QUIET) printf("%s\n", origin); else printf("%s-%s: %s\n", name, version, origin); } else if (opt & INFO_PREFIX) { if (opt & INFO_QUIET) printf("%s\n", prefix); else printf("%s-%s: %s\n", name, version, prefix); } else { if (opt & INFO_QUIET) printf("%s-%s\n", name, version); else { if ((pkg_type(pkg) == PKG_REMOTE) && multirepos_enabled) printf("%s-%s [repository: %s]: %s\n", name, version, reponame, comment); else printf("%s-%s: %s\n", name, version, comment); } } return (0); }
int pkg_add(struct pkgdb *db, const char *path, unsigned flags, struct pkg_manifest_key *keys) { const char *arch; const char *origin; const char *name; struct archive *a; struct archive_entry *ae; struct pkg *pkg = NULL; struct pkg_dep *dep = NULL; struct pkg *pkg_inst = NULL; bool extract = true; bool handle_rc = false; bool disable_mtree; char dpath[MAXPATHLEN]; const char *basedir; const char *ext; char *mtree; char *prefix; int retcode = EPKG_OK; int ret; assert(path != NULL); /* * Open the package archive file, read all the meta files and set the * current archive_entry to the first non-meta file. * If there is no non-meta files, EPKG_END is returned. */ ret = pkg_open2(&pkg, &a, &ae, path, keys, 0); if (ret == EPKG_END) extract = false; else if (ret != EPKG_OK) { retcode = ret; goto cleanup; } if ((flags & PKG_ADD_UPGRADE) == 0) pkg_emit_install_begin(pkg); if (pkg_is_valid(pkg) != EPKG_OK) { pkg_emit_error("the package is not valid"); return (EPKG_FATAL); } if (flags & PKG_ADD_AUTOMATIC) pkg_set(pkg, PKG_AUTOMATIC, (int64_t)true); /* * Check the architecture */ pkg_get(pkg, PKG_ARCH, &arch, PKG_ORIGIN, &origin, PKG_NAME, &name); if (!is_valid_abi(arch, true)) { if ((flags & PKG_ADD_FORCE) == 0) { retcode = EPKG_FATAL; goto cleanup; } } /* * Check if the package is already installed */ ret = pkg_try_installed(db, origin, &pkg_inst, PKG_LOAD_BASIC); if (ret == EPKG_OK) { if ((flags & PKG_FLAG_FORCE) == 0) { pkg_emit_already_installed(pkg_inst); retcode = EPKG_INSTALLED; pkg_free(pkg_inst); pkg_inst = NULL; goto cleanup; } else { pkg_emit_notice("package %s is already installed, forced install", name); pkg_free(pkg_inst); pkg_inst = NULL; } } else if (ret != EPKG_END) { retcode = ret; goto cleanup; } /* * Check for dependencies by searching the same directory as * the package archive we're reading. Of course, if we're * reading from a file descriptor or a unix domain socket or * somesuch, there's no valid directory to search. */ if (pkg_type(pkg) == PKG_FILE) { basedir = dirname(path); if ((ext = strrchr(path, '.')) == NULL) { pkg_emit_error("%s has no extension", path); retcode = EPKG_FATAL; goto cleanup; } } else { basedir = NULL; ext = NULL; } while (pkg_deps(pkg, &dep) == EPKG_OK) { if (pkg_is_installed(db, pkg_dep_origin(dep)) == EPKG_OK) continue; if (basedir != NULL) { const char *dep_name = pkg_dep_name(dep); const char *dep_ver = pkg_dep_version(dep); snprintf(dpath, sizeof(dpath), "%s/%s-%s%s", basedir, dep_name, dep_ver, ext); if ((flags & PKG_ADD_UPGRADE) == 0 && access(dpath, F_OK) == 0) { ret = pkg_add(db, dpath, PKG_ADD_AUTOMATIC, keys); if (ret != EPKG_OK) { retcode = EPKG_FATAL; goto cleanup; } } else { pkg_emit_error("Missing dependency matching '%s'", pkg_dep_get(dep, PKG_DEP_ORIGIN)); retcode = EPKG_FATAL; goto cleanup; } } else { retcode = EPKG_FATAL; pkg_emit_missing_dep(pkg, dep); goto cleanup; } } /* register the package before installing it in case there are * problems that could be caught here. */ retcode = pkgdb_register_pkg(db, pkg, flags & PKG_ADD_UPGRADE, flags & PKG_FLAG_FORCE); if (retcode != EPKG_OK) goto cleanup; /* MTREE replicates much of the standard functionality * inplicit in the way pkg works. It has to remain available * in the ports for compatibility with the old pkg_tools, but * ultimately, MTREE should be made redundant. Use this for * experimantal purposes and to develop MTREE-free versions of * packages. */ pkg_config_bool(PKG_CONFIG_DISABLE_MTREE, &disable_mtree); if (!disable_mtree) { pkg_get(pkg, PKG_PREFIX, &prefix, PKG_MTREE, &mtree); if ((retcode = do_extract_mtree(mtree, prefix)) != EPKG_OK) goto cleanup_reg; } /* * Execute pre-install scripts */ if ((flags & (PKG_ADD_NOSCRIPT | PKG_ADD_USE_UPGRADE_SCRIPTS)) == 0) pkg_script_run(pkg, PKG_SCRIPT_PRE_INSTALL); /* add the user and group if necessary */ /* pkg_add_user_group(pkg); */ /* * Extract the files on disk. */ if (extract && (retcode = do_extract(a, ae)) != EPKG_OK) { /* If the add failed, clean up (silently) */ pkg_delete_files(pkg, 2); pkg_delete_dirs(db, pkg, 1); goto cleanup_reg; } /* * Execute post install scripts */ if ((flags & PKG_ADD_NOSCRIPT) == 0) { if ((flags & PKG_ADD_USE_UPGRADE_SCRIPTS) == PKG_ADD_USE_UPGRADE_SCRIPTS) pkg_script_run(pkg, PKG_SCRIPT_POST_UPGRADE); else pkg_script_run(pkg, PKG_SCRIPT_POST_INSTALL); } /* * start the different related services if the users do want that * and that the service is running */ pkg_config_bool(PKG_CONFIG_HANDLE_RC_SCRIPTS, &handle_rc); if (handle_rc) pkg_start_stop_rc_scripts(pkg, PKG_RC_START); cleanup_reg: if ((flags & PKG_ADD_UPGRADE) == 0) pkgdb_register_finale(db, retcode); if (retcode == EPKG_OK && (flags & PKG_ADD_UPGRADE) == 0) pkg_emit_install_finished(pkg); cleanup: if (a != NULL) { archive_read_close(a); archive_read_free(a); } pkg_free(pkg); if (pkg_inst != NULL) pkg_free(pkg_inst); return (retcode); }
int event_callback(void *data, struct pkg_event *ev) { struct pkg *pkg = NULL; struct pkg_dep *dep = NULL; const char *message; int *debug = data; (void)debug; const char *name, *version, *newversion; switch(ev->type) { case PKG_EVENT_ERRNO: warn("%s(%s)", ev->e_errno.func, ev->e_errno.arg); break; case PKG_EVENT_ERROR: warnx("%s", ev->e_pkg_error.msg); break; case PKG_EVENT_FETCHING: if (fetched == 0) { strlcpy(url, ev->e_fetching.url, sizeof(url)); start_progress_meter(url, ev->e_fetching.total, &fetched); } fetched = ev->e_fetching.done; if (ev->e_fetching.done == ev->e_fetching.total) { stop_progress_meter(); fetched = 0; } break; case PKG_EVENT_INSTALL_BEGIN: pkg_get(ev->e_install_begin.pkg, PKG_NAME, &name, PKG_VERSION, &version); printf("Installing %s-%s...", name, version); fflush(stdout); break; case PKG_EVENT_INSTALL_FINISHED: printf(" done\n"); pkg_get(ev->e_install_finished.pkg, PKG_MESSAGE, &message); if (message != NULL && message[0] != '\0') printf("%s\n", message); break; case PKG_EVENT_INTEGRITYCHECK_BEGIN: printf("Checking integrity..."); fflush(stdout); break; case PKG_EVENT_INTEGRITYCHECK_FINISHED: printf(" done\n"); break; case PKG_EVENT_DEINSTALL_BEGIN: pkg_get(ev->e_deinstall_begin.pkg, PKG_NAME, &name, PKG_VERSION, &version); printf("Deinstalling %s-%s...", name, version); fflush(stdout); break; case PKG_EVENT_DEINSTALL_FINISHED: printf(" done\n"); break; case PKG_EVENT_UPGRADE_BEGIN: pkg_get(ev->e_upgrade_finished.pkg, PKG_NAME, &name, PKG_VERSION, &version, PKG_NEWVERSION, &newversion); printf("Upgrading %s from %s to %s...", name, version, newversion); fflush(stdout); break; case PKG_EVENT_UPGRADE_FINISHED: printf(" done\n"); break; case PKG_EVENT_REQUIRED: pkg = ev->e_required.pkg; pkg_get(pkg, PKG_NAME, &name, PKG_VERSION, &version); fprintf(stderr, "%s-%s is required by:", name, version); while (pkg_rdeps(pkg, &dep) == EPKG_OK) { fprintf(stderr, " %s", pkg_dep_get(dep, PKG_DEP_ORIGIN)); } if (ev->e_required.force == 1) fprintf(stderr, ", deleting anyway\n"); else fprintf(stderr, "\n"); break; case PKG_EVENT_ALREADY_INSTALLED: pkg_get(ev->e_already_installed.pkg, PKG_NAME, &name, PKG_VERSION, &version); printf("%s-%s already installed\n", name, version); break; default: break; } return 0; }