fetch.c
1 /*- 2 * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com> 3 * Copyright (c) 2013-2014 Matthew Seaman <matthew@FreeBSD.org> 4 * Copyright (c) 2012-2013 Bryan Drewery <bdrewery@FreeBSD.org> 5 * Copyright (c) 2016 Vsevolod Stakhov <vsevolod@FreeBSD.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer 13 * in this position and unchanged. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/types.h> 31 32 #include <err.h> 33 #include <getopt.h> 34 #include <libgen.h> 35 #include <stdbool.h> 36 #include <stdio.h> 37 #include <string.h> 38 #include <unistd.h> 39 40 #include <pkg.h> 41 42 #include "pkgcli.h" 43 44 void 45 usage_fetch(void) 46 { 47 fprintf(stderr, "Usage: pkg fetch [-r reponame] [-o destdir] [-dqsUy] " 48 "[-Cgix] <pkg-name> <...>\n"); 49 fprintf(stderr, " pkg fetch [-r reponame] [-dqUy] -a\n"); 50 fprintf(stderr, " pkg fetch [-r reponame] [-dqUy] -u\n\n"); 51 fprintf(stderr, "For more information see 'pkg help fetch'.\n"); 52 } 53 54 int 55 exec_fetch(int argc, char **argv) 56 { 57 struct pkgdb *db = NULL; 58 struct pkg_jobs *jobs = NULL; 59 const char *destdir = NULL; 60 int ch; 61 int retcode; 62 int status = EXIT_FAILURE; 63 bool upgrades_for_installed = false, rc, csum_only = false; 64 unsigned mode; 65 match_t match = MATCH_EXACT; 66 pkg_flags f = PKG_FLAG_NONE; 67 c_charv_t reponames = vec_init(); 68 69 if (getenv("PKG_REPO_SYMLINK") != NULL) 70 f |= PKG_FLAG_FETCH_SYMLINK; 71 72 struct option longopts[] = { 73 { "all", no_argument, NULL, 'a' }, 74 { "case-sensitive", no_argument, NULL, 'C' }, 75 { "dependencies", no_argument, NULL, 'd' }, 76 { "glob", no_argument, NULL, 'g' }, 77 { "case-insensitive", no_argument, NULL, 'i' }, 78 { "quiet", no_argument, NULL, 'q' }, 79 { "repository", required_argument, NULL, 'r' }, 80 { "symlink", no_argument, NULL, 's' }, 81 { "available-updates", no_argument, NULL, 'u' }, 82 { "no-repo-update", no_argument, NULL, 'U' }, 83 { "regex", no_argument, NULL, 'x' }, 84 { "yes", no_argument, NULL, 'y' }, 85 { "output", required_argument, NULL, 'o' }, 86 { NULL, 0, NULL, 0 }, 87 }; 88 89 while ((ch = getopt_long(argc, argv, "+aCdgiqr:sUuxyo:", longopts, NULL)) != -1) { 90 switch (ch) { 91 case 'a': 92 match = MATCH_ALL; 93 break; 94 case 'C': 95 pkgdb_set_case_sensitivity(true); 96 break; 97 case 'd': 98 f |= PKG_FLAG_WITH_DEPS | PKG_FLAG_RECURSIVE; 99 break; 100 case 'g': 101 match = MATCH_GLOB; 102 break; 103 case 'i': 104 pkgdb_set_case_sensitivity(false); 105 break; 106 case 'q': 107 quiet = true; 108 break; 109 case 'r': 110 vec_push(&reponames, optarg); 111 break; 112 case 's': 113 f |= PKG_FLAG_FETCH_SYMLINK; 114 break; 115 case 'u': 116 f |= PKG_FLAG_UPGRADES_FOR_INSTALLED; 117 upgrades_for_installed = true; 118 break; 119 case 'U': 120 auto_update = false; 121 break; 122 case 'x': 123 match = MATCH_REGEX; 124 break; 125 case 'y': 126 yes = true; 127 break; 128 case 'o': 129 f |= PKG_FLAG_FETCH_MIRROR; 130 destdir = optarg; 131 break; 132 default: 133 usage_fetch(); 134 return (EXIT_FAILURE); 135 } 136 } 137 argc -= optind; 138 argv += optind; 139 140 if (argc < 1 && match != MATCH_ALL && !upgrades_for_installed) { 141 usage_fetch(); 142 return (EXIT_FAILURE); 143 } 144 145 if (match == MATCH_ALL && upgrades_for_installed) { 146 usage_fetch(); 147 return (EXIT_FAILURE); 148 } 149 150 if (auto_update) 151 mode = PKGDB_MODE_READ|PKGDB_MODE_WRITE|PKGDB_MODE_CREATE; 152 else 153 mode = PKGDB_MODE_READ; 154 155 retcode = pkgdb_access2(mode, PKGDB_DB_REPO, &reponames); 156 157 if (retcode == EPKG_ENOACCESS) { 158 warnx("Insufficient privileges to access repo catalogue"); 159 return (EXIT_FAILURE); 160 } else if (retcode != EPKG_OK) 161 return (EXIT_FAILURE); 162 163 if (upgrades_for_installed) { 164 retcode = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_LOCAL); 165 166 if (retcode == EPKG_ENOACCESS) { 167 warnx("Insufficient privileges to access the package database"); 168 return (EXIT_FAILURE); 169 } else if (retcode != EPKG_OK) 170 return (EXIT_FAILURE); 171 } 172 173 /* first update the remote repositories if needed */ 174 if (auto_update && 175 (retcode = pkgcli_update(false, false, &reponames)) != EPKG_OK) 176 return (retcode); 177 178 if (pkgdb_open_all2(&db, PKGDB_REMOTE, &reponames) != EPKG_OK) 179 return (EXIT_FAILURE); 180 181 if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY) != EPKG_OK) { 182 pkgdb_close(db); 183 warnx("Cannot get a read lock on a database, it is locked by another process"); 184 return (EXIT_FAILURE); 185 } 186 187 188 if (pkg_jobs_new(&jobs, PKG_JOBS_FETCH, db) != EPKG_OK) 189 goto cleanup; 190 191 if (pkg_jobs_set_repositories(jobs, &reponames) != EPKG_OK) 192 goto cleanup; 193 194 if (destdir != NULL && pkg_jobs_set_destdir(jobs, destdir) != EPKG_OK) 195 goto cleanup; 196 197 pkg_jobs_set_flags(jobs, f); 198 199 if (!upgrades_for_installed && 200 pkg_jobs_add(jobs, match, argv, argc) != EPKG_OK) 201 goto cleanup; 202 203 if (pkg_jobs_solve(jobs) != EPKG_OK) 204 goto cleanup; 205 206 if (pkg_jobs_count(jobs) == 0) 207 goto cleanup; 208 209 if (!quiet) { 210 211 rc = print_jobs_summary(jobs, 212 "The following packages will be fetched:\n\n"); 213 214 if (rc != 0) { 215 rc = query_yesno(false, "\nProceed with fetching " 216 "packages? "); 217 } else { 218 printf("No packages are required to be fetched.\n"); 219 rc = query_yesno(false, "Check the integrity of packages " 220 "downloaded? "); 221 csum_only = true; 222 } 223 } 224 else { 225 rc = true; 226 } 227 228 if (!rc || (retcode = pkg_jobs_apply(jobs)) != EPKG_OK) 229 goto cleanup; 230 231 if (csum_only && !quiet) 232 printf("Integrity check was successful.\n"); 233 234 status = EXIT_SUCCESS; 235 236 cleanup: 237 pkg_jobs_free(jobs); 238 pkgdb_release_lock(db, PKGDB_LOCK_READONLY); 239 pkgdb_close(db); 240 241 return (status); 242 }