diff --git a/bin/xbps-bin/install.c b/bin/xbps-bin/install.c index c65015e3..76b48058 100644 --- a/bin/xbps-bin/install.c +++ b/bin/xbps-bin/install.c @@ -122,8 +122,7 @@ download_package_list(prop_object_iterator_t iter) /* * Skip packages in local repositories. */ - if ((strncmp(repoloc, "http://", 7)) && - (strncmp(repoloc, "ftp://", 6))) + if (!xbps_check_is_repo_string_remote(repoloc)) continue; prop_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); diff --git a/bin/xbps-repo/main.c b/bin/xbps-repo/main.c index be05ce91..ce333528 100644 --- a/bin/xbps-repo/main.c +++ b/bin/xbps-repo/main.c @@ -49,14 +49,13 @@ usage(void) { printf("Usage: xbps-repo [options] [action] [arguments]\n\n" " Available actions:\n" - " add, genindex, list, remove, search, show\n" + " add, genindex, list, remove, search, show, sync\n" " Actions with arguments:\n" " add\t\t\n" " genindex\t\n" " remove\t\n" " search\t\n" " show\t\n" - " sync\t\t\n" " Options shared by all actions:\n" " -r\t\t\n" " -V\t\tPrints xbps release version\n" @@ -134,21 +133,21 @@ out: } static int -add_repository(const char *uri, bool remote) +add_repository(const char *uri) { prop_dictionary_t dict; repo_info_t *rinfo; char *plist, idxstr[PATH_MAX]; int rv = 0; - if (remote) { + if (xbps_check_is_repo_string_remote(uri)) { if (!sanitize_localpath(idxstr, uri)) return errno; printf("Fetching remote package index at %s...\n", uri); rv = xbps_sync_repository_pkg_index(idxstr); if (rv != 0) { - printf("Couldn't download pkg index: %s\n", + printf("Error: could not fetch pkg index file: %s.\n", xbps_fetch_error_string()); return rv; } @@ -208,8 +207,8 @@ int main(int argc, char **argv) { char dpkgidx[PATH_MAX], *root = NULL; + struct repository_data *rdata = NULL; int c, rv = 0; - bool remote_repo = false; while ((c = getopt(argc, argv, "Vr:")) != -1) { switch (c) { @@ -238,11 +237,7 @@ main(int argc, char **argv) if (argc != 2) usage(); - if ((strncmp(argv[1], "http://", 7) == 0) || - (strncmp(argv[1], "ftp://", 6) == 0)) - remote_repo = true; - - rv = add_repository(argv[1], remote_repo); + rv = add_repository(argv[1]); } else if (strcasecmp(argv[0], "list") == 0) { /* Lists all repositories registered in pool. */ @@ -304,15 +299,25 @@ main(int argc, char **argv) exit(rv); } else if (strcasecmp(argv[0], "sync") == 0) { - /* Syncs the pkg index file from a remote repo */ - if (argc != 2) + /* Syncs the pkg index for all registered remote repos */ + if (argc != 1) usage(); - if (!sanitize_localpath(dpkgidx, argv[1])) - exit(EXIT_FAILURE); - - printf("Updating package index from: %s\n", dpkgidx); - rv = xbps_sync_repository_pkg_index(dpkgidx); + if ((rv = xbps_prepare_repolist_data()) != 0) + exit(rv); + /* + * Iterate over repository pool. + */ + SIMPLEQ_FOREACH(rdata, &repodata_queue, chain) { + const char *uri = rdata->rd_uri; + if (xbps_check_is_repo_string_remote(uri)) { + printf("Syncing package index from: %s\n", uri); + rv = xbps_sync_repository_pkg_index(uri); + if (rv != 0) + break; + } + } + xbps_release_repolist_data(); } else { usage(); diff --git a/bin/xbps-repo/xbps-repo.8.txt b/bin/xbps-repo/xbps-repo.8.txt index 3eb2c471..95095452 100644 --- a/bin/xbps-repo/xbps-repo.8.txt +++ b/bin/xbps-repo/xbps-repo.8.txt @@ -67,10 +67,9 @@ Please note that all targets are *case insensitive*. the size it takes in filesystem, description, maintainer, architecture and other information. -*sync 'URI'*:: - Syncs the package index file that is available from the repository - specified at 'URI'. The new file will be fetched if it has been - modified since last synchronization. +*sync*:: + Syncs the package index file for all registered remote repositories. + The new file will be fetched if local and remote size/mtime do not match. BUGS diff --git a/include/xbps_api.h b/include/xbps_api.h index deeb6ad3..5481377e 100644 --- a/include/xbps_api.h +++ b/include/xbps_api.h @@ -221,6 +221,7 @@ int SYMEXPORT xbps_check_pkg_file_hash(prop_dictionary_t, const char *); int SYMEXPORT xbps_check_is_installed_pkg(const char *); bool SYMEXPORT xbps_check_is_installed_pkgname(const char *); +bool SYMEXPORT xbps_check_is_repo_string_remote(const char *); char SYMEXPORT *xbps_get_pkg_index_plist(const char *); char SYMEXPORT *xbps_get_pkg_name(const char *); char SYMEXPORT *xbps_get_pkgdep_name(const char *); diff --git a/lib/sync_remote_pkgidx.c b/lib/sync_remote_pkgidx.c index 7cb1c957..e571534e 100644 --- a/lib/sync_remote_pkgidx.c +++ b/lib/sync_remote_pkgidx.c @@ -45,23 +45,23 @@ xbps_get_remote_repo_string(const char *uri) return NULL; /* - * Replace dots and slashes with underscores, so that + * Replace '.' ':' and '/' characters with underscores, so that * provided URL: * - * www.foo.org/blah/xbps/binpkg-repo + * http://www.foo.org/blah/xbps/binpkg-repo * * becomes: * - * www_foo_org_blah_xbps_binpkg_repo + * http___www_foo_org_blah_xbps_binpkg_repo * */ - p = xbps_xasprintf("%s%s", url->host, url->doc); + p = xbps_xasprintf("%s://%s%s", url->scheme, url->host, url->doc); fetchFreeURL(url); if (p == NULL) return NULL; for (i = 0; i < strlen(p); i++) { - if (p[i] == '.' || p[i] == '/') + if (p[i] == '.' || p[i] == '/' || p[i] == ':') p[i] = '_'; } @@ -71,10 +71,17 @@ xbps_get_remote_repo_string(const char *uri) int SYMEXPORT xbps_sync_repository_pkg_index(const char *uri) { - struct url *url; + struct url *url = NULL; struct utsname un; - char *rpidx, *dir, *lrepodir, *uri_fixedp = NULL; + struct stat st; + const char *fetch_outputdir; + char *rpidx, *dir, *lrepodir, *uri_fixedp; + char *metadir, *tmp_metafile, *lrepofile; int rv = 0; + bool only_sync = false; + + rpidx = dir = lrepodir = uri_fixedp = NULL; + metadir = tmp_metafile = lrepofile = NULL; if (uname(&un) == -1) return errno; @@ -88,55 +95,137 @@ xbps_sync_repository_pkg_index(const char *uri) return errno; } + /* + * Create metadir if it doesn't exist yet. + */ + metadir = xbps_xasprintf("%s/%s", xbps_get_rootdir(), + XBPS_META_PATH); + if (metadir == NULL) { + rv = errno; + goto out; + } + rv = stat(metadir, &st); + if (rv == -1 && errno == ENOENT) { + if (mkpath(metadir, 0755) == -1) { + rv = errno; + goto out; + } + } else if (rv == 0 && !S_ISDIR(st.st_mode)) { + rv = ENOTDIR; + goto out; + } + + /* + * Remote repository pkg-index.plist full URL. + */ + rpidx = xbps_xasprintf("%s/%s/%s", uri, un.machine, XBPS_PKGINDEX); + if (rpidx == NULL) { + rv = errno; + goto out; + } + /* + * Save temporary file in XBPS_META_PATH, and rename if it + * was downloaded successfully. + */ + tmp_metafile = xbps_xasprintf("%s/%s", metadir, XBPS_PKGINDEX); + if (tmp_metafile == NULL) { + rv = errno; + goto out; + } + /* + * Full path to machine arch local repository directory. + */ + lrepodir = xbps_xasprintf("%s/%s/%s/%s", + xbps_get_rootdir(), XBPS_META_PATH, uri_fixedp, un.machine); + if (lrepodir == NULL) { + rv = errno; + goto out; + } + /* + * If directory exists probably the pkg-index.plist file + * was downloaded previously... + */ + rv = stat(lrepodir, &st); + if (rv == 0 && S_ISDIR(st.st_mode)) { + only_sync = true; + fetch_outputdir = lrepodir; + } else + fetch_outputdir = metadir; + + /* + * Download pkg-index.plist file from repository. + */ + if ((rv = xbps_fetch_file(rpidx, fetch_outputdir, + true, NULL)) != 0) { + (void)remove(tmp_metafile); + goto out; + } + if (only_sync) + goto out; + /* * Create local arch repodir: * * /var/db/xbps/repo// */ - lrepodir = xbps_xasprintf("%s/%s/repo/%s/%s", - xbps_get_rootdir(), XBPS_META_PATH, uri_fixedp, un.machine); - if (lrepodir == NULL) { - fetchFreeURL(url); - free(uri_fixedp); - return errno; - } - if (mkpath(lrepodir, 0755) == -1) { - free(lrepodir); - free(uri_fixedp); - fetchFreeURL(url); - return errno; + rv = stat(lrepodir, &st); + if (rv == -1 && errno == ENOENT) { + if (mkpath(lrepodir, 0755) == -1) { + rv = errno; + goto out; + } + } else if (rv == 0 && !S_ISDIR(st.st_mode)) { + rv = ENOTDIR; + goto out; } /* * Create local noarch repodir: * * /var/db/xbps/repo//noarch */ - dir = xbps_xasprintf("%s/%s/repo/%s/noarch", + dir = xbps_xasprintf("%s/%s/%s/noarch", xbps_get_rootdir(), XBPS_META_PATH, uri_fixedp); - free(uri_fixedp); - fetchFreeURL(url); if (dir == NULL) { - free(lrepodir); - return errno; + rv = errno; + goto out; } - if (mkpath(dir, 0755) == -1) { + rv = stat(dir, &st); + if (rv == -1 && errno == ENOENT) { + if (mkpath(dir, 0755) == -1) { + free(dir); + rv = errno; + goto out; + } + } else if (rv == 0 && !S_ISDIR(st.st_mode)) { free(dir); - free(lrepodir); - return errno; + rv = ENOTDIR; + goto out; } free(dir); - /* - * Download pkg-index.plist file from repository. - */ - rpidx = xbps_xasprintf("%s/%s/%s", uri, un.machine, XBPS_PKGINDEX); - if (rpidx == NULL) { - free(lrepodir); - return errno; + lrepofile = xbps_xasprintf("%s/%s", lrepodir, XBPS_PKGINDEX); + if (lrepofile == NULL) { + rv = errno; + goto out; } - rv = xbps_fetch_file(rpidx, lrepodir, true, NULL); - - free(rpidx); - free(lrepodir); + /* + * Rename to destination file now it has been fetched successfully. + */ + rv = rename(tmp_metafile, lrepofile); +out: + if (rpidx) + free(rpidx); + if (lrepodir) + free(lrepodir); + if (metadir) + free(metadir); + if (tmp_metafile) + free(tmp_metafile); + if (lrepofile) + free(lrepofile); + if (url) + fetchFreeURL(url); + if (uri_fixedp) + free(uri_fixedp); return rv; } diff --git a/lib/util.c b/lib/util.c index 907f77e8..cf778599 100644 --- a/lib/util.c +++ b/lib/util.c @@ -111,6 +111,19 @@ xbps_check_pkg_file_hash(prop_dictionary_t pkgd, const char *repoloc) return rv; } +bool SYMEXPORT +xbps_check_is_repo_string_remote(const char *uri) +{ + assert(uri != NULL); + + if ((strncmp(uri, "https://", 8) == 0) || + (strncmp(uri, "http://", 7) == 0) || + (strncmp(uri, "ftp://", 6) == 0)) + return true; + + return false; +} + int SYMEXPORT xbps_check_is_installed_pkg(const char *pkg) { @@ -289,7 +302,7 @@ get_pkg_index_remote_plist(const char *uri, const char *machine) if (uri_fixed == NULL) return NULL; - repodir = xbps_xasprintf("%s/%s/repo/%s/%s/%s", + repodir = xbps_xasprintf("%s/%s/%s/%s/%s", xbps_get_rootdir(), XBPS_META_PATH, uri_fixed, machine, XBPS_PKGINDEX); if (repodir == NULL) {