char * xbps_binpkg_pkgver(const char *pkg) { const char *fname; char *p, *p1, *res; unsigned int len; /* skip path if found, only interested in filename */ if ((fname = strrchr(pkg, '/'))) fname++; else fname = pkg; /* 5 == .xbps */ len = strlen(fname) - 5; p = malloc(len+1); assert(p); (void)memcpy(p, fname, len); p[len] = '\0'; p1 = strrchr(p, '.'); assert(p1); p[strlen(p)-strlen(p1)] = '\0'; /* sanity check it's a proper pkgver string */ if (xbps_pkg_version(p) == NULL) { free(p); return NULL; } res = strdup(p); assert(res); free(p); return res; }
static xbps_dictionary_t get_pkg_in_array(xbps_array_t array, const char *str, bool virtual) { xbps_object_t obj = NULL; xbps_object_iterator_t iter; const char *pkgver; char *dpkgn; bool found = false; iter = xbps_array_iterator(array); assert(iter); while ((obj = xbps_object_iterator_next(iter))) { if (virtual) { /* * Check if package pattern matches * any virtual package version in dictionary. */ if (xbps_pkgpattern_version(str)) found = xbps_match_virtual_pkg_in_dict(obj, str, true); else found = xbps_match_virtual_pkg_in_dict(obj, str, false); if (found) break; } else if (xbps_pkgpattern_version(str)) { /* match by pattern against pkgver */ if (!xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver)) continue; if (xbps_pkgpattern_match(pkgver, str)) { found = true; break; } } else if (xbps_pkg_version(str)) { /* match by exact pkgver */ if (!xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver)) continue; if (strcmp(str, pkgver) == 0) { found = true; break; } } else { /* match by pkgname */ if (!xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver)) continue; dpkgn = xbps_pkg_name(pkgver); assert(dpkgn); if (strcmp(dpkgn, str) == 0) { free(dpkgn); found = true; break; } free(dpkgn); } }
static void show_package_list(struct transaction *trans, const char *match, int cols) { xbps_object_t obj; while ((obj = xbps_object_iterator_next(trans->iter)) != NULL) { const char *pkgver, *tract; char *buf = NULL; bool dload = false; xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); xbps_dictionary_get_cstring_nocopy(obj, "transaction", &tract); xbps_dictionary_get_bool(obj, "download", &dload); if (match && strcmp(tract, "update") == 0) { xbps_dictionary_t ipkgd; const char *ipkgver, *iversion, *version; char *pkgname; /* get installed pkgver */ pkgname = xbps_pkg_name(pkgver); assert(pkgname); ipkgd = xbps_pkgdb_get_pkg(trans->xhp, pkgname); assert(ipkgd); xbps_dictionary_get_cstring_nocopy(ipkgd, "pkgver", &ipkgver); version = xbps_pkg_version(pkgver); iversion = xbps_pkg_version(ipkgver); buf = xbps_xasprintf("%s (%s -> %s)", pkgname, iversion, version); free(pkgname); } if ((match && (strcmp(match, tract) == 0)) || (!match && dload)) { if (buf) { print_package_line(buf, cols, false); free(buf); } else { print_package_line(pkgver, cols, false); } } } xbps_object_iterator_reset(trans->iter); print_package_line(NULL, cols, true); }
ATF_TC_BODY(util_test, tc) { ATF_CHECK_EQ(xbps_pkg_name("font-adobe-100dpi-7.8"), NULL); ATF_CHECK_EQ(xbps_pkg_version("font-adobe-100dpi"), NULL); ATF_CHECK_EQ(xbps_pkg_version("font-adobe-100dpi-7.8"), NULL); ATF_REQUIRE_STREQ(xbps_pkg_name("font-adobe-100dpi-7.8_2"), "font-adobe-100dpi"); ATF_REQUIRE_STREQ(xbps_pkg_name("systemd-43_1"), "systemd"); ATF_REQUIRE_STREQ(xbps_pkg_name("font-adobe-100dpi-1.8_blah"), "font-adobe-100dpi"); ATF_REQUIRE_STREQ(xbps_pkg_version("font-adobe-100dpi-7.8_2"), "7.8_2"); ATF_REQUIRE_STREQ(xbps_pkg_version("font-adobe-100dpi-1.8_blah"), "1.8_blah"); ATF_REQUIRE_STREQ(xbps_pkg_revision("systemd-43_1_0"), "0"); ATF_REQUIRE_STREQ(xbps_pkg_revision("systemd_21-43_0"), "0"); ATF_REQUIRE_STREQ(xbps_pkgpattern_name("systemd>=43"), "systemd"); ATF_REQUIRE_STREQ(xbps_pkgpattern_name("systemd>43"), "systemd"); ATF_REQUIRE_STREQ(xbps_pkgpattern_name("systemd<43"), "systemd"); ATF_REQUIRE_STREQ(xbps_pkgpattern_name("systemd<=43"), "systemd"); ATF_REQUIRE_STREQ(xbps_pkgpattern_name("systemd-[0-9]*"), "systemd"); ATF_REQUIRE_STREQ(xbps_pkgpattern_name("systemd>4[3-9]?"), "systemd"); ATF_REQUIRE_STREQ(xbps_pkgpattern_name("systemd<4_1?"), "systemd"); }
/* * 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 1 if entry should be installed, 0 if don't or -1 on error. */ int HIDDEN xbps_entry_install_conf_file(struct xbps_handle *xhp, xbps_dictionary_t filesd, struct archive_entry *entry, const char *entry_pname, const char *pkgver, const char *pkgname) { xbps_dictionary_t forigd; xbps_object_t obj, obj2; xbps_object_iterator_t iter, iter2; const char *cffile, *sha256_new = NULL; char *buf, *sha256_cur = NULL, *sha256_orig = NULL; int rv = 0; assert(xbps_object_type(filesd) == XBPS_TYPE_DICTIONARY); assert(entry != NULL); assert(entry_pname != NULL); assert(pkgver != NULL); iter = xbps_array_iter_from_dict(filesd, "conf_files"); if (iter == NULL) return -1; /* * Get original hash for the file from current * installed package. */ xbps_dbg_printf(xhp, "%s: processing conf_file %s\n", pkgver, entry_pname); forigd = xbps_pkgdb_get_pkg_metadata(xhp, pkgname); if (forigd == NULL) { xbps_dbg_printf(xhp, "%s: conf_file %s not currently " "installed\n", pkgver, entry_pname); rv = 1; goto out; } iter2 = xbps_array_iter_from_dict(forigd, "conf_files"); if (iter2 != NULL) { while ((obj2 = xbps_object_iterator_next(iter2))) { xbps_dictionary_get_cstring_nocopy(obj2, "file", &cffile); buf = xbps_xasprintf(".%s", cffile); if (strcmp(entry_pname, buf) == 0) { xbps_dictionary_get_cstring(obj2, "sha256", &sha256_orig); free(buf); break; } free(buf); buf = NULL; } xbps_object_iterator_release(iter2); } /* * First case: original hash not found, install new file. */ if (sha256_orig == NULL) { xbps_dbg_printf(xhp, "%s: conf_file %s not installed\n", pkgver, entry_pname); rv = 1; goto out; } /* * Compare original, installed and new hash for current file. */ while ((obj = xbps_object_iterator_next(iter))) { xbps_dictionary_get_cstring_nocopy(obj, "file", &cffile); buf = xbps_xasprintf(".%s", cffile); if (strcmp(entry_pname, buf)) { free(buf); buf = NULL; continue; } sha256_cur = xbps_file_hash(buf); free(buf); xbps_dictionary_get_cstring_nocopy(obj, "sha256", &sha256_new); if (sha256_cur == NULL) { if (errno == ENOENT) { /* * File not installed, install new one. */ xbps_dbg_printf(xhp, "%s: conf_file %s not " "installed\n", pkgver, entry_pname); rv = 1; break; } else { rv = -1; break; } } /* * Orig = X, Curr = X, New = X * * Keep file as is (no changes). */ if ((strcmp(sha256_orig, sha256_cur) == 0) && (strcmp(sha256_orig, sha256_new) == 0) && (strcmp(sha256_cur, sha256_new) == 0)) { xbps_dbg_printf(xhp, "%s: conf_file %s orig = X, " "cur = X, new = X\n", pkgver, entry_pname); rv = 0; break; /* * Orig = X, Curr = X, New = Y * * Install new file (installed file hasn't been modified). */ } else if ((strcmp(sha256_orig, sha256_cur) == 0) && (strcmp(sha256_orig, sha256_new)) && (strcmp(sha256_cur, sha256_new))) { xbps_set_cb_state(xhp, XBPS_STATE_CONFIG_FILE, 0, pkgver, "Updating configuration file `%s' provided " "by `%s'.", cffile, pkgver); rv = 1; break; /* * Orig = X, Curr = Y, New = X * * Keep installed file as is because it has been modified, * but new package doesn't contain new changes compared * to the original version. */ } else if ((strcmp(sha256_orig, sha256_new) == 0) && (strcmp(sha256_cur, sha256_new)) && (strcmp(sha256_orig, sha256_cur))) { xbps_set_cb_state(xhp, XBPS_STATE_CONFIG_FILE, 0, pkgver, "Keeping modified configuration file `%s'.", cffile); rv = 0; break; /* * Orig = X, Curr = Y, New = Y * * Keep file as is because changes made are compatible * with new version. */ } else if ((strcmp(sha256_cur, sha256_new) == 0) && (strcmp(sha256_orig, sha256_new)) && (strcmp(sha256_orig, sha256_cur))) { xbps_dbg_printf(xhp, "%s: conf_file %s orig = X, " "cur = Y, new = Y\n", pkgver, entry_pname); rv = 0; break; /* * Orig = X, Curr = Y, New = Z * * Install new file as <file>.new-<version> */ } else if ((strcmp(sha256_orig, sha256_cur)) && (strcmp(sha256_cur, sha256_new)) && (strcmp(sha256_orig, sha256_new))) { const char *version; version = xbps_pkg_version(pkgver); assert(version); buf = xbps_xasprintf(".%s.new-%s", cffile, version); xbps_set_cb_state(xhp, XBPS_STATE_CONFIG_FILE, 0, pkgver, "Installing new configuration file to " "`%s.new-%s'.", cffile, version); archive_entry_set_pathname(entry, buf); free(buf); rv = 1; break; } } out: if (sha256_orig) free(sha256_orig); if (sha256_cur) free(sha256_cur); xbps_object_iterator_release(iter); xbps_dbg_printf(xhp, "%s: conf_file %s returned %d\n", pkgver, entry_pname, rv); return rv; }
int main(int argc, char **argv) { xbps_dictionary_t dict; struct xbps_handle xh; struct xferstat xfer; const char *version, *rootdir = NULL, *confdir = NULL; char *pkgname, *hash, *filename; int flags = 0, c, rv = 0; while ((c = getopt(argc, argv, "C:dr:V")) != -1) { switch (c) { case 'C': confdir = optarg; break; case 'r': /* To specify the root directory */ rootdir = optarg; break; case 'd': flags |= XBPS_FLAG_DEBUG; break; case 'V': printf("%s\n", XBPS_RELVER); exit(EXIT_SUCCESS); case '?': default: usage(); } } argc -= optind; argv += optind; if (argc < 1) usage(); memset(&xh, 0, sizeof(xh)); if ((strcmp(argv[0], "version") == 0) || (strcmp(argv[0], "real-version") == 0) || (strcmp(argv[0], "arch") == 0) || (strcmp(argv[0], "getsystemdir") == 0) || (strcmp(argv[0], "fetch") == 0)) { /* * Initialize libxbps. */ xh.flags = flags; xh.fetch_cb = fetch_file_progress_cb; xh.fetch_cb_data = &xfer; if (rootdir) xbps_strlcpy(xh.rootdir, rootdir, sizeof(xh.rootdir)); if (confdir) xbps_strlcpy(xh.confdir, confdir, sizeof(xh.confdir)); if ((rv = xbps_init(&xh)) != 0) { xbps_error_printf("xbps-uhelper: failed to " "initialize libxbps: %s.\n", strerror(rv)); exit(EXIT_FAILURE); } } if (strcmp(argv[0], "version") == 0) { /* Prints version of an installed package */ if (argc != 2) usage(); if ((((dict = xbps_pkgdb_get_pkg(&xh, argv[1])) == NULL)) && (((dict = xbps_pkgdb_get_virtualpkg(&xh, argv[1])) == NULL))) exit(EXIT_FAILURE); xbps_dictionary_get_cstring_nocopy(dict, "pkgver", &version); printf("%s\n", xbps_pkg_version(version)); } else if (strcmp(argv[0], "real-version") == 0) { /* Prints version of an installed real package, not virtual */ if (argc != 2) usage(); if ((dict = xbps_pkgdb_get_pkg(&xh, argv[1])) == NULL) exit(EXIT_FAILURE); xbps_dictionary_get_cstring_nocopy(dict, "pkgver", &version); printf("%s\n", xbps_pkg_version(version)); } else if (strcmp(argv[0], "getpkgversion") == 0) { /* Returns the version of a pkg string */ if (argc != 2) usage(); version = xbps_pkg_version(argv[1]); if (version == NULL) { fprintf(stderr, "Invalid string, expected <string>-<version>_<revision>\n"); exit(EXIT_FAILURE); } printf("%s\n", version); } else if (strcmp(argv[0], "getpkgname") == 0) { /* Returns the name of a pkg string */ if (argc != 2) usage(); pkgname = xbps_pkg_name(argv[1]); if (pkgname == NULL) { fprintf(stderr, "Invalid string, expected <string>-<version>_<revision>\n"); exit(EXIT_FAILURE); } printf("%s\n", pkgname); free(pkgname); } else if (strcmp(argv[0], "getpkgrevision") == 0) { /* Returns the revision of a pkg string */ if (argc != 2) usage(); version = xbps_pkg_revision(argv[1]); if (version == NULL) exit(EXIT_SUCCESS); printf("%s\n", version); } else if (strcmp(argv[0], "getpkgdepname") == 0) { /* Returns the pkgname of a dependency */ if (argc != 2) usage(); pkgname = xbps_pkgpattern_name(argv[1]); if (pkgname == NULL) exit(EXIT_FAILURE); printf("%s\n", pkgname); free(pkgname); } else if (strcmp(argv[0], "getpkgdepversion") == 0) { /* returns the version of a package pattern dependency */ if (argc != 2) usage(); version = xbps_pkgpattern_version(argv[1]); if (version == NULL) exit(EXIT_FAILURE); printf("%s\n", version); } else if (strcmp(argv[0], "binpkgver") == 0) { /* Returns the pkgver of a binpkg string */ if (argc != 2) usage(); version = xbps_binpkg_pkgver(argv[1]); if (version == NULL) { fprintf(stderr, "Invalid string, expected <pkgname>-<version>_<revision>.<arch>.xbps\n"); exit(EXIT_FAILURE); } printf("%s\n", version); } else if (strcmp(argv[0], "binpkgarch") == 0) { /* Returns the arch of a binpkg string */ if (argc != 2) usage(); version = xbps_binpkg_arch(argv[1]); if (version == NULL) { fprintf(stderr, "Invalid string, expected <pkgname>-<version>_<revision>.<arch>.xbps\n"); exit(EXIT_FAILURE); } printf("%s\n", version); } else if (strcmp(argv[0], "pkgmatch") == 0) { /* Matches a pkg with a pattern */ if (argc != 3) usage(); exit(xbps_pkgpattern_match(argv[1], argv[2])); } else if (strcmp(argv[0], "cmpver") == 0) { /* Compare two version strings, installed vs required */ if (argc != 3) usage(); exit(xbps_cmpver(argv[1], argv[2])); } else if (strcmp(argv[0], "arch") == 0) { /* returns the xbps native arch */ if (argc != 1) usage(); printf("%s\n", xh.native_arch); } else if (strcmp(argv[0], "getsystemdir") == 0) { /* returns the xbps system directory (<sharedir>/xbps.d) */ if (argc != 1) usage(); printf("%s\n", XBPS_SYSDEFCONF_PATH); } else if (strcmp(argv[0], "digest") == 0) { /* Prints SHA256 hashes for specified files */ if (argc < 2) usage(); for (int i = 1; i < argc; i++) { hash = xbps_file_hash(argv[i]); if (hash == NULL) { fprintf(stderr, "E: couldn't get hash for %s (%s)\n", argv[i], strerror(errno)); exit(EXIT_FAILURE); } printf("%s\n", hash); } } else if (strcmp(argv[0], "fetch") == 0) { /* Fetch a file from specified URL */ if (argc < 2) usage(); for (int i = 1; i < argc; i++) { filename = fname(argv[i]); rv = xbps_fetch_file_dest(&xh, argv[i], filename, "v"); if (rv == -1) { printf("%s: %s\n", argv[i], xbps_fetch_error_string()); } else if (rv == 0) { printf("%s: file is identical with remote.\n", argv[i]); } else rv = 0; } } else { usage(); } exit(rv ? EXIT_FAILURE : EXIT_SUCCESS); }