static void process_one_alternative(const char *altgrname, const char *val) { xbps_dictionary_t d; xbps_array_t a; char *altfiles; bool alloc = false; if ((d = xbps_dictionary_get(pkg_propsd, "alternatives")) == NULL) { d = xbps_dictionary_create(); assert(d); alloc = true; } if ((a = xbps_dictionary_get(d, altgrname)) == NULL) { a = xbps_array_create(); assert(a); } altfiles = strchr(val, ':') + 1; assert(altfiles); xbps_array_add_cstring(a, altfiles); xbps_dictionary_set(d, altgrname, a); xbps_dictionary_set(pkg_propsd, "alternatives", d); if (alloc) { xbps_object_release(a); xbps_object_release(d); } }
static void generate_full_revdeps_tree(struct xbps_handle *xhp) { xbps_object_t obj; xbps_object_iterator_t iter; if (xhp->pkgdb_revdeps) return; xhp->pkgdb_revdeps = xbps_dictionary_create(); assert(xhp->pkgdb_revdeps); iter = xbps_dictionary_iterator(xhp->pkgdb); assert(iter); while ((obj = xbps_object_iterator_next(iter))) { xbps_array_t rundeps; xbps_dictionary_t pkgd; const char *pkgver; pkgd = xbps_dictionary_get_keysym(xhp->pkgdb, obj); rundeps = xbps_dictionary_get(pkgd, "run_depends"); if (!xbps_array_count(rundeps)) continue; xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); for (unsigned int i = 0; i < xbps_array_count(rundeps); i++) { xbps_array_t pkg; const char *pkgdep, *vpkgname; char *curpkgname; bool alloc = false; xbps_array_get_cstring_nocopy(rundeps, i, &pkgdep); curpkgname = xbps_pkgpattern_name(pkgdep); if (curpkgname == NULL) curpkgname = xbps_pkg_name(pkgdep); assert(curpkgname); vpkgname = vpkg_user_conf(xhp, curpkgname); if (vpkgname == NULL) vpkgname = curpkgname; pkg = xbps_dictionary_get(xhp->pkgdb_revdeps, vpkgname); if (pkg == NULL) { alloc = true; pkg = xbps_array_create(); } if (!xbps_match_string_in_array(pkg, pkgver)) { xbps_array_add_cstring_nocopy(pkg, pkgver); xbps_dictionary_set(xhp->pkgdb_revdeps, vpkgname, pkg); } free(curpkgname); if (alloc) xbps_object_release(pkg); } } xbps_object_iterator_release(iter); }
/* * Verify reverse dependencies for packages in transaction. * This will catch cases where a package update would break its reverse dependencies: * * - foo-1.0 is being updated to 2.0. * - baz-1.1 depends on foo<2.0. * - foo is updated to 2.0, hence baz-1.1 is currently broken. * * Abort transaction if such case is found. */ static bool check_virtual_pkgs(xbps_array_t mdeps, xbps_dictionary_t trans_pkgd, xbps_dictionary_t rev_pkgd) { xbps_array_t provides; bool matched = false; provides = xbps_dictionary_get(trans_pkgd, "provides"); for (unsigned int i = 0; i < xbps_array_count(provides); i++) { xbps_array_t rundeps; const char *pkgver, *revpkgver, *pkgpattern; char *pkgname, *vpkgname, *vpkgver, *str; pkgver = revpkgver = pkgpattern = NULL; pkgname = vpkgname = vpkgver = str = NULL; xbps_dictionary_get_cstring_nocopy(trans_pkgd, "pkgver", &pkgver); xbps_dictionary_get_cstring_nocopy(rev_pkgd, "pkgver", &revpkgver); xbps_array_get_cstring(provides, i, &vpkgver); vpkgname = xbps_pkg_name(vpkgver); assert(vpkgname); rundeps = xbps_dictionary_get(rev_pkgd, "run_depends"); for (unsigned int x = 0; x < xbps_array_count(rundeps); x++) { xbps_array_get_cstring_nocopy(rundeps, x, &pkgpattern); if (((pkgname = xbps_pkgpattern_name(pkgpattern)) == NULL) && ((pkgname = xbps_pkg_name(pkgpattern)) == NULL)) continue; if (strcmp(vpkgname, pkgname)) { free(pkgname); continue; } free(pkgname); if (!strcmp(vpkgver, pkgpattern) || xbps_pkgpattern_match(vpkgver, pkgpattern)) { continue; } str = xbps_xasprintf("%s broken, needs '%s' virtual pkg (got `%s')", revpkgver, pkgpattern, vpkgver); xbps_array_add_cstring(mdeps, str); free(str); matched = true; } free(vpkgname); free(vpkgver); } return matched; }
static xbps_dictionary_t get_pkg_metadata(struct xbps_handle *xhp, xbps_dictionary_t pkgd) { xbps_dictionary_t pkg_metad; const char *pkgver; char *pkgname, *plist; xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); pkgname = xbps_pkg_name(pkgver); assert(pkgname); if ((pkg_metad = xbps_dictionary_get(xhp->pkg_metad, pkgname)) != NULL) { free(pkgname); return pkg_metad; } plist = xbps_xasprintf("%s/.%s.plist", xhp->metadir, pkgname); pkg_metad = xbps_dictionary_internalize_from_file(plist); free(plist); if (pkg_metad == NULL) { xbps_dbg_printf(xhp, "[pkgdb] cannot read %s metadata: %s\n", pkgver, strerror(errno)); free(pkgname); return NULL; } if (xhp->pkg_metad == NULL) xhp->pkg_metad = xbps_dictionary_create(); xbps_dictionary_set(xhp->pkg_metad, pkgname, pkg_metad); xbps_object_release(pkg_metad); free(pkgname); return pkg_metad; }
void list_files (xbps_dictionary_t filesd, const char *pkgver, void *arg) { xbps_array_t pkgfiles; const char *pkgname; struct config *cfg = arg; pkgname = xbps_pkg_name (pkgver); if (strcmp (pkgname, cfg->pattern) != 0) return; pkgfiles = xbps_dictionary_get (filesd, pkgver); for (unsigned int i = 0; i < xbps_array_count (pkgfiles); i++) { char *filestr = NULL; xbps_array_get_cstring (pkgfiles, i, &filestr); if (filestr == NULL) continue; printf ("%s: %s\n", pkgver, filestr); free (filestr); } }
static bool check_remove_pkg_files(struct xbps_handle *xhp, xbps_dictionary_t pkgd, const char *pkgver, uid_t euid) { struct stat st; xbps_array_t array; xbps_object_iterator_t iter; xbps_object_t obj; const char *objs[] = { "files", "conf_files", "links", "dirs" }; const char *file; char path[PATH_MAX]; bool fail = false; for (uint8_t i = 0; i < __arraycount(objs); i++) { array = xbps_dictionary_get(pkgd, objs[i]); if (array == NULL || xbps_array_count(array) == 0) continue; iter = xbps_array_iter_from_dict(pkgd, objs[i]); if (iter == NULL) continue; while ((obj = xbps_object_iterator_next(iter))) { xbps_dictionary_get_cstring_nocopy(obj, "file", &file); snprintf(path, sizeof(path), "%s/%s", xhp->rootdir, file); /* * Check if effective user ID owns the file; this is * enough to ensure the user has write permissions * on the directory. */ if (euid == 0 || (!lstat(path, &st) && euid == st.st_uid)) { /* success */ continue; } if (errno != ENOENT) { /* * only bail out if something else than ENOENT * is returned. */ int rv = errno; if (rv == 0) { /* lstat succeeds but euid != uid */ rv = EPERM; } fail = true; xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE_FAIL, rv, pkgver, "%s: cannot remove `%s': %s", pkgver, file, strerror(rv)); } errno = 0; } xbps_object_iterator_release(iter); } return fail; }
static int pkgdb_map_vpkgs(struct xbps_handle *xhp) { xbps_object_iterator_t iter; xbps_object_t obj; int rv = 0; if (!xbps_dictionary_count(xhp->pkgdb)) return 0; if (xhp->vpkgd == NULL) { xhp->vpkgd = xbps_dictionary_create(); assert(xhp->vpkgd); } /* * This maps all pkgs that have virtualpkgs in pkgdb. */ iter = xbps_dictionary_iterator(xhp->pkgdb); assert(iter); while ((obj = xbps_object_iterator_next(iter))) { xbps_array_t provides; xbps_dictionary_t pkgd; const char *pkgver; char *pkgname; pkgd = xbps_dictionary_get_keysym(xhp->pkgdb, obj); provides = xbps_dictionary_get(pkgd, "provides"); if (provides == NULL) continue; xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); pkgname = xbps_pkg_name(pkgver); assert(pkgname); for (unsigned int i = 0; i < xbps_array_count(provides); i++) { const char *vpkg; xbps_array_get_cstring_nocopy(provides, i, &vpkg); if (!xbps_dictionary_set_cstring(xhp->vpkgd, vpkg, pkgname)) { xbps_dbg_printf(xhp, "%s: set_cstring vpkg " "%s pkgname %s\n", __func__, vpkg, pkgname); rv = EINVAL; } else { xbps_dbg_printf(xhp, "[pkgdb] added vpkg %s for %s\n", vpkg, pkgname); } } free(pkgname); } xbps_object_iterator_release(iter); return rv; }
bool xbps_pkg_has_rundeps(xbps_dictionary_t pkgd) { xbps_array_t array; assert(xbps_object_type(pkgd) == XBPS_TYPE_DICTIONARY); array = xbps_dictionary_get(pkgd, "run_depends"); if (xbps_array_count(array)) return true; return false; }
int HIDDEN xbps_repository_find_deps(struct xbps_handle *xhp, xbps_array_t unsorted, xbps_dictionary_t repo_pkgd) { xbps_array_t pkg_rdeps, pkg_provides = NULL; const char *pkgver; unsigned short depth = 0; pkg_rdeps = xbps_dictionary_get(repo_pkgd, "run_depends"); if (xbps_array_count(pkg_rdeps) == 0) return 0; xbps_dictionary_get_cstring_nocopy(repo_pkgd, "pkgver", &pkgver); xbps_dbg_printf(xhp, "Finding required dependencies for '%s':\n", pkgver); /* * This will find direct and indirect deps, if any of them is not * there it will be added into the missing_deps array. */ pkg_provides = xbps_dictionary_get(repo_pkgd, "provides"); return find_repo_deps(xhp, unsorted, pkg_rdeps, pkg_provides, pkgver, &depth); }
static xbps_array_t merge_filelist(xbps_dictionary_t d) { xbps_array_t a, result; xbps_dictionary_t filed; unsigned int i; result = xbps_array_create(); assert(result); if ((a = xbps_dictionary_get(d, "files"))) { for (i = 0; i < xbps_array_count(a); i++) { filed = xbps_array_get(a, i); xbps_array_add(result, filed); } } if ((a = xbps_dictionary_get(d, "links"))) { for (i = 0; i < xbps_array_count(a); i++) { filed = xbps_array_get(a, i); xbps_array_add(result, filed); } } if ((a = xbps_dictionary_get(d, "conf_files"))) { for (i = 0; i < xbps_array_count(a); i++) { filed = xbps_array_get(a, i); xbps_array_add(result, filed); } } if ((a = xbps_dictionary_get(d, "dirs"))) { for (i = 0; i < xbps_array_count(a); i++) { filed = xbps_array_get(a, i); xbps_array_add(result, filed); } } return result; }
static void shlib_register(xbps_dictionary_t d, const char *shlib, const char *pkgver) { xbps_array_t array; bool alloc = false; if ((array = xbps_dictionary_get(d, shlib)) == NULL) { alloc = true; array = xbps_array_create(); xbps_dictionary_set(d, shlib, array); } if (!xbps_match_string_in_array(array, pkgver)) xbps_array_add_cstring_nocopy(array, pkgver); if (alloc) xbps_object_release(array); }
int check_pkg_symlinks(struct xbps_handle *xhp, const char *pkgname, void *arg) { xbps_array_t array; xbps_object_t obj; xbps_dictionary_t filesd = arg; int rv = 0; array = xbps_dictionary_get(filesd, "links"); if (array == NULL) return 0; for (unsigned int i = 0; i < xbps_array_count(array); i++) { const char *file = NULL, *tgt = NULL; char path[PATH_MAX], *lnk = NULL; obj = xbps_array_get(array, i); if (!xbps_dictionary_get_cstring_nocopy(obj, "file", &file)) continue; if (!xbps_dictionary_get_cstring_nocopy(obj, "target", &tgt)) { xbps_warn_printf("%s: `%s' symlink with " "empty target object!\n", pkgname, file); continue; } if (tgt[0] == '\0') { xbps_warn_printf("%s: `%s' symlink with " "empty target object!\n", pkgname, file); continue; } snprintf(path, sizeof(path), "%s/%s", xhp->rootdir, file); if ((lnk = xbps_symlink_target(xhp, path, tgt)) == NULL) { xbps_error_printf("%s: broken symlink %s (target: %s)\n", pkgname, file, tgt); rv = -1; continue; } if (strcmp(lnk, tgt)) { xbps_warn_printf("%s: modified symlink %s " "points to %s (shall be %s)\n", pkgname, file, lnk, tgt); rv = -1; } free(lnk); } return rv; }
int show_pkg_deps(struct xbps_handle *xhp, const char *pkgname, bool full) { xbps_array_t rdeps; xbps_dictionary_t pkgd; int indent = 0; pkgd = xbps_pkgdb_get_pkg(xhp, pkgname); if (pkgd == NULL) return ENOENT; rdeps = xbps_dictionary_get(pkgd, "run_depends"); if (rdeps != NULL) print_rdeps(xhp, rdeps, full, false, true, &indent); return 0; }
int repo_show_pkg_deps(struct xbps_handle *xhp, const char *pattern, bool full) { xbps_array_t rdeps; xbps_dictionary_t pkgd; int indent = 0; if (((pkgd = xbps_rpool_get_pkg(xhp, pattern)) == NULL) && ((pkgd = xbps_rpool_get_virtualpkg(xhp, pattern)) == NULL)) return errno; rdeps = xbps_dictionary_get(pkgd, "run_depends"); if (rdeps != NULL) print_rdeps(xhp, rdeps, full, true, true, &indent); return 0; }
bool HIDDEN xbps_transaction_shlibs(struct xbps_handle *xhp, xbps_array_t pkgs, xbps_array_t mshlibs) { xbps_object_t obj; xbps_object_iterator_t iter; xbps_dictionary_t shrequires, shprovides; bool unmatched = false; shrequires = collect_shlibs(xhp, pkgs, true); shprovides = collect_shlibs(xhp, pkgs, false); /* iterate over shlib-requires to find unmatched shlibs */ iter = xbps_dictionary_iterator(shrequires); assert(iter); while ((obj = xbps_object_iterator_next(iter))) { xbps_array_t array; const char *pkgver, *shlib; char *buf; shlib = xbps_dictionary_keysym_cstring_nocopy(obj); xbps_dbg_printf(xhp, "%s: checking for `%s': ", __func__, shlib); if (xbps_dictionary_get(shprovides, shlib)) { xbps_dbg_printf_append(xhp, "found\n"); continue; } xbps_dbg_printf_append(xhp, "not found\n"); unmatched = true; array = xbps_dictionary_get_keysym(shrequires, obj); for (unsigned int i = 0; i < xbps_array_count(array); i++) { xbps_array_get_cstring_nocopy(array, i, &pkgver); buf = xbps_xasprintf("%s: broken, unresolvable " "shlib `%s'", pkgver, shlib); xbps_array_add_cstring(mshlibs, buf); free(buf); } xbps_object_release(array); } xbps_object_iterator_release(iter); xbps_object_release(shprovides); return unmatched; }
xbps_array_t xbps_pkgdb_get_pkg_revdeps(struct xbps_handle *xhp, const char *pkg) { xbps_array_t res; xbps_dictionary_t pkgd; const char *pkgver; char *pkgname; if ((pkgd = xbps_pkgdb_get_pkg(xhp, pkg)) == NULL) return NULL; generate_full_revdeps_tree(xhp); xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); pkgname = xbps_pkg_name(pkgver); res = xbps_dictionary_get(xhp->pkgdb_revdeps, pkgname); free(pkgname); return res; }
xbps_array_t xbps_repo_get_pkg_revdeps(struct xbps_repo *repo, const char *pkg) { xbps_array_t revdeps = NULL, vdeps = NULL; xbps_dictionary_t pkgd; const char *vpkg; bool match = false; if (repo->idx == NULL) return NULL; if (((pkgd = xbps_repo_get_pkg(repo, pkg)) == NULL) && ((pkgd = xbps_repo_get_virtualpkg(repo, pkg)) == NULL)) { errno = ENOENT; return NULL; } /* * If pkg is a virtual pkg let's match it instead of the real pkgver. */ if ((vdeps = xbps_dictionary_get(pkgd, "provides"))) { for (unsigned int i = 0; i < xbps_array_count(vdeps); i++) { char *vpkgn; xbps_array_get_cstring_nocopy(vdeps, i, &vpkg); vpkgn = xbps_pkg_name(vpkg); assert(vpkgn); if (strcmp(vpkgn, pkg) == 0) { free(vpkgn); match = true; break; } free(vpkgn); vpkg = NULL; } if (match) revdeps = revdeps_match(repo, pkgd, vpkg); } if (!match) revdeps = revdeps_match(repo, pkgd, NULL); return revdeps; }
static bool entry_is_conf_file(const char *file) { xbps_array_t a; const char *curfile; unsigned int i; assert(file); a = xbps_dictionary_get(pkg_propsd, "conf_files"); if (a == NULL || xbps_array_count(a) == 0) return false; for (i = 0; i < xbps_array_count(a); i++) { xbps_array_get_cstring_nocopy(a, i, &curfile); if (strcmp(file, curfile) == 0) return true; } return false; }
/* * Check if pkg is explicitly marked to replace a specific installed version. */ bool xbps_pkg_reverts(xbps_dictionary_t pkg, const char *pkgver) { unsigned int i; xbps_array_t reverts; const char *version = xbps_pkg_version(pkgver); const char *revertver; if ((reverts = xbps_dictionary_get(pkg, "reverts")) == NULL) return false; for (i = 0; i < xbps_array_count(reverts); i++) { xbps_array_get_cstring_nocopy(reverts, i, &revertver); if (strcmp(version, revertver) == 0) { return true; } } return false; }
/* * Returns true if entry is a configuration file, false otherwise. */ int HIDDEN xbps_entry_is_a_conf_file(xbps_dictionary_t filesd, const char *entry_pname) { xbps_array_t array; xbps_dictionary_t d; const char *cffile; array = xbps_dictionary_get(filesd, "conf_files"); if (xbps_array_count(array) == 0) return false; for (unsigned int i = 0; i < xbps_array_count(array); i++) { d = xbps_array_get(array, i); xbps_dictionary_get_cstring_nocopy(d, "file", &cffile); if (strcmp(cffile, entry_pname) == 0) return true; } return false; }
static void print_rdeps(struct xbps_handle *xhp, xbps_array_t rdeps, bool full, bool repo, bool origin, int *indent) { xbps_array_t currdeps; xbps_dictionary_t pkgd; const char *pkgdep; unsigned int i; int j; if (!origin) (*indent)++; for (i = 0; i < xbps_array_count(rdeps); i++) { xbps_array_get_cstring_nocopy(rdeps, i, &pkgdep); if (!origin || !full) for (j = 0; j < *indent; j++) putchar(' '); printf("%s\n", pkgdep); if (!full) continue; if (repo) { pkgd = xbps_rpool_get_pkg(xhp, pkgdep); if (pkgd == NULL) pkgd = xbps_rpool_get_virtualpkg(xhp, pkgdep); } else { pkgd = xbps_pkgdb_get_pkg(xhp, pkgdep); if (pkgd == NULL) pkgd = xbps_pkgdb_get_virtualpkg(xhp, pkgdep); } if (pkgd != NULL) { currdeps = xbps_dictionary_get(pkgd, "run_depends"); if (currdeps != NULL) print_rdeps(xhp, currdeps, full, repo, false, indent); } } (*indent)--; }
void match_files_by_pattern (xbps_dictionary_t filesd, const char *pkgver, void *arg) { xbps_array_t pkgfiles; struct config *cfg = arg; pkgfiles = xbps_dictionary_get (filesd, pkgver); for (unsigned int i = 0; i < xbps_array_count (pkgfiles); i++) { char *filestr = NULL; xbps_array_get_cstring (pkgfiles, i, &filestr); if (filestr == NULL) continue; if (fnmatch (cfg->pattern, filestr, FNM_PERIOD) == 0) printf ("\033[0;1m%s:\033[0m %s\n", pkgver, filestr); free (filestr); } }
/* * Returns true if entry is a configuration file, false otherwise. */ int HIDDEN xbps_entry_is_a_conf_file(xbps_dictionary_t propsd, const char *entry_pname) { xbps_array_t array; const char *cffile; unsigned int i; assert(xbps_object_type(propsd) == XBPS_TYPE_DICTIONARY); assert(entry_pname != NULL); array = xbps_dictionary_get(propsd, "conf_files"); if (xbps_array_count(array) == 0) return false; for (i = 0; i < xbps_array_count(array); i++) { xbps_array_get_cstring_nocopy(array, i, &cffile); if (strcmp(cffile, entry_pname) == 0) return true; } return false; }
static const char * find_pkg_symlink_target(xbps_dictionary_t d, const char *file) { xbps_array_t links; xbps_object_t obj; unsigned int i; const char *pkgfile, *tgt = NULL; char *rfile; assert(d); links = xbps_dictionary_get(d, "links"); for (i = 0; i < xbps_array_count(links); i++) { rfile = strchr(file, '.') + 1; obj = xbps_array_get(links, i); xbps_dictionary_get_cstring_nocopy(obj, "file", &pkgfile); if (strcmp(rfile, pkgfile) == 0) { xbps_dictionary_get_cstring_nocopy(obj, "target", &tgt); break; } } return tgt; }
bool xbps_verify_file_signature(struct xbps_repo *repo, const char *fname) { xbps_dictionary_t repokeyd = NULL; xbps_data_t pubkey; char *hexfp = NULL; unsigned char *digest = NULL, *sig_buf = NULL; size_t sigbuflen, sigfilelen; char *rkeyfile = NULL, *sig = NULL; bool val = false; if (!xbps_dictionary_count(repo->idxmeta)) { xbps_dbg_printf(repo->xhp, "%s: unsigned repository\n", repo->uri); return false; } hexfp = xbps_pubkey2fp(repo->xhp, xbps_dictionary_get(repo->idxmeta, "public-key")); if (hexfp == NULL) { xbps_dbg_printf(repo->xhp, "%s: incomplete signed repo, missing hexfp obj\n", repo->uri); return false; } /* * Prepare repository RSA public key to verify fname signature. */ rkeyfile = xbps_xasprintf("%s/keys/%s.plist", repo->xhp->metadir, hexfp); repokeyd = xbps_plist_dictionary_from_file(repo->xhp, rkeyfile); if (xbps_object_type(repokeyd) != XBPS_TYPE_DICTIONARY) { xbps_dbg_printf(repo->xhp, "cannot read rkey data at %s: %s\n", rkeyfile, strerror(errno)); goto out; } pubkey = xbps_dictionary_get(repokeyd, "public-key"); if (xbps_object_type(pubkey) != XBPS_TYPE_DATA) goto out; /* * Prepare fname and signature data buffers. */ if (!(digest = xbps_file_hash_raw(fname))) { xbps_dbg_printf(repo->xhp, "can't open file %s: %s\n", fname, strerror(errno)); goto out; } sig = xbps_xasprintf("%s.sig", fname); if (!xbps_mmap_file(sig, (void *)&sig_buf, &sigbuflen, &sigfilelen)) { xbps_dbg_printf(repo->xhp, "can't open signature file %s: %s\n", sig, strerror(errno)); goto out; } /* * Verify fname RSA signature. */ if (rsa_verify_hash(repo, pubkey, sig_buf, sigfilelen, digest)) val = true; out: if (hexfp) free(hexfp); if (rkeyfile) free(rkeyfile); if (digest) free(digest); if (sig_buf) (void)munmap(sig_buf, sigbuflen); if (sig) free(sig); if (repokeyd) xbps_object_release(repokeyd); return val; }
int HIDDEN xbps_remove_pkg_files(struct xbps_handle *xhp, xbps_dictionary_t dict, const char *key, const char *pkgver) { struct stat st; xbps_array_t array; xbps_object_iterator_t iter; xbps_object_t obj; const char *file, *sha256, *curobj = NULL; char *path = NULL, *pkgname = NULL; char buf[PATH_MAX]; int rv = 0; assert(xbps_object_type(dict) == XBPS_TYPE_DICTIONARY); assert(key != NULL); array = xbps_dictionary_get(dict, key); if (xbps_array_count(array) == 0) return 0; iter = xbps_array_iter_from_dict(dict, key); if (iter == NULL) return ENOMEM; if (strcmp(key, "files") == 0) curobj = "file"; else if (strcmp(key, "conf_files") == 0) curobj = "configuration file"; else if (strcmp(key, "links") == 0) curobj = "link"; else if (strcmp(key, "dirs") == 0) curobj = "directory"; pkgname = xbps_pkg_name(pkgver); assert(pkgname); while ((obj = xbps_object_iterator_next(iter))) { xbps_dictionary_get_cstring_nocopy(obj, "file", &file); path = xbps_xasprintf("%s/%s", xhp->rootdir, file); if ((strcmp(key, "files") == 0) || (strcmp(key, "conf_files") == 0)) { /* * Check SHA256 hash in regular files and * configuration files. */ xbps_dictionary_get_cstring_nocopy(obj, "sha256", &sha256); rv = xbps_file_hash_check(path, sha256); if (rv == ENOENT) { /* missing file, ignore it */ xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE_HASH_FAIL, rv, pkgver, "%s: failed to check hash for %s `%s': %s", pkgver, curobj, file, strerror(rv)); free(path); rv = 0; continue; } else if (rv == ERANGE) { rv = 0; if ((xhp->flags & XBPS_FLAG_FORCE_REMOVE_FILES) == 0) { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE_HASH_FAIL, 0, pkgver, "%s: %s `%s' SHA256 mismatch, " "preserving file", pkgver, curobj, file); free(path); continue; } else { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE_HASH_FAIL, 0, pkgver, "%s: %s `%s' SHA256 mismatch, " "forcing removal", pkgver, curobj, file); } } else if (rv != 0 && rv != ERANGE) { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE_HASH_FAIL, rv, pkgver, "%s: [remove] failed to check hash for " "%s `%s': %s", pkgver, curobj, file, strerror(rv)); free(path); break; } } else if (strcmp(key, "links") == 0) { /* * All regular files from package were removed at this * point, so we will only remove dangling symlinks. */ if (realpath(path, buf) == NULL) { if (errno != ENOENT && errno != ELOOP) { free(path); rv = errno; break; } } if (stat(buf, &st) == 0) { free(path); continue; } } /* * Remove the object if possible. */ if (remove(path) == -1) { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE_FAIL, errno, pkgver, "%s: failed to remove %s `%s': %s", pkgver, curobj, file, strerror(errno)); errno = 0; } else { /* success */ xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE, 0, pkgver, "Removed %s `%s'", curobj, file); } free(path); } xbps_object_iterator_release(iter); free(pkgname); return rv; }
int HIDDEN xbps_transaction_package_replace(struct xbps_handle *xhp, xbps_array_t pkgs) { for (unsigned int i = 0; i < xbps_array_count(pkgs); i++) { xbps_array_t replaces; xbps_object_t obj, obj2; xbps_object_iterator_t iter; const char *pkgver; char *pkgname; obj = xbps_array_get(pkgs, i); replaces = xbps_dictionary_get(obj, "replaces"); if (replaces == NULL || xbps_array_count(replaces) == 0) continue; iter = xbps_array_iterator(replaces); assert(iter); xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); pkgname = xbps_pkg_name(pkgver); assert(pkgname); while ((obj2 = xbps_object_iterator_next(iter)) != NULL) { xbps_dictionary_t instd, reppkgd; const char *tract, *pattern, *curpkgver; char *curpkgname; bool instd_auto = false; pattern = xbps_string_cstring_nocopy(obj2); /* * Find the installed package that matches the pattern * to be replaced. */ if (((instd = xbps_pkgdb_get_pkg(xhp, pattern)) == NULL) && ((instd = xbps_pkgdb_get_virtualpkg(xhp, pattern)) == NULL)) continue; xbps_dictionary_get_cstring_nocopy(instd, "pkgver", &curpkgver); curpkgname = xbps_pkg_name(curpkgver); assert(curpkgname); /* * Check that we are not replacing the same package, * due to virtual packages. */ if (strcmp(pkgname, curpkgname) == 0) { free(curpkgname); continue; } /* * Make sure to not add duplicates. */ xbps_dictionary_get_bool(instd, "automatic-install", &instd_auto); reppkgd = xbps_find_pkg_in_array(pkgs, curpkgname, NULL); if (reppkgd) { xbps_dictionary_get_cstring_nocopy(reppkgd, "transaction", &tract); if (strcmp(tract, "remove") == 0) continue; /* * Package contains replaces="pkgpattern", but the * package that should be replaced is also in the * transaction and it's going to be updated. */ xbps_dictionary_set_bool(reppkgd, "automatic-install", instd_auto); xbps_array_replace_dict_by_name(pkgs, reppkgd, curpkgname); continue; } /* * If new package is providing a virtual package to the * package that we want to replace we should respect * the automatic-install object. */ if (xbps_match_virtual_pkg_in_dict(obj, pattern)) { xbps_dictionary_set_bool(obj, "automatic-install", instd_auto); } xbps_dbg_printf(xhp, "Package `%s' will be replaced by `%s', " "matched with `%s'\n", curpkgver, pkgver, pattern); /* * Add package dictionary into the transaction and mark * it as to be "removed". */ xbps_dictionary_set_cstring_nocopy(instd, "transaction", "remove"); if (!xbps_array_add_first(pkgs, instd)) return EINVAL; free(curpkgname); } xbps_object_iterator_release(iter); free(pkgname); } return 0; }
int sign_repo(struct xbps_handle *xhp, const char *repodir, const char *privkey, const char *signedby) { struct stat st; struct xbps_repo *repo; xbps_dictionary_t pkgd, meta = NULL; xbps_data_t data = NULL, rpubkey = NULL; xbps_object_iterator_t iter = NULL; xbps_object_t obj; RSA *rsa = NULL; unsigned char *sig; unsigned int siglen; uint16_t rpubkeysize, pubkeysize; const char *arch, *pkgver, *rsignedby = NULL; char *binpkg = NULL, *binpkg_sig = NULL, *buf = NULL, *defprivkey = NULL; int binpkg_fd, binpkg_sig_fd, rv = 0; bool flush = false; if (signedby == NULL) { fprintf(stderr, "--signedby unset! cannot sign repository\n"); return -1; } /* * Check that repository index exists and not empty, otherwise bail out. */ repo = xbps_repo_open(xhp, repodir, true); if (repo == NULL) { rv = errno; fprintf(stderr, "%s: cannot read repository data: %s\n", _XBPS_RINDEX, strerror(errno)); goto out; } if (xbps_dictionary_count(repo->idx) == 0) { fprintf(stderr, "%s: invalid repository, existing!\n", _XBPS_RINDEX); rv = EINVAL; goto out; } /* * If privkey not set, default to ~/.ssh/id_rsa. */ if (privkey == NULL) defprivkey = xbps_xasprintf("%s/.ssh/id_rsa", getenv("HOME")); else defprivkey = strdup(privkey); ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); OpenSSL_add_all_ciphers(); OpenSSL_add_all_digests(); if ((rsa = load_rsa_privkey(defprivkey)) == NULL) { fprintf(stderr, "%s: failed to read the RSA privkey\n", _XBPS_RINDEX); rv = EINVAL; goto out; } /* * Iterate over the idx dictionary and then sign all binary * packages in this repository. */ iter = xbps_dictionary_iterator(repo->idx); assert(iter); while ((obj = xbps_object_iterator_next(iter))) { pkgd = xbps_dictionary_get_keysym(repo->idx, obj); xbps_dictionary_get_cstring_nocopy(pkgd, "architecture", &arch); xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); binpkg = xbps_xasprintf("%s/%s.%s.xbps", repodir, pkgver, arch); binpkg_sig = xbps_xasprintf("%s.sig", binpkg); /* * Skip pkg if file signature exists */ if ((binpkg_sig_fd = access(binpkg_sig, R_OK)) == 0) { if (xhp->flags & XBPS_FLAG_VERBOSE) fprintf(stderr, "skipping %s, file signature found.\n", pkgver); free(binpkg); free(binpkg_sig); close(binpkg_sig_fd); continue; } /* * Generate pkg file signature. */ if ((binpkg_fd = open(binpkg, O_RDONLY)) == -1) { fprintf(stderr, "cannot read %s: %s\n", binpkg, strerror(errno)); free(binpkg); free(binpkg_sig); continue; } fstat(binpkg_fd, &st); buf = malloc(st.st_size); assert(buf); if (read(binpkg_fd, buf, st.st_size) != st.st_size) { fprintf(stderr, "failed to read %s: %s\n", binpkg, strerror(errno)); close(binpkg_fd); free(buf); free(binpkg); free(binpkg_sig); continue; } close(binpkg_fd); if (!rsa_sign_buf(rsa, buf, st.st_size, &sig, &siglen)) { fprintf(stderr, "failed to sign %s: %s\n", binpkg, strerror(errno)); free(buf); free(binpkg); free(binpkg_sig); continue; } free(buf); free(binpkg); /* * Write pkg file signature. */ binpkg_sig_fd = creat(binpkg_sig, 0644); if (binpkg_sig_fd == -1) { fprintf(stderr, "failed to create %s: %s\n", binpkg_sig, strerror(errno)); free(sig); free(binpkg_sig); continue; } if (write(binpkg_sig_fd, sig, siglen) != (ssize_t)siglen) { fprintf(stderr, "failed to write %s: %s\n", binpkg_sig, strerror(errno)); free(sig); free(binpkg_sig); close(binpkg_sig_fd); continue; } free(sig); free(binpkg_sig); close(binpkg_sig_fd); printf("signed successfully %s\n", pkgver); } xbps_object_iterator_release(iter); /* * Check if repository index-meta contains changes compared to its * current state. */ if ((buf = pubkey_from_privkey(rsa)) == NULL) { rv = EINVAL; goto out; } meta = xbps_dictionary_create(); data = xbps_data_create_data(buf, strlen(buf)); rpubkey = xbps_dictionary_get(repo->idxmeta, "public-key"); if (!xbps_data_equals(rpubkey, data)) flush = true; free(buf); pubkeysize = RSA_size(rsa) * 8; xbps_dictionary_get_uint16(repo->idxmeta, "public-key-size", &rpubkeysize); if (rpubkeysize != pubkeysize) flush = true; xbps_dictionary_get_cstring_nocopy(repo->idxmeta, "signature-by", &rsignedby); if (rsignedby == NULL || strcmp(rsignedby, signedby)) flush = true; if (!flush) goto out; xbps_dictionary_set(meta, "public-key", data); xbps_dictionary_set_uint16(meta, "public-key-size", pubkeysize); xbps_dictionary_set_cstring_nocopy(meta, "signature-by", signedby); xbps_dictionary_set_cstring_nocopy(meta, "signature-type", "rsa"); xbps_object_release(data); data = NULL; if (!repodata_flush(xhp, repodir, repo->idx, meta)) { fprintf(stderr, "failed to write repodata: %s\n", strerror(errno)); goto out; } printf("Signed repository (%u package%s)\n", xbps_dictionary_count(repo->idx), xbps_dictionary_count(repo->idx) == 1 ? "" : "s"); out: if (defprivkey) { free(defprivkey); } if (rsa) { RSA_free(rsa); rsa = NULL; } if (repo) { xbps_repo_close(repo); } return rv ? -1 : 0; }
/* * Verify reverse dependencies for packages in transaction. * This will catch cases where a package update would break its reverse dependencies: * * - foo-1.0 is being updated to 2.0. * - baz-1.1 depends on foo<2.0. * - foo is updated to 2.0, hence baz-1.1 is currently broken. * * Abort transaction if such case is found. */ static bool check_virtual_pkgs(struct xbps_handle *xhp, xbps_dictionary_t trans_pkgd, xbps_dictionary_t rev_pkgd) { xbps_array_t unsorted, provides, rundeps, mdeps; const char *pkgver, *revpkgver, *pkgpattern; char *pkgname, *pkgdepname, *vpkgname, *vpkgver, *str; unsigned int i, x; bool matched = false; unsorted = xbps_dictionary_get(xhp->transd, "unsorted_deps"); provides = xbps_dictionary_get(trans_pkgd, "provides"); for (i = 0; i < xbps_array_count(provides); i++) { char *tmp = NULL; xbps_array_get_cstring(provides, i, &vpkgver); if (strchr(vpkgver, '_') == NULL) { tmp = xbps_xasprintf("%s_1", vpkgver); vpkgver = strdup(tmp); } vpkgname = xbps_pkg_name(vpkgver); assert(vpkgname); rundeps = xbps_dictionary_get(rev_pkgd, "run_depends"); for (x = 0; x < xbps_array_count(rundeps); x++) { xbps_array_get_cstring_nocopy(rundeps, x, &pkgpattern); if (((pkgname = xbps_pkgpattern_name(pkgpattern)) == NULL) && ((pkgname = xbps_pkg_name(pkgpattern)) == NULL)) continue; if (strcmp(vpkgname, pkgname)) { free(pkgname); continue; } free(pkgname); if (xbps_pkgpattern_match(vpkgver, pkgpattern)) continue; /* * Installed package conflicts with package * in transaction being updated, check * if a new version of this conflicting package * is in the transaction. */ xbps_dictionary_get_cstring_nocopy(trans_pkgd, "pkgver", &pkgver); pkgdepname = xbps_pkg_name(pkgver); assert(pkgdepname); if (xbps_find_pkg_in_array(unsorted, pkgdepname)) { free(pkgdepname); continue; } free(pkgdepname); mdeps = xbps_dictionary_get(xhp->transd, "missing_deps"); xbps_dictionary_get_cstring_nocopy(trans_pkgd, "pkgver", &pkgver); xbps_dictionary_get_cstring_nocopy(rev_pkgd, "pkgver", &revpkgver); str = xbps_xasprintf("CONFLICT: `%s' update " "breaks `%s', needs `%s' virtual pkg (got `%s`)", pkgver, revpkgver, pkgpattern, vpkgver); xbps_array_add_cstring(mdeps, str); free(str); matched = true; } free(vpkgname); free(vpkgver); } return matched; }
void HIDDEN xbps_transaction_revdeps(struct xbps_handle *xhp) { xbps_array_t mdeps, unsorted, pkgrdeps, rundeps; xbps_dictionary_t revpkgd; xbps_object_t obj; const char *pkgver, *curdep, *revpkgver, *curpkgver, *tract; char *pkgname, *curdepname, *curpkgname, *str; unsigned int i, j, x; unsorted = xbps_dictionary_get(xhp->transd, "unsorted_deps"); for (i = 0; i < xbps_array_count(unsorted); i++) { obj = xbps_array_get(unsorted, i); /* * Only check packages in transaction being updated. */ xbps_dictionary_get_cstring_nocopy(obj, "transaction", &tract); if (strcmp(tract, "update")) continue; /* * if pkg in transaction is not installed, * pass to next one. */ xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); pkgname = xbps_pkg_name(pkgver); assert(pkgname); if (xbps_pkg_is_installed(xhp, pkgname) == 0) { free(pkgname); continue; } /* * If pkg is installed but does not have revdeps, * pass to next one. */ pkgrdeps = xbps_pkgdb_get_pkg_revdeps(xhp, pkgname); if (!xbps_array_count(pkgrdeps)) { free(pkgname); continue; } free(pkgname); /* * Time to validate revdeps for current pkg. */ for (x = 0; x < xbps_array_count(pkgrdeps); x++) { bool found = false; xbps_array_get_cstring_nocopy(pkgrdeps, x, &curpkgver); revpkgd = xbps_pkgdb_get_pkg(xhp, curpkgver); /* * First try to match any supported virtual package. */ if (check_virtual_pkgs(xhp, obj, revpkgd)) continue; /* * Try to match real dependencies. */ rundeps = xbps_dictionary_get(revpkgd, "run_depends"); /* * Find out what dependency is it. */ curpkgname = xbps_pkg_name(pkgver); assert(curpkgname); for (j = 0; j < xbps_array_count(rundeps); j++) { xbps_array_get_cstring_nocopy(rundeps, j, &curdep); if (((curdepname = xbps_pkg_name(curdep)) == NULL) && ((curdepname = xbps_pkgpattern_name(curdep)) == NULL)) abort(); if (strcmp(curdepname, curpkgname) == 0) { free(curdepname); found = true; break; } free(curdepname); } if (!found) continue; if (xbps_match_pkgdep_in_array(rundeps, pkgver)) continue; /* * Installed package conflicts with package * in transaction being updated, check * if a new version of this conflicting package * is in the transaction. */ pkgname = xbps_pkg_name(curpkgver); if (xbps_find_pkg_in_array(unsorted, pkgname)) { free(pkgname); continue; } free(pkgname); mdeps = xbps_dictionary_get(xhp->transd, "missing_deps"); xbps_dictionary_get_cstring_nocopy(revpkgd, "pkgver", &revpkgver); str = xbps_xasprintf("CONFLICT: `%s' " "update breaks `%s', needs `%s'", pkgver, revpkgver, curdep); xbps_array_add_cstring(mdeps, str); free(str); } } }