diff --git a/utils/plist.c b/utils/plist.c index bcb8c77e955..80077f7750d 100644 --- a/utils/plist.c +++ b/utils/plist.c @@ -33,8 +33,10 @@ #include "xbps_api.h" -static bool xbps_list_strings_in_array2(prop_object_t, void *); -static bool repo_haspkg; +struct callback_args { + const char *string; + int number; +}; bool xbps_add_obj_to_dict(prop_dictionary_t dict, prop_object_t obj, @@ -67,25 +69,27 @@ xbps_add_obj_to_array(prop_array_t array, prop_object_t obj) bool xbps_callback_array_iter_in_dict(prop_dictionary_t dict, const char *key, - bool (*func)(prop_object_t, void *), + bool (*func)(prop_object_t, void *, bool *), void *arg) { prop_object_iterator_t iter; prop_object_t obj; - bool run = false, ret = false; + bool run, ret, cbloop_done; + + run = ret = cbloop_done = false; if (func == NULL) return false; - repo_haspkg = false; + cbloop_done = false; iter = xbps_get_array_iter_from_dict(dict, key); if (iter == NULL) return false; while ((obj = prop_object_iterator_next(iter))) { - run = (*func)(obj, arg); - if (run && repo_haspkg) { + run = (*func)(obj, arg, &cbloop_done); + if (run && cbloop_done) { ret = true; break; } @@ -160,6 +164,26 @@ xbps_get_array_iter_from_dict(prop_dictionary_t dict, const char *key) return prop_array_iterator(array); } + +bool +xbps_remove_obj_from_array(prop_object_t obj, void *arg, bool *loop_done) +{ + static int idx; + struct callback_args *cb = arg; + + if (prop_object_type(obj) != PROP_TYPE_STRING) + return false; + + if (prop_string_equals_cstring(obj, cb->string)) { + cb->number = idx; + *loop_done = true; + return true; + } + idx++; + + return false; +} + bool xbps_register_repository(const char *uri) { @@ -233,6 +257,55 @@ fail: return false; } +bool +xbps_unregister_repository(const char *uri) +{ + prop_dictionary_t dict; + prop_array_t array; + struct callback_args *cb; + bool done = false; + + if (uri == NULL) + return false; + + dict = prop_dictionary_internalize_from_file(XBPS_REPOLIST_PATH); + if (dict == NULL) + return false; + + array = prop_dictionary_get(dict, "repository-list"); + if (array == NULL || prop_object_type(array) != PROP_TYPE_ARRAY) + return false; + + cb = malloc(sizeof(*cb)); + if (cb == NULL) { + errno = ENOMEM; + return false; + } + + cb->string = uri; + cb->number = -1; + + done = xbps_callback_array_iter_in_dict(dict, "repository-list", + xbps_remove_obj_from_array, cb); + if (done && cb->number >= 0) { + /* Found, remove it. */ + prop_array_remove(array, cb->number); + + /* Update plist file. */ + if (prop_dictionary_externalize_to_file(dict, + XBPS_REPOLIST_PATH)) { + free(cb); + return true; + } + } else { + /* Not found. */ + errno = ENODEV; + } + + free(cb); + return false; +} + void xbps_show_pkg_info(prop_dictionary_t dict) { @@ -285,17 +358,26 @@ xbps_show_pkg_info(prop_dictionary_t dict) } bool -xbps_show_pkg_info_from_repolist(prop_object_t obj, void *arg) +xbps_show_pkg_info_from_repolist(prop_object_t obj, void *arg, bool *loop_done) { prop_dictionary_t dict, pkgdict; prop_string_t oloc; const char *repofile, *repoloc; + char plist[PATH_MAX]; if (prop_object_type(obj) != PROP_TYPE_STRING) return false; + /* Get the location */ repofile = prop_string_cstring_nocopy(obj); - dict = prop_dictionary_internalize_from_file(repofile); + + /* Add full path to pkg-index.plist file */ + strncpy(plist, repofile, sizeof(plist) - 1); + plist[sizeof(plist) - 1] = '\0'; + strncat(plist, "/", sizeof(plist) - strlen(plist) - 1); + strncat(plist, XBPS_PKGINDEX, sizeof(plist) - strlen(plist) - 1); + + dict = prop_dictionary_internalize_from_file(plist); pkgdict = xbps_find_pkg_in_dict(dict, arg); if (pkgdict == NULL) return false; @@ -311,13 +393,13 @@ xbps_show_pkg_info_from_repolist(prop_object_t obj, void *arg) printf("Repository: %s\n", repoloc); xbps_show_pkg_info(pkgdict); - repo_haspkg = true; + *loop_done = true; return true; } bool -xbps_list_pkgs_in_dict(prop_object_t obj, void *arg) +xbps_list_pkgs_in_dict(prop_object_t obj, void *arg, bool *loop_done) { const char *pkgname, *version, *short_desc; @@ -335,8 +417,8 @@ xbps_list_pkgs_in_dict(prop_object_t obj, void *arg) return false; } -static bool -xbps_list_strings_in_array2(prop_object_t obj, void *arg) +bool +xbps_list_strings_in_array2(prop_object_t obj, void *arg, bool *loop_done) { static uint16_t count; const char *sep; @@ -361,7 +443,7 @@ xbps_list_strings_in_array2(prop_object_t obj, void *arg) } bool -xbps_list_strings_in_array(prop_object_t obj, void *arg) +xbps_list_strings_in_array(prop_object_t obj, void *arg, bool *loop_done) { if (prop_object_type(obj) != PROP_TYPE_STRING) return false; diff --git a/utils/plist.h b/utils/plist.h index c00d23106f9..050a8b110cd 100644 --- a/utils/plist.h +++ b/utils/plist.h @@ -58,14 +58,14 @@ xbps_add_obj_to_array(prop_array_t, prop_object_t); * Arguments: * - prop_dictionary_t: dictionary to search on. * - const char *: key of the array. - * - (*func)(prop_object_t, void *): callback associated. - * - void *: argument passed to the callback. + * - func(prop_object_t, void *, bool *): callback associated. + * - void *: argument for the callback. * * Returns true on success, false otherwise and the loop is terminated. */ bool xbps_callback_array_iter_in_dict(prop_dictionary_t, const char *, - bool (*func)(prop_object_t, void *), + bool (*func)(prop_object_t, void *, bool *), void *); /* @@ -105,15 +105,15 @@ prop_object_iterator_t xbps_get_array_iter_from_dict(prop_dictionary_t, const char *); /* - * Registers a repository specified by an URI into the pool. + * (Un)registers a repository specified by an URI from/into the pool. * * Arguments: - * - const char *: URI to register. + * - const char *: URI to (un)register. * - * Returns true on success, false otherwise. + * Returns true on success, or false and an appropiate errno value otherwise. */ -bool -xbps_register_repository(const char *); +bool xbps_register_repository(const char *); +bool xbps_unregister_repository(const char *); /* * Shows information of a package by looking at its dictionary. @@ -122,12 +122,15 @@ xbps_register_repository(const char *); * Arguments: * - prop_dictionary_t: the package dictionary. */ -void -xbps_show_pkg_info(prop_dictionary_t); +void xbps_show_pkg_info(prop_dictionary_t); -/* Internal functions. */ -bool xbps_list_pkgs_in_dict(prop_object_t, void *); -bool xbps_list_strings_in_array(prop_object_t, void *); -bool xbps_show_pkg_info_from_repolist(prop_object_t obj, void *); +/* + * Internal functions. + */ +bool xbps_list_pkgs_in_dict(prop_object_t, void *, bool *); +bool xbps_list_strings_in_array(prop_object_t, void *, bool *); +bool xbps_list_strings_in_array2(prop_object_t, void *, bool *); +bool xbps_remove_obj_from_array(prop_object_t, void *, bool *); +bool xbps_show_pkg_info_from_repolist(prop_object_t obj, void *, bool *); #endif /* !_XBPS_PLIST_H_ */ diff --git a/utils/xbps-bin.c b/utils/xbps-bin.c index bea6aca3750..e838185524a 100644 --- a/utils/xbps-bin.c +++ b/utils/xbps-bin.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "xbps_api.h" @@ -39,6 +40,7 @@ typedef struct repository_info { size_t total_pkgs; } repo_info_t; +static const char *sanitize_localpath(const char *); static prop_dictionary_t getrepolist_dict(void); static bool pkgindex_getinfo(prop_dictionary_t, repo_info_t *); static void usage(void); @@ -48,16 +50,18 @@ usage(void) { printf("Usage: xbps-bin [action] [arguments]\n\n" " Available actions:\n" - " repo-add, repo-list, show\n" + " repo-add, repo-list, repo-rm, show\n" " Action arguments:\n" " repo-add\t[]\n" " repo-list\t[none]\n" + " repo-rm\t[]\n" " show\t[]\n" "\n" " Examples:\n" - " $ xbps-bin repo-list\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" + " $ xbps-bin repo-rm /path/to/directory\n" " $ xbps-bin show klibc\n"); exit(1); } @@ -106,12 +110,53 @@ getrepolist_dict(void) return dict; } +static const char * +sanitize_localpath(const char *path) +{ + const char *res; + char strtmp[PATH_MAX]; + char *dirnp, *basenp, *dir, *base; + + dir = strdup(path); + if (dir == NULL) + return NULL; + + base = strdup(path); + if (base == NULL) + goto fail; + + dirnp = dirname(dir); + if (strcmp(dirnp, ".") == 0) + goto fail2; + + basenp = basename(base); + if (strcmp(basenp, base) == 0) + goto fail2; + + /* Sanitize path into a temporary path. */ + strncpy(strtmp, dirnp, sizeof(strtmp) - 1); + strtmp[sizeof(strtmp) - 1] = '\0'; + strncat(strtmp, "/", sizeof(strtmp) - strlen(strtmp) - 1); + strncat(strtmp, basenp, sizeof(strtmp) - strlen(strtmp) -1); + + free(dir); + free(base); + res = strtmp; + return res; +fail: + free(dir); +fail2: + free(base); + return NULL; +} + int main(int argc, char **argv) { prop_dictionary_t dict; repo_info_t *rinfo = NULL; - char pkgindex[PATH_MAX], *tmp; + const char *dpkgidx; + char plist[PATH_MAX]; if (argc < 2) usage(); @@ -121,22 +166,21 @@ main(int argc, char **argv) if (argc != 3) usage(); - tmp = strncpy(pkgindex, argv[2], sizeof(pkgindex)); - if (sizeof(*tmp) >= sizeof(pkgindex)) - exit(ENAMETOOLONG); + dpkgidx = sanitize_localpath(argv[2]); + if (dpkgidx == NULL) + exit(EINVAL); - /* Append trailing slash if needed */ - if (pkgindex[strlen(pkgindex) - 1] != '/') - strncat(pkgindex, "/", sizeof(pkgindex)); + /* Temp buffer to verify pkgindex file. */ + strncpy(plist, dpkgidx, sizeof(plist) - 1); + plist[sizeof(plist) - 1] = '\0'; + strncat(plist, "/", sizeof(plist) - strlen(plist) - 1); + strncat(plist, XBPS_PKGINDEX, + sizeof(plist) - strlen(plist) - 1); - tmp = strncat(pkgindex, XBPS_PKGINDEX, sizeof(pkgindex)); - if (sizeof(*tmp) >= sizeof(pkgindex)) - exit(ENAMETOOLONG); - - dict = prop_dictionary_internalize_from_file(pkgindex); + dict = prop_dictionary_internalize_from_file(plist); if (dict == NULL) { printf("Directory %s does not contain any " - "xbps pkgindex file.\n", argv[2]); + "xbps pkgindex file.\n", dpkgidx); exit(EINVAL); } @@ -145,13 +189,15 @@ main(int argc, char **argv) exit(ENOMEM); if (!pkgindex_getinfo(dict, rinfo)) { - printf("'%s' is incomplete.\n", pkgindex); + printf("'%s' is incomplete.\n", plist); + free(rinfo); exit(EINVAL); } - if (!xbps_register_repository((const char *)&pkgindex)) { + if (!xbps_register_repository(dpkgidx)) { printf("ERROR: couldn't register repository (%s)\n", strerror(errno)); + free(rinfo); exit(EINVAL); } @@ -168,17 +214,38 @@ main(int argc, char **argv) xbps_callback_array_iter_in_dict(getrepolist_dict(), "repository-list", xbps_list_strings_in_array, NULL); + } else if (strcmp(argv[1], "repo-rm") == 0) { + /* Remove a repository from the pool. */ + if (argc != 3) + usage(); + + dpkgidx = sanitize_localpath(argv[2]); + if (dpkgidx == NULL) + exit(EINVAL); + + if (!xbps_unregister_repository(dpkgidx)) { + if (errno == ENODEV) + printf("Repository '%s' not actually " + "registered.\n", dpkgidx); + else + printf("ERROR: couldn't unregister " + "repository (%s)\n", strerror(errno)); + exit(EINVAL); + } + } else if (strcmp(argv[1], "show") == 0) { /* Shows info about a binary package. */ if (argc != 3) usage(); if (!xbps_callback_array_iter_in_dict(getrepolist_dict(), - "repository-list", xbps_show_pkg_info_from_repolist, - argv[2])) { - printf("Package %s doesn't exist on any repository.\n", + "repository-list", + xbps_show_pkg_info_from_repolist, argv[2])) { + printf("ERROR: unable to locate package '%s'.\n", argv[2]); + exit(EINVAL); } + } else { usage(); }