/* * Checks package integrity of an installed package. * The following task is accomplished in this file: * * o Check for target file in symlinks, so that we can check that * they have not been modified. * * returns 0 if test ran successfully, 1 otherwise and -1 on error. */ static char * symlink_target(const char *pkgname, const char *path) { struct stat sb; char *lnk; ssize_t r; if (lstat(path, &sb) == -1) { xbps_error_printf("%s: lstat failed for %s\n", pkgname, path); return NULL; } lnk = malloc(sb.st_size + 1); assert(lnk); r = readlink(path, lnk, sb.st_size + 1); if (r < 0 || r > sb.st_size) { xbps_error_printf("%s: readlink failed for %s\n", pkgname, path); free(lnk); return NULL; } lnk[sb.st_size] = '\0'; return lnk; }
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 xbps_pkgdb_update(struct xbps_handle *xhp, bool flush, bool update) { xbps_dictionary_t pkgdb_storage; static int cached_rv; int rv = 0; if (cached_rv && !flush) return cached_rv; if (xhp->pkgdb && update) { pkgdb_storage = xbps_dictionary_internalize_from_file(xhp->pkgdb_plist); if (pkgdb_storage == NULL || !xbps_dictionary_equals(xhp->pkgdb, pkgdb_storage)) { /* flush dictionary to storage */ if (!xbps_dictionary_externalize_to_file(xhp->pkgdb, xhp->pkgdb_plist)) return errno; } if (pkgdb_storage) xbps_object_release(pkgdb_storage); xbps_object_release(xhp->pkgdb); xhp->pkgdb = NULL; cached_rv = 0; } if (!update) return rv; /* update copy in memory */ if ((xhp->pkgdb = xbps_dictionary_internalize_from_file(xhp->pkgdb_plist)) == NULL) { rv = errno; if (!rv) rv = EINVAL; if (rv == ENOENT) xhp->pkgdb = xbps_dictionary_create(); else xbps_error_printf("cannot access to pkgdb: %s\n", strerror(rv)); cached_rv = rv = errno; } return rv; }
int xbps_pkgdb_update(struct xbps_handle *xhp, bool flush) { xbps_dictionary_t pkgdb_storage; char *plist; static int cached_rv; int rv = 0; if (cached_rv && !flush) return cached_rv; plist = xbps_xasprintf("%s/%s", xhp->metadir, XBPS_PKGDB); if (xhp->pkgdb && flush) { pkgdb_storage = xbps_dictionary_internalize_from_file(plist); if (pkgdb_storage == NULL || !xbps_dictionary_equals(xhp->pkgdb, pkgdb_storage)) { /* flush dictionary to storage */ if (!xbps_dictionary_externalize_to_file(xhp->pkgdb, plist)) { free(plist); return errno; } } if (pkgdb_storage) xbps_object_release(pkgdb_storage); xbps_object_release(xhp->pkgdb); xhp->pkgdb = NULL; cached_rv = 0; } /* update copy in memory */ if ((xhp->pkgdb = xbps_dictionary_internalize_from_file(plist)) == NULL) { if (errno == ENOENT) xhp->pkgdb = xbps_dictionary_create(); else xbps_error_printf("cannot access to pkgdb: %s\n", strerror(errno)); cached_rv = rv = errno; } free(plist); 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); }
int exec_transaction(struct xbps_handle *xhp, int maxcols, bool yes, bool drun) { xbps_array_t array; struct transaction *trans; uint64_t fsize = 0, isize = 0; char freesize[8], instsize[8]; int rv = 0; trans = calloc(1, sizeof(*trans)); if (trans == NULL) return ENOMEM; if ((rv = xbps_transaction_prepare(xhp)) != 0) { if (rv == ENODEV) { array = xbps_dictionary_get(xhp->transd, "missing_deps"); if (xbps_array_count(array)) { /* missing dependencies */ print_array(array); fprintf(stderr, "Transaction aborted due to unresolved dependencies.\n"); } } else if (rv == ENOEXEC) { array = xbps_dictionary_get(xhp->transd, "missing_shlibs"); if (xbps_array_count(array)) { /* missing shlibs */ print_array(array); fprintf(stderr, "Transaction aborted due to unresolved shlibs.\n"); } } else if (rv == EAGAIN) { /* conflicts */ array = xbps_dictionary_get(xhp->transd, "conflicts"); print_array(array); fprintf(stderr, "Transaction aborted due to conflicting packages.\n"); } else if (rv == ENOSPC) { /* not enough free space */ xbps_dictionary_get_uint64(xhp->transd, "total-installed-size", &isize); if (xbps_humanize_number(instsize, (int64_t)isize) == -1) { xbps_error_printf("humanize_number2 returns " "%s\n", strerror(errno)); return -1; } xbps_dictionary_get_uint64(xhp->transd, "disk-free-size", &fsize); if (xbps_humanize_number(freesize, (int64_t)fsize) == -1) { xbps_error_printf("humanize_number2 returns " "%s\n", strerror(errno)); return -1; } fprintf(stderr, "Transaction aborted due to insufficient disk " "space (need %s, got %s free).\n", instsize, freesize); } else { xbps_dbg_printf(xhp, "Empty transaction dictionary: %s\n", strerror(errno)); } goto out; } #ifdef FULL_DEBUG xbps_dbg_printf(xhp, "Dictionary before transaction happens:\n"); xbps_dbg_printf_append(xhp, "%s", xbps_dictionary_externalize(xhp->transd)); #endif trans->xhp = xhp; trans->d = xhp->transd; trans->iter = xbps_array_iter_from_dict(xhp->transd, "packages"); assert(trans->iter); /* * dry-run mode, show what would be done but don't run anything. */ if (drun) { show_actions(trans->iter); goto out; } /* * Show download/installed size for the transaction. */ if ((rv = show_transaction_sizes(trans, maxcols)) != 0) goto out; /* * Ask interactively (if -y not set). */ if (!yes && !yesno("Do you want to continue?")) { printf("Aborting!\n"); goto out; } /* * It's time to run the transaction! */ if ((rv = xbps_transaction_commit(xhp)) == 0) { printf("\n%u downloaded, %u installed, %u updated, " "%u configured, %u removed.\n", trans->dl_pkgcnt, trans->inst_pkgcnt, trans->up_pkgcnt, trans->cf_pkgcnt + trans->inst_pkgcnt, trans->rm_pkgcnt); } out: if (trans->iter) xbps_object_iterator_release(trans->iter); if (trans) free(trans); return rv; }
static int show_transaction_sizes(struct transaction *trans, int cols) { uint64_t dlsize = 0, instsize = 0, rmsize = 0, disk_free_size = 0; char size[8]; if (!print_trans_colmode(trans, cols)) { /* * Show the list of packages that will be downloaded, installed, updated, * removed or configured. */ xbps_dictionary_get_uint32(trans->d, "total-download-pkgs", &trans->dl_pkgcnt); if (trans->dl_pkgcnt) { printf("%u package%s will be downloaded:\n", trans->dl_pkgcnt, trans->dl_pkgcnt == 1 ? "" : "s"); show_package_list(trans, NULL, cols); printf("\n"); } xbps_dictionary_get_uint32(trans->d, "total-install-pkgs", &trans->inst_pkgcnt); if (trans->inst_pkgcnt) { printf("%u package%s will be installed:\n", trans->inst_pkgcnt, trans->inst_pkgcnt == 1 ? "" : "s"); show_package_list(trans, "install", cols); printf("\n"); } xbps_dictionary_get_uint32(trans->d, "total-update-pkgs", &trans->up_pkgcnt); if (trans->up_pkgcnt) { printf("%u package%s will be updated:\n", trans->up_pkgcnt, trans->up_pkgcnt == 1 ? "" : "s"); show_package_list(trans, "update", cols); printf("\n"); } xbps_dictionary_get_uint32(trans->d, "total-configure-pkgs", &trans->cf_pkgcnt); if (trans->cf_pkgcnt) { printf("%u package%s will be configured:\n", trans->cf_pkgcnt, trans->cf_pkgcnt == 1 ? "" : "s"); show_package_list(trans, "configure", cols); printf("\n"); } xbps_dictionary_get_uint32(trans->d, "total-remove-pkgs", &trans->rm_pkgcnt); if (trans->rm_pkgcnt) { printf("%u package%s will be removed:\n", trans->rm_pkgcnt, trans->rm_pkgcnt == 1 ? "" : "s"); show_package_list(trans, "remove", cols); printf("\n"); } } /* * Show total download/installed/removed size for all required packages. */ xbps_dictionary_get_uint64(trans->d, "total-download-size", &dlsize); xbps_dictionary_get_uint64(trans->d, "total-installed-size", &instsize); xbps_dictionary_get_uint64(trans->d, "total-removed-size", &rmsize); xbps_dictionary_get_uint64(trans->d, "disk-free-size", &disk_free_size); if (dlsize || instsize || rmsize || disk_free_size) printf("\n"); if (dlsize) { if (xbps_humanize_number(size, (int64_t)dlsize) == -1) { xbps_error_printf("humanize_number returns " "%s\n", strerror(errno)); return -1; } printf("Size to download: %6s\n", size); } if (instsize) { if (xbps_humanize_number(size, (int64_t)instsize) == -1) { xbps_error_printf("humanize_number2 returns " "%s\n", strerror(errno)); return -1; } printf("Size required on disk: %6s\n", size); } if (rmsize) { if (xbps_humanize_number(size, (int64_t)rmsize) == -1) { xbps_error_printf("humanize_number3 returns " "%s\n", strerror(errno)); return -1; } printf("Size freed on disk: %6s\n", size); } if (disk_free_size) { if (xbps_humanize_number(size, (int64_t)disk_free_size) == -1) { xbps_error_printf("humanize_number3 returns " "%s\n", strerror(errno)); return -1; } printf("Free space on disk: %6s\n", size); } printf("\n"); return 0; }
static int show_transaction_sizes(struct transaction *trans, int cols) { uint64_t dlsize = 0, instsize = 0, rmsize = 0; char size[8]; /* * Show the list of packages that will be installed. */ if (xbps_dictionary_get_uint32(trans->d, "total-install-pkgs", &trans->inst_pkgcnt)) { printf("%u package%s will be installed:\n", trans->inst_pkgcnt, trans->inst_pkgcnt == 1 ? "" : "s"); show_package_list(trans->iter, "install", cols); printf("\n"); } if (xbps_dictionary_get_uint32(trans->d, "total-update-pkgs", &trans->up_pkgcnt)) { printf("%u package%s will be updated:\n", trans->up_pkgcnt, trans->up_pkgcnt == 1 ? "" : "s"); show_package_list(trans->iter, "update", cols); printf("\n"); } if (xbps_dictionary_get_uint32(trans->d, "total-configure-pkgs", &trans->cf_pkgcnt)) { printf("%u package%s will be configured:\n", trans->cf_pkgcnt, trans->cf_pkgcnt == 1 ? "" : "s"); show_package_list(trans->iter, "configure", cols); printf("\n"); } if (xbps_dictionary_get_uint32(trans->d, "total-remove-pkgs", &trans->rm_pkgcnt)) { printf("%u package%s will be removed:\n", trans->rm_pkgcnt, trans->rm_pkgcnt == 1 ? "" : "s"); show_package_list(trans->iter, "remove", cols); printf("\n"); } /* * Show total download/installed/removed size for all required packages. */ xbps_dictionary_get_uint64(trans->d, "total-download-size", &dlsize); xbps_dictionary_get_uint64(trans->d, "total-installed-size", &instsize); xbps_dictionary_get_uint64(trans->d, "total-removed-size", &rmsize); if (dlsize || instsize || rmsize) printf("\n"); if (dlsize) { if (xbps_humanize_number(size, (int64_t)dlsize) == -1) { xbps_error_printf("humanize_number returns " "%s\n", strerror(errno)); return -1; } printf("Total download size:\t%6s\n", size); } if (instsize) { if (xbps_humanize_number(size, (int64_t)instsize) == -1) { xbps_error_printf("humanize_number2 returns " "%s\n", strerror(errno)); return -1; } printf("Total installed size:\t%6s\n", size); } if (rmsize) { if (xbps_humanize_number(size, (int64_t)rmsize) == -1) { xbps_error_printf("humanize_number3 returns " "%s\n", strerror(errno)); return -1; } printf("Total freed size:\t%6s\n", size); } printf("\n"); return 0; }