install.c
1 /*- 2 * Copyright (c) 2011-2016 Baptiste Daroussin <bapt@FreeBSD.org> 3 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org> 4 * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com> 5 * Copyright (c) 2013-2014 Matthew Seaman <matthew@FreeBSD.org> 6 * Copyright (c) 2012-2013 Bryan Drewery <bdrewery@FreeBSD.org> 7 * Copyright (c) 2016 Vsevolod Stakhov <vsevolod@FreeBSD.org> 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer 15 * in this position and unchanged. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/types.h> 33 34 #include <err.h> 35 #include <getopt.h> 36 #include <libgen.h> 37 #include <stdbool.h> 38 #include <stdio.h> 39 #include <string.h> 40 #include <unistd.h> 41 42 #include <pkg.h> 43 44 #include "pkgcli.h" 45 46 void 47 usage_install(void) 48 { 49 fprintf(stderr, 50 "Usage: pkg install [-ACfFgiIlMnqRUxy] [--autoremove] [-r reponame] <pkg-name> ...\n\n"); 51 fprintf(stderr, "For more information see 'pkg help install'.\n"); 52 } 53 54 int 55 exec_install(int argc, char **argv) 56 { 57 struct pkgdb *db = NULL; 58 struct pkg_jobs *jobs = NULL; 59 int retcode; 60 int status; 61 int updcode = EPKG_OK; 62 int ch; 63 int mode, repo_type; 64 int done = 0; 65 int lock_type = PKGDB_LOCK_ADVISORY; 66 int nbactions = 0; 67 int scriptnoexec = 0; 68 int autoremove = 0; 69 bool rc = true; 70 bool local_only = false; 71 bool autoremove_flag = false; 72 match_t match = MATCH_EXACT; 73 pkg_flags f = PKG_FLAG_NONE | PKG_FLAG_PKG_VERSION_TEST; 74 c_charv_t reponames = vec_init(); 75 76 struct option longopts[] = { 77 { "automatic", no_argument, NULL, 'A' }, 78 { "autoremove", no_argument, &autoremove, 1 }, 79 { "case-sensitive", no_argument, NULL, 'C' }, 80 { "force", no_argument, NULL, 'f' }, 81 { "fetch-only", no_argument, NULL, 'F' }, 82 { "glob", no_argument, NULL, 'g' }, 83 { "case-insensitive", no_argument, NULL, 'i' }, 84 { "no-scripts", no_argument, NULL, 'I' }, 85 { "script-no-exec", no_argument, &scriptnoexec, 1 }, 86 { "local-only", no_argument, NULL, 'l' }, 87 { "ignore-missing", no_argument, NULL, 'M' }, 88 { "dry-run", no_argument, NULL, 'n' }, 89 { "quiet", no_argument, NULL, 'q' }, 90 { "repository", required_argument, NULL, 'r' }, 91 { "recursive", no_argument, NULL, 'R' }, 92 { "no-repo-update", no_argument, NULL, 'U' }, 93 { "regex", no_argument, NULL, 'x' }, 94 { "register-only", no_argument, NULL, 'X' }, 95 { "yes", no_argument, NULL, 'y' }, 96 { NULL, 0, NULL, 0 }, 97 }; 98 99 if (STREQ(argv[0], "add")) { 100 auto_update = false; 101 local_only = true; 102 yes = true; 103 quiet = true; 104 } 105 106 while ((ch = getopt_long(argc, argv, "+ACfFgiIlMnqr:RUxy", longopts, NULL)) != -1) { 107 switch (ch) { 108 case 'A': 109 f |= PKG_FLAG_AUTOMATIC; 110 break; 111 case 'C': 112 pkgdb_set_case_sensitivity(true); 113 break; 114 case 'f': 115 f |= PKG_FLAG_FORCE; 116 break; 117 case 'F': 118 f |= PKG_FLAG_SKIP_INSTALL; 119 lock_type = PKGDB_LOCK_READONLY; 120 break; 121 case 'g': 122 match = MATCH_GLOB; 123 break; 124 case 'i': 125 pkgdb_set_case_sensitivity(false); 126 break; 127 case 'I': 128 f |= PKG_FLAG_NOSCRIPT; 129 break; 130 case 'l': 131 local_only = true; 132 auto_update = false; 133 break; 134 case 'M': 135 f |= PKG_FLAG_FORCE_MISSING; 136 break; 137 case 'n': 138 f |= PKG_FLAG_DRY_RUN; 139 lock_type = PKGDB_LOCK_READONLY; 140 dry_run = true; 141 break; 142 case 'q': 143 quiet = true; 144 break; 145 case 'r': 146 vec_push(&reponames, optarg); 147 break; 148 case 'R': 149 f |= PKG_FLAG_RECURSIVE; 150 break; 151 case 'U': 152 auto_update = false; 153 break; 154 case 'x': 155 match = MATCH_REGEX; 156 break; 157 case 'X': 158 f |= PKG_FLAG_REGISTER_ONLY | PKG_FLAG_NOSCRIPT; 159 break; 160 case 'y': 161 yes = true; 162 break; 163 case 0: 164 if (scriptnoexec == 1) 165 f |= PKG_FLAG_NOEXEC; 166 if (autoremove) 167 autoremove_flag = true; 168 break; 169 default: 170 usage_install(); 171 return (EXIT_FAILURE); 172 } 173 } 174 argc -= optind; 175 argv += optind; 176 177 if (argc < 1) { 178 usage_install(); 179 return (EXIT_FAILURE); 180 } 181 182 if (dry_run && !auto_update) 183 mode = PKGDB_MODE_READ; 184 else 185 mode = PKGDB_MODE_READ | 186 PKGDB_MODE_WRITE | 187 PKGDB_MODE_CREATE; 188 if (local_only) 189 repo_type = PKGDB_DB_LOCAL; 190 else 191 repo_type = PKGDB_DB_LOCAL|PKGDB_DB_REPO; 192 193 /* It is safe to use both `reponame` and `NULL` here */ 194 retcode = pkgdb_access2(mode, repo_type, &reponames); 195 196 if (retcode == EPKG_ENOACCESS && dry_run) { 197 auto_update = false; 198 retcode = pkgdb_access2(PKGDB_MODE_READ, 199 repo_type, &reponames); 200 } 201 202 if (retcode == EPKG_ENOACCESS) { 203 warnx("Insufficient privileges to install packages"); 204 return (EXIT_FAILURE); 205 } else if (retcode != EPKG_OK) 206 return (EXIT_FAILURE); 207 208 /* first update the remote repositories if needed */ 209 if (auto_update && pkg_repos_total_count() > 0 && 210 (updcode = pkgcli_update(false, false, &reponames)) != EPKG_OK) 211 return (updcode); 212 213 if (pkgdb_open_all2(&db, 214 local_only ? PKGDB_DEFAULT : PKGDB_MAYBE_REMOTE, 215 &reponames) != EPKG_OK) 216 return (EXIT_FAILURE); 217 218 if (pkgdb_obtain_lock(db, lock_type) != EPKG_OK) { 219 pkgdb_close(db); 220 warnx("Cannot get an advisory lock on a database, it is locked by another process"); 221 return (EXIT_FAILURE); 222 } 223 224 status = EXIT_FAILURE; 225 if (pkg_jobs_new(&jobs, PKG_JOBS_INSTALL, db) != EPKG_OK) 226 goto cleanup; 227 228 if (!local_only && reponames.len > 0 && 229 pkg_jobs_set_repositories(jobs, &reponames) != EPKG_OK) 230 goto cleanup; 231 232 pkg_jobs_set_flags(jobs, f); 233 234 if (pkg_jobs_add(jobs, match, argv, argc) == EPKG_FATAL) 235 goto cleanup; 236 237 if (pkg_jobs_solve(jobs) != EPKG_OK) 238 goto cleanup; 239 240 status = EXIT_SUCCESS; 241 while ((nbactions = pkg_jobs_count(jobs)) > 0) { 242 rc = yes; 243 /* print a summary before applying the jobs */ 244 if (!quiet || dry_run) { 245 print_jobs_summary(jobs, 246 "The following %d package(s) will be affected (of %d checked):\n\n", 247 nbactions, pkg_jobs_total(jobs)); 248 } 249 if (dry_run) 250 break; 251 252 if (!quiet) { 253 rc = query_yesno(false, 254 "\nProceed with this action? "); 255 } 256 257 if (rc) { 258 retcode = pkg_jobs_apply(jobs); 259 done = 1; 260 if (retcode == EPKG_CONFLICT) { 261 printf("Conflicts with the existing packages " 262 "have been found.\nOne more solver " 263 "iteration is needed to resolve them.\n"); 264 continue; 265 } 266 else if (retcode != EPKG_OK) { 267 status = retcode; 268 goto cleanup; 269 } 270 } 271 272 if (messages != NULL) { 273 fflush(messages->fp); 274 printf("%s", messages->buf); 275 } 276 break; 277 } 278 279 if (done == 0 && rc) { 280 bool want_automatic = (f & PKG_FLAG_AUTOMATIC) != 0; 281 bool suggested = false; 282 283 for (int i = 0; i < argc; i++) { 284 struct pkgdb_it *lit; 285 struct pkg *lpkg = NULL; 286 bool automatic; 287 288 lit = pkgdb_query(db, argv[i], match); 289 if (lit == NULL) 290 continue; 291 if (pkgdb_it_next(lit, &lpkg, PKG_LOAD_BASIC) != EPKG_OK) { 292 pkgdb_it_free(lit); 293 continue; 294 } 295 pkgdb_it_free(lit); 296 pkg_get(lpkg, PKG_ATTR_AUTOMATIC, &automatic); 297 if (!want_automatic && automatic) { 298 if (query_yesno(false, 299 "%n-%v is already installed as automatic. " 300 "Mark as non-automatic? ", 301 lpkg, lpkg)) 302 pkgdb_set(db, lpkg, 303 PKG_SET_AUTOMATIC, (int)false); 304 suggested = true; 305 } else if (want_automatic && !automatic) { 306 if (query_yesno(false, 307 "%n-%v is already installed. " 308 "Mark as automatically installed? ", 309 lpkg, lpkg)) 310 pkgdb_set(db, lpkg, 311 PKG_SET_AUTOMATIC, (int)true); 312 suggested = true; 313 } 314 pkg_free(lpkg); 315 } 316 if (!suggested) 317 printf("The most recent versions of packages are already installed\n"); 318 } 319 320 if (!rc) 321 status = EXIT_FAILURE; 322 323 if (done && status == EXIT_SUCCESS) 324 pkgcli_autoremove(db, autoremove_flag); 325 326 cleanup: 327 pkgdb_release_lock(db, lock_type); 328 pkg_jobs_free(jobs); 329 pkgdb_close(db); 330 331 if (!dry_run) 332 pkg_cache_full_clean(); 333 334 if (!rc && newpkgversion) 335 newpkgversion = false; 336 337 return (status); 338 }