diff --git a/bin/xbps-bin.c b/bin/xbps-bin.c index 38550e80a1..aae2d2808a 100644 --- a/bin/xbps-bin.c +++ b/bin/xbps-bin.c @@ -50,8 +50,9 @@ usage(void) { printf("Usage: xbps-bin [action] [arguments]\n\n" " Available actions:\n" - " repo-add, repo-list, repo-rm, search, show\n" + " install, repo-add, repo-list, repo-rm, search, show\n" " Action arguments:\n" + " install\t[] []\n" " repo-add\t[]\n" " repo-list\t[none]\n" " repo-rm\t[]\n" @@ -59,6 +60,7 @@ usage(void) " show\t[]\n" "\n" " Examples:\n" + " $ xbps-bin install klibc\n" " $ xbps-bin repo-add /path/to/directory\n" " $ xbps-bin repo-add http://www.location.org/xbps-repo\n" " $ xbps-bin repo-list\n" @@ -163,6 +165,7 @@ main(int argc, char **argv) prop_dictionary_t dict; repo_info_t *rinfo = NULL; char dpkgidx[PATH_MAX], repolist[PATH_MAX]; + int rv = 0; if (argc < 2) usage(); @@ -269,19 +272,19 @@ main(int argc, char **argv) } else if (strcasecmp(argv[1], "install") == 0) { /* Installs a binary package and required deps. */ - if (argc != 3) + if (argc < 3 || argc > 4) usage(); - dict = getrepolist_dict(); - if (!xbps_callback_array_iter_in_dict(dict, "repository-list", - xbps_install_binary_pkg_from_repolist, argv[2])) { - prop_object_release(dict); - printf("ERROR: unable to find a binary package " - "for %s.\n", argv[2]); - exit(EINVAL); + if (argc == 3) { + /* Install into root directory by default. */ + rv = xbps_install_binary_pkg(argv[2], "/"); + } else { + /* install into specified directory. */ + rv = xbps_install_binary_pkg(argv[2], argv[3]); } - prop_object_release(dict); + if (rv) + exit(rv); } else { usage(); } diff --git a/include/plist.h b/include/plist.h index b4aed480eb..ec63781c0f 100644 --- a/include/plist.h +++ b/include/plist.h @@ -158,11 +158,12 @@ int xbps_cmpver_packages(const char *, const char *); int xbps_cmpver_versions(const char *, const char *); const char * xbps_get_pkg_version(const char *); char * xbps_get_pkg_name(const char *); -int xbps_install_pkg_deps(prop_dictionary_t, prop_dictionary_t); -int xbps_install_binary_pkg(prop_dictionary_t, const char *, - const char *); +int xbps_install_pkg_deps(prop_array_t, prop_dictionary_t); +int xbps_install_binary_pkg(const char *, const char *); bool xbps_install_binary_pkg_from_repolist(prop_object_t, void *, bool *); -int xbps_unpack_binary_pkg(prop_dictionary_t, int (*cb)(struct archive *)); +int xbps_unpack_binary_pkg(prop_dictionary_t, prop_dictionary_t, + int (*cb)(struct archive *)); int xbps_unpack_archive_cb(struct archive *); +bool xbps_pkg_has_rundeps(prop_dictionary_t); #endif /* !_XBPS_PLIST_H_ */ diff --git a/include/xbps_api.h b/include/xbps_api.h index 3c91487a32..c7b903f65f 100644 --- a/include/xbps_api.h +++ b/include/xbps_api.h @@ -48,7 +48,7 @@ #define XBPS_REGPKGDB "regpkgdb.plist" /* Return values for xbps_install_binary_pkg() */ -#define XBPS_PKG_ENOTINREPO 1 /* Not found in repos */ +#define XBPS_PKG_ENOTINREPO 1 /* Not found in repo */ #define XBPS_PKG_EEXIST 2 /* Already installed */ #define XBPS_PKG_EINDEPS 3 /* Check deps failed */ #define XBPS_PKG_ECHDIRDEST 4 /* chdir() to dest failed */ diff --git a/lib/depends.c b/lib/depends.c index a9098af03e..74b9289157 100644 --- a/lib/depends.c +++ b/lib/depends.c @@ -32,11 +32,11 @@ #include -typedef struct pkg_dependency { +struct pkg_dependency { LIST_ENTRY(pkg_dependency) deps; - prop_dictionary_t dict; + prop_dictionary_t repo; char *name; -} pkg_dep_t; +}; static LIST_HEAD(, pkg_dependency) pkg_deps_list = LIST_HEAD_INITIALIZER(pkg_deps_list); @@ -79,13 +79,26 @@ xbps_check_is_installed_pkg(const char *plist, const char *pkg) } void -xbps_add_pkg_dependency(const char *pkgname, prop_dictionary_t dict) +xbps_clean_pkg_depslist(void) { - pkg_dep_t *dep; + struct pkg_dependency *dep; + + LIST_FOREACH(dep, &pkg_deps_list, deps) { + LIST_REMOVE(dep, deps); + free(dep->name); + prop_object_release(dep->repo); + } +} + +void +xbps_add_pkg_dependency(const char *pkgname, prop_dictionary_t repo) +{ + struct pkg_dependency *dep; size_t len = 0; + assert(repo != NULL); assert(pkgname != NULL); - assert(dict != NULL); + assert(pkgdict != NULL); LIST_FOREACH(dep, &pkg_deps_list, deps) if (strcmp(dep->name, pkgname) == 0) @@ -97,38 +110,20 @@ xbps_add_pkg_dependency(const char *pkgname, prop_dictionary_t dict) len = strlen(pkgname) + 1; dep->name = malloc(len); - if (dep->name == NULL) { - free(dep); - return; - } + assert(dep != NULL); memcpy(dep->name, pkgname, len - 1); dep->name[len - 1] = '\0'; - dep->dict = prop_dictionary_copy(dict); + dep->repo = prop_dictionary_copy(repo); LIST_INSERT_HEAD(&pkg_deps_list, dep, deps); } -static bool -pkg_has_rundeps(prop_dictionary_t pkg) -{ - prop_array_t array; - - assert(pkg != NULL); - - array = prop_dictionary_get(pkg, "run_depends"); - if (array && prop_array_count(array) > 0) - return true; - - return false; -} - static int find_deps_in_pkg(prop_dictionary_t repo, prop_dictionary_t pkg) { prop_dictionary_t pkgdict; prop_array_t array; - prop_string_t name; prop_object_t obj; prop_object_iterator_t iter = NULL; const char *reqpkg; @@ -142,19 +137,31 @@ find_deps_in_pkg(prop_dictionary_t repo, prop_dictionary_t pkg) if (iter == NULL) return -1; - name = prop_dictionary_get(pkg, "pkgname"); - xbps_add_pkg_dependency(prop_string_cstring_nocopy(name), pkg); - - /* Iterate over the list of required run dependencies for a pkg */ + /* + * Iterate over the list of required run dependencies for + * a package. + */ while ((obj = prop_object_iterator_next(iter))) { + /* + * If required package is not in repo, just pass to the + * next one. + */ reqpkg = prop_string_cstring_nocopy(obj); pkgname = xbps_get_pkg_name(reqpkg); pkgdict = xbps_find_pkg_in_dict(repo, pkgname); - xbps_add_pkg_dependency(pkgname, pkgdict); + if (pkgdict == NULL) { + free(pkgname); + continue; + } + + /* + * Package is on repo, add it into the list. + */ + xbps_add_pkg_dependency(pkgname, repo); free(pkgname); /* Iterate on required pkg to find more deps */ - if (pkg_has_rundeps(pkgdict)) { + if (xbps_pkg_has_rundeps(pkgdict)) { /* more deps? */ if (!find_deps_in_pkg(repo, pkgdict)) continue; @@ -167,47 +174,119 @@ find_deps_in_pkg(prop_dictionary_t repo, prop_dictionary_t pkg) } int -xbps_install_pkg_deps(prop_dictionary_t repo, prop_dictionary_t pkg) +xbps_install_pkg_deps(prop_array_t repolist, prop_dictionary_t pkg) { - pkg_dep_t *dep; + prop_dictionary_t repo, pkgdict; + prop_array_t array; + prop_object_iterator_t iter; + prop_object_t obj; prop_string_t pkgname, version; + struct pkg_dependency *dep; + size_t required_deps = 0, deps_found = 0; + const char *reqpkg, *verstr; + char plist[PATH_MAX], *namestr; int rv = 0; + bool dep_found = false; - assert(pkg != NULL); - assert(repo != NULL); - assert(prop_object_type(pkg) == PROP_TYPE_DICTIONARY); - assert(prop_object_type(repo) == PROP_TYPE_DICTIONARY); + iter = prop_array_iterator(repolist); + if (iter == NULL) + return ENOMEM; - if (!pkg_has_rundeps(pkg)) { - /* Package has no required dependencies. */ - return 0; + /* + * Iterate over the repository list and find out if we have + * all required dependencies. + */ + while ((obj = prop_object_iterator_next(iter)) != NULL) { + memset(plist, 0, sizeof(&plist)); + if (!xbps_append_full_path(plist, + prop_string_cstring_nocopy(obj), XBPS_PKGINDEX)) { + xbps_clean_pkg_depslist(); + prop_object_iterator_release(iter); + rv = EINVAL; + goto out; + } + + repo = prop_dictionary_internalize_from_file(plist); + if (repo == NULL) { + prop_object_iterator_release(iter); + rv = errno; + goto out; + } + + rv = find_deps_in_pkg(repo, pkg); + if (rv == -1) { + prop_object_release(repo); + prop_object_iterator_release(iter); + goto out; + } + + prop_object_release(repo); + } + prop_object_iterator_release(iter); + + /* + * Find out if all required dependencies and binary packages + * from repositories are there. + */ + array = prop_dictionary_get(pkg, "run_depends"); + iter = prop_array_iterator(array); + if (iter == NULL) { + rv = ENOMEM; + goto out; } - /* Check what dependencies are required. */ - if (find_deps_in_pkg(repo, pkg) == -1) { - errno = XBPS_PKG_EINDEPS; - return -1; + while ((obj = prop_object_iterator_next(iter)) != NULL) { + dep_found = false; + required_deps++; + reqpkg = prop_string_cstring_nocopy(obj); + namestr = xbps_get_pkg_name(reqpkg); + verstr = xbps_get_pkg_version(reqpkg); + + LIST_FOREACH(dep, &pkg_deps_list, deps) { + if (strcmp(dep->name, namestr) == 0) { + deps_found++; + dep_found = true; + break; + } + } + if (dep_found == false) { + printf("Cannot find %s >= %s in repository list.\n", + namestr, verstr); + (void)fflush(stdout); + } + free(namestr); + } + prop_object_iterator_release(iter); + + if (required_deps != deps_found) { + rv = XBPS_PKG_ENOTINREPO; + goto out; } /* * Iterate over the list of dependencies and install them. */ LIST_FOREACH(dep, &pkg_deps_list, deps) { - pkgname = prop_dictionary_get(dep->dict, "pkgname"); - version = prop_dictionary_get(dep->dict, "version"); + pkgdict = xbps_find_pkg_in_dict(dep->repo, dep->name); + if (pkgdict == NULL) { + rv = EINVAL; + break; + } + + pkgname = prop_dictionary_get(pkgdict, "pkgname"); + version = prop_dictionary_get(pkgdict, "version"); printf("Required package: %s >= %s\n", prop_string_cstring_nocopy(pkgname), prop_string_cstring_nocopy(version)); (void)fflush(stdout); - rv = xbps_unpack_binary_pkg(dep->dict, xbps_unpack_archive_cb); + rv = xbps_unpack_binary_pkg(dep->repo, pkgdict, + xbps_unpack_archive_cb); if (rv != 0) break; - - LIST_REMOVE(dep, deps); - free(dep->name); - prop_object_release(dep->dict); } - return 1; +out: + xbps_clean_pkg_depslist(); + return rv; } diff --git a/lib/install.c b/lib/install.c index 8be1b87050..083d65ea7a 100644 --- a/lib/install.c +++ b/lib/install.c @@ -32,105 +32,105 @@ #include -bool -xbps_install_binary_pkg_from_repolist(prop_object_t obj, void *arg, bool *done) +int +xbps_install_binary_pkg(const char *pkgname, const char *destdir) { - prop_dictionary_t dict; - prop_string_t oloc; - const char *repofile, *repoloc; + prop_array_t array; + prop_dictionary_t repolistd, repod, pkgrd; + prop_object_t obj; + prop_object_iterator_t iter; char plist[PATH_MAX]; int rv = 0; - assert(prop_object_type(obj) == PROP_TYPE_STRING); - - /* Get the location */ - repofile = prop_string_cstring_nocopy(obj); - - /* Get string for pkg-index.plist with full path. */ - if (!xbps_append_full_path(plist, repofile, XBPS_PKGINDEX)) - return false; - - dict = prop_dictionary_internalize_from_file(plist); - if (dict == NULL || prop_dictionary_count(dict) == 0) - return false; - - oloc = prop_dictionary_get(dict, "location-remote"); - if (oloc == NULL) - oloc = prop_dictionary_get(dict, "location-local"); - - if (oloc && prop_object_type(oloc) == PROP_TYPE_STRING) - repoloc = prop_string_cstring_nocopy(oloc); - else { - prop_object_release(dict); - return false; - } - - printf("Searching in repository: %s\n", repoloc); - rv = xbps_install_binary_pkg(dict, arg, "/home/juan/root_xbps"); - *done = true; - prop_object_release(dict); - - if (rv != 0) - return false; - - return true; -} - -int -xbps_install_binary_pkg(prop_dictionary_t repo, const char *pkgname, - const char *dest) -{ - prop_dictionary_t pkg_rdict, dict; - prop_object_t obj; - char dbfile[PATH_MAX]; - int rv = 0; - assert(pkgname != NULL); - if (dest) { - if ((rv = chdir(dest)) != 0) + if (destdir) { + if ((rv = chdir(destdir)) != 0) return XBPS_PKG_ECHDIRDEST; } - /* Get pkg metadata from a repository */ - pkg_rdict = xbps_find_pkg_in_dict(repo, pkgname); - if (pkg_rdict == NULL) - return XBPS_PKG_ENOTINREPO; - - /* Check if package is already installed. */ - if (!xbps_append_full_path(dbfile, NULL, XBPS_REGPKGDB)) + /* Get the dictionary with list of repositories. */ + if (!xbps_append_full_path(plist, NULL, XBPS_REPOLIST)) return EINVAL; - dict = prop_dictionary_internalize_from_file(dbfile); - if (dict && xbps_find_pkg_in_dict(dict, pkgname)) { - prop_object_release(dict); - return XBPS_PKG_EEXIST; + repolistd = prop_dictionary_internalize_from_file(plist); + if (repolistd == NULL) + return EINVAL; + + /* Iterate over the list of repositories to find a pkg. */ + array = prop_dictionary_get(repolistd, "repository-list"); + if (array == NULL || prop_array_count(array) == 0) { + prop_object_release(repolistd); + return EINVAL; } - obj = prop_dictionary_get(pkg_rdict, "version"); - printf("Available package: %s-%s.\n", - pkgname, prop_string_cstring_nocopy(obj)); - (void)fflush(stdout); + iter = prop_array_iterator(array); + if (iter == NULL) { + prop_object_release(repolistd); + return ENOMEM; + } - /* - * Install the package, and its dependencies if there are. - */ - switch (xbps_install_pkg_deps(repo, pkg_rdict)) { - case -1: - return XBPS_PKG_EINDEPS; - case 0: + while ((obj = prop_object_iterator_next(iter)) != NULL) { /* - * Package has no dependencies, just install it. + * Get the dictionary from a repository's index file. */ - rv = xbps_unpack_binary_pkg(pkg_rdict, xbps_unpack_archive_cb); - break; - case 1: + assert(prop_object_type(obj) == PROP_TYPE_STRING); + memset(plist, 0, sizeof(&plist)); + if (!xbps_append_full_path(plist, + prop_string_cstring_nocopy(obj), XBPS_PKGINDEX)) { + prop_object_iterator_release(iter); + prop_object_release(repolistd); + return EINVAL; + } + repod = prop_dictionary_internalize_from_file(plist); + if (repod == NULL) { + prop_object_iterator_release(iter); + prop_object_release(repolistd); + return EINVAL; + } + /* - * 1 means that package has dependencies, but - * xbps_install_pkg_deps() takes care of it. + * Get the package dictionary from current repository. */ + pkgrd = xbps_find_pkg_in_dict(repod, pkgname); + if (pkgrd == NULL) { + prop_object_release(repod); + continue; + } + + /* + * Check if pkg needs deps. + */ + if (!xbps_pkg_has_rundeps(pkgrd)) { + /* pkg has no deps, just install it. */ + rv = xbps_unpack_binary_pkg(repod, pkgrd, + xbps_unpack_archive_cb); + prop_object_release(repolistd); + prop_object_release(repod); + break; + } + + /* + * Install all required dependencies. + */ + rv = xbps_install_pkg_deps(array, pkgrd); + if (rv != 0) { + prop_object_release(repolistd); + prop_object_release(repod); + break; + } + /* + * Finally install the package, now that all + * required dependencies were installed. + */ + rv = xbps_unpack_binary_pkg(repod, pkgrd, + xbps_unpack_archive_cb); + prop_object_release(repolistd); + prop_object_release(repod); break; } + prop_object_iterator_release(iter); + return rv; } @@ -138,10 +138,14 @@ int xbps_unpack_archive_cb(struct archive *ar) { struct archive_entry *entry; + static bool first; int rv = 0; while (archive_read_next_header(ar, &entry) == ARCHIVE_OK) { if ((rv = archive_read_extract(ar, entry, 0)) != 0) { + if (!first) + printf("\n"); + first = true; printf("couldn't write %s (%s), ignoring!\n", archive_entry_pathname(entry), strerror(errno)); } @@ -152,9 +156,10 @@ xbps_unpack_archive_cb(struct archive *ar) } int -xbps_unpack_binary_pkg(prop_dictionary_t pkg, int (*cb)(struct archive *)) +xbps_unpack_binary_pkg(prop_dictionary_t repo, prop_dictionary_t pkg, + int (*cb)(struct archive *)) { - prop_string_t pkgname, version, filename; + prop_string_t pkgname, version, filename, repoloc; struct archive *ar; char binfile[PATH_MAX]; int rv; @@ -163,14 +168,19 @@ xbps_unpack_binary_pkg(prop_dictionary_t pkg, int (*cb)(struct archive *)) /* Append filename to the full path for binary pkg */ filename = prop_dictionary_get(pkg, "filename"); - if (!xbps_append_full_path(binfile, "/storage/xbps/binpkgs", + repoloc = prop_dictionary_get(repo, "location-local"); + + if (!xbps_append_full_path(binfile, + prop_string_cstring_nocopy(repoloc), prop_string_cstring_nocopy(filename))) return EINVAL; pkgname = prop_dictionary_get(pkg, "pkgname"); version = prop_dictionary_get(pkg, "version"); - printf("Unpacking %s-%s (from %s)... ", + printf("From repository %s ...\n", + prop_string_cstring_nocopy(repoloc)); + printf(" Unpacking %s-%s (%s) ... ", prop_string_cstring_nocopy(pkgname), prop_string_cstring_nocopy(version), prop_string_cstring_nocopy(filename)); @@ -190,8 +200,10 @@ xbps_unpack_binary_pkg(prop_dictionary_t pkg, int (*cb)(struct archive *)) return rv; } - if ((rv = (*cb)(ar)) == 0) + if ((rv = (*cb)(ar)) == 0) { printf("done.\n"); + (void)fflush(stdout); + } return rv; } diff --git a/lib/util.c b/lib/util.c index 7504feecd7..77fd297662 100644 --- a/lib/util.c +++ b/lib/util.c @@ -63,6 +63,19 @@ xbps_get_pkg_name(const char *pkg) return pkgname; } +bool +xbps_pkg_has_rundeps(prop_dictionary_t pkg) +{ + prop_array_t array; + + assert(pkg != NULL); + array = prop_dictionary_get(pkg, "run_depends"); + if (array && prop_array_count(array) > 0) + return true; + + return false; +} + bool xbps_append_full_path(char *buf, const char *root, const char *plistf) {