static int check_binpkgs_hash(struct xbps_handle *xhp, prop_object_iterator_t iter) { prop_object_t obj; const char *pkgver, *repoloc, *filen, *sha256, *trans; const char *pkgname, *version; char *binfile; int rv = 0; while ((obj = prop_object_iterator_next(iter)) != NULL) { prop_dictionary_get_cstring_nocopy(obj, "transaction", &trans); if ((strcmp(trans, "remove") == 0) || (strcmp(trans, "configure") == 0)) continue; prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname); prop_dictionary_get_cstring_nocopy(obj, "version", &version); prop_dictionary_get_cstring_nocopy(obj, "repository", &repoloc); assert(repoloc != NULL); prop_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); assert(pkgver != NULL); prop_dictionary_get_cstring_nocopy(obj, "filename", &filen); assert(filen != NULL); prop_dictionary_get_cstring_nocopy(obj, "filename-sha256", &sha256); assert(sha256 != NULL); binfile = xbps_path_from_repository_uri(xhp, obj, repoloc); if (binfile == NULL) { rv = EINVAL; break; } xbps_set_cb_state(xhp, XBPS_STATE_VERIFY, 0, pkgname, version, "Verifying `%s' package integrity...", filen, repoloc); rv = xbps_file_hash_check(binfile, sha256); if (rv != 0) { free(binfile); xbps_set_cb_state(xhp, XBPS_STATE_VERIFY_FAIL, rv, pkgname, version, "Failed to verify `%s' package integrity: %s", filen, strerror(rv)); break; } free(binfile); } prop_object_iterator_reset(iter); return rv; }
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; }
xbps_array_t xbps_find_pkg_obsoletes(struct xbps_handle *xhp, xbps_dictionary_t instd, xbps_dictionary_t newd) { xbps_array_t instfiles, newfiles, obsoletes; xbps_object_t obj, obj2; xbps_string_t oldstr, newstr; unsigned int i, x; const char *oldhash; char *file; int rv = 0; bool found; assert(xbps_object_type(instd) == XBPS_TYPE_DICTIONARY); assert(xbps_object_type(newd) == XBPS_TYPE_DICTIONARY); obsoletes = xbps_array_create(); assert(obsoletes); instfiles = merge_filelist(instd); if (xbps_array_count(instfiles) == 0) { /* nothing to check if current pkg does not own any file */ xbps_object_release(instfiles); return obsoletes; } newfiles = merge_filelist(newd); /* * Iterate over files list from installed package. */ for (i = 0; i < xbps_array_count(instfiles); i++) { found = false; obj = xbps_array_get(instfiles, i); if (xbps_object_type(obj) != XBPS_TYPE_DICTIONARY) { /* ignore unexistent files */ continue; } oldstr = xbps_dictionary_get(obj, "file"); if (oldstr == NULL) continue; file = xbps_xasprintf(".%s", xbps_string_cstring_nocopy(oldstr)); oldhash = NULL; xbps_dictionary_get_cstring_nocopy(obj, "sha256", &oldhash); if (oldhash) { rv = xbps_file_hash_check(file, oldhash); if (rv == ENOENT || rv == ERANGE) { /* * Skip unexistent and files that do not * match the hash. */ free(file); continue; } } /* * Check if current file is available in new pkg filelist. */ for (x = 0; x < xbps_array_count(newfiles); x++) { obj2 = xbps_array_get(newfiles, x); newstr = xbps_dictionary_get(obj2, "file"); assert(newstr); /* * Skip files with same path. */ if (xbps_string_equals(oldstr, newstr)) { found = true; break; } } if (found) { free(file); continue; } /* * Do not add required symlinks for the * system transition to /usr. */ if ((strcmp(file, "./bin") == 0) || (strcmp(file, "./bin/") == 0) || (strcmp(file, "./sbin") == 0) || (strcmp(file, "./sbin/") == 0) || (strcmp(file, "./lib") == 0) || (strcmp(file, "./lib/") == 0) || (strcmp(file, "./lib64/") == 0) || (strcmp(file, "./lib64") == 0)) { free(file); continue; } /* * Obsolete found, add onto the array. */ xbps_dbg_printf(xhp, "found obsolete: %s\n", file); xbps_array_add_cstring(obsoletes, file); free(file); } xbps_object_release(instfiles); xbps_object_release(newfiles); return obsoletes; }
static int remove_pkg_files(struct xbps_handle *xhp, xbps_dictionary_t dict, const char *key, const char *pkgver) { xbps_array_t array; xbps_object_iterator_t iter; xbps_object_t obj; const char *curobj = NULL; /* These are symlinks in Void and must not be removed */ const char *basesymlinks[] = { "/bin", "/sbin", "/usr/sbin", "/lib", "/lib32", "/lib64", "/usr/lib32", "/usr/lib64", "/var/run", }; 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"; xbps_object_iterator_reset(iter); while ((obj = xbps_object_iterator_next(iter))) { const char *file, *sha256; char path[PATH_MAX]; bool found; xbps_dictionary_get_cstring_nocopy(obj, "file", &file); snprintf(path, sizeof(path), "%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)); 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); 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)); break; } } /* * Make sure to not remove any symlink of root directory. */ found = false; for (uint8_t i = 0; i < __arraycount(basesymlinks); i++) { if (strcmp(file, basesymlinks[i]) == 0) { found = true; xbps_dbg_printf(xhp, "[remove] %s ignoring " "%s removal\n", pkgver, file); break; } } if (found) { continue; } if (strcmp(key, "links") == 0) { const char *target = NULL; char *lnk; xbps_dictionary_get_cstring_nocopy(obj, "target", &target); assert(target); lnk = xbps_symlink_target(xhp, path, target); if (lnk == NULL) { xbps_dbg_printf(xhp, "[remove] %s " "symlink_target: %s\n", path, strerror(errno)); continue; } if (strcmp(lnk, target)) { xbps_dbg_printf(xhp, "[remove] %s symlink " "modified (stored %s current %s)\n", path, target, lnk); if ((xhp->flags & XBPS_FLAG_FORCE_REMOVE_FILES) == 0) { free(lnk); continue; } } free(lnk); } /* * 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)); } else { /* success */ xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE, 0, pkgver, "Removed %s `%s'", curobj, file); } } xbps_object_iterator_release(iter); return rv; }
xbps_array_t xbps_find_pkg_obsoletes(struct xbps_handle *xhp, xbps_dictionary_t instd, xbps_dictionary_t newd) { xbps_array_t instfiles, newfiles, obsoletes; /* These are symlinks in Void and must not be removed */ const char *basesymlinks[] = { "./bin", "./sbin", "./lib", "./lib32", "./lib64", "./usr/lib32", "./usr/lib64", "./var/run", }; int rv = 0; assert(xbps_object_type(instd) == XBPS_TYPE_DICTIONARY); assert(xbps_object_type(newd) == XBPS_TYPE_DICTIONARY); obsoletes = xbps_array_create(); assert(obsoletes); instfiles = merge_filelist(instd); if (xbps_array_count(instfiles) == 0) { /* nothing to check if current pkg does not own any file */ xbps_object_release(instfiles); return obsoletes; } newfiles = merge_filelist(newd); /* * Iterate over files list from installed package. */ for (unsigned int i = 0; i < xbps_array_count(instfiles); i++) { xbps_object_t obj, obj2; xbps_string_t oldstr, newstr; struct stat st; uint64_t mtime = 0; const char *oldhash; char file[PATH_MAX]; bool found = false; obj = xbps_array_get(instfiles, i); if (xbps_object_type(obj) != XBPS_TYPE_DICTIONARY) { /* ignore unexistent files */ continue; } oldstr = xbps_dictionary_get(obj, "file"); if (oldstr == NULL) continue; snprintf(file, sizeof(file), ".%s", xbps_string_cstring_nocopy(oldstr)); if (xbps_dictionary_get_cstring_nocopy(obj, "sha256", &oldhash)) { rv = xbps_file_hash_check(file, oldhash); if (rv == ENOENT || rv == ERANGE) { /* Skip unexistent and files that do not * match the hash. */ continue; } } /* * Check if current file is available in new pkg filelist. */ for (unsigned int x = 0; x < xbps_array_count(newfiles); x++) { obj2 = xbps_array_get(newfiles, x); newstr = xbps_dictionary_get(obj2, "file"); assert(newstr); /* * Skip files with same path. */ if (xbps_string_equals(oldstr, newstr)) { found = true; break; } } if (found) { continue; } /* * Make sure to not remove any symlink of root directory. */ for (uint8_t x = 0; x < __arraycount(basesymlinks); x++) { if (strcmp(file, basesymlinks[x]) == 0) { found = true; xbps_dbg_printf(xhp, "[obsoletes] ignoring " "%s removal\n", file); break; } } if (found) { continue; } /* * Finally check if file mtime on disk matched what * the installed pkg has stored. */ if (xbps_dictionary_get_uint64(obj, "mtime", &mtime)) { if (lstat(file, &st) == -1) { xbps_dbg_printf(xhp, "[obsoletes] lstat failed " "for %s: %s\n", file, strerror(errno)); continue; } if (mtime != (uint64_t)st.st_mtime) continue; xbps_dbg_printf(xhp, "[obsoletes] %s: matched mtime, adding obsolete.\n", file); } /* * Obsolete found, add onto the array. */ xbps_dbg_printf(xhp, "found obsolete: %s\n", file); xbps_array_add_cstring(obsoletes, file); } xbps_object_release(instfiles); xbps_object_release(newfiles); return obsoletes; }