delete.c
1 /*- 2 * Copyright (c) 2011-2012 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) 2016 Vsevolod Stakhov <vsevolod@FreeBSD.org> 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer 14 * in this position and unchanged. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <err.h> 32 #include <getopt.h> 33 #include <stdio.h> 34 #include <string.h> 35 #include <unistd.h> 36 37 #include <pkg.h> 38 39 #include "pkgcli.h" 40 41 void 42 usage_delete(void) 43 { 44 fprintf(stderr, "Usage: pkg delete [-DfnqRy] [--autoremove] [-Cgix] <pkg-name> ...\n"); 45 fprintf(stderr, " pkg delete [-Dnqy] [--autoremove] -a\n\n"); 46 fprintf(stderr, "For more information see 'pkg help delete'.\n"); 47 } 48 49 int 50 exec_delete(int argc, char **argv) 51 { 52 struct pkg_jobs *jobs = NULL; 53 struct pkgdb *db = NULL; 54 match_t match = MATCH_EXACT; 55 pkg_flags f = PKG_FLAG_NONE; 56 bool recursive_flag = false, rc = false; 57 bool autoremove_flag = false; 58 int retcode = EXIT_FAILURE; 59 int ch; 60 int i; 61 int lock_type = PKGDB_LOCK_ADVISORY; 62 int locked_pkgs = 0; 63 int nbactions = 0; 64 int scriptnoexec = 0; 65 int autoremove = 0; 66 67 struct option longopts[] = { 68 { "all", no_argument, NULL, 'a' }, 69 { "autoremove", no_argument, &autoremove, 1 }, 70 { "case-sensitive", no_argument, NULL, 'C' }, 71 { "no-scripts", no_argument, NULL, 'D' }, 72 { "script-no-exec", no_argument, &scriptnoexec, 1 }, 73 { "force", no_argument, NULL, 'f' }, 74 { "glob", no_argument, NULL, 'g' }, 75 { "case-insensitive", no_argument, NULL, 'i' }, 76 { "dry-run", no_argument, NULL, 'n' }, 77 { "quiet", no_argument, NULL, 'q' }, 78 { "recursive", no_argument, NULL, 'R' }, 79 { "regex", no_argument, NULL, 'x' }, 80 { "yes", no_argument, NULL, 'y' }, 81 { NULL, 0, NULL, 0 }, 82 }; 83 84 85 while ((ch = getopt_long(argc, argv, "+aCDfginqRxy", longopts, NULL)) != -1) { 86 switch (ch) { 87 case 'a': 88 match = MATCH_ALL; 89 break; 90 case 'C': 91 pkgdb_set_case_sensitivity(true); 92 break; 93 case 'D': 94 f |= PKG_FLAG_NOSCRIPT; 95 break; 96 case 'f': 97 f |= PKG_FLAG_FORCE; 98 force = true; 99 break; 100 case 'g': 101 match = MATCH_GLOB; 102 break; 103 case 'i': 104 pkgdb_set_case_sensitivity(false); 105 break; 106 case 'n': 107 f |= PKG_FLAG_DRY_RUN; 108 lock_type = PKGDB_LOCK_READONLY; 109 dry_run = true; 110 break; 111 case 'q': 112 quiet = true; 113 break; 114 case 'R': 115 recursive_flag = true; 116 break; 117 case 'x': 118 match = MATCH_REGEX; 119 break; 120 case 'y': 121 yes = true; 122 break; 123 case 0: 124 if (scriptnoexec) 125 f |= PKG_FLAG_NOEXEC; 126 if (autoremove) 127 autoremove_flag = true; 128 break; 129 default: 130 usage_delete(); 131 return (EXIT_FAILURE); 132 } 133 } 134 135 argc -= optind; 136 argv += optind; 137 138 if (argc < 1 && match != MATCH_ALL) { 139 usage_delete(); 140 return (EXIT_FAILURE); 141 } 142 143 if (dry_run) 144 retcode = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_LOCAL); 145 else 146 retcode = pkgdb_access(PKGDB_MODE_READ|PKGDB_MODE_WRITE, 147 PKGDB_DB_LOCAL); 148 149 if (retcode == EPKG_ENODB) { 150 warnx("No packages installed. Nothing to do!"); 151 return (EXIT_SUCCESS); 152 } else if (retcode == EPKG_ENOACCESS) { 153 warnx("Insufficient privileges to delete packages"); 154 return (EXIT_FAILURE); 155 } else if (retcode != EPKG_OK) { 156 warnx("Error accessing the package database"); 157 return (EXIT_FAILURE); 158 } 159 160 if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) 161 return (EXIT_FAILURE); 162 163 if (pkgdb_obtain_lock(db, lock_type) != EPKG_OK) { 164 pkgdb_close(db); 165 warnx("Cannot get an advisory lock on a database, it is locked by another process"); 166 return (EXIT_FAILURE); 167 } 168 169 170 if (pkg_jobs_new(&jobs, PKG_JOBS_DEINSTALL, db) != EPKG_OK) { 171 pkgdb_close(db); 172 return (EXIT_FAILURE); 173 } 174 175 /* 176 * By default delete packages recursively. 177 * If force mode is enabled then we try to remove packages non-recursively. 178 * However, if -f and -R flags are both enabled then we return to 179 * recursive deletion. 180 */ 181 if (!force || recursive_flag) 182 f |= PKG_FLAG_RECURSIVE; 183 184 pkg_jobs_set_flags(jobs, f); 185 186 if (match == MATCH_EXACT) { 187 for (i = 0; i < argc; i++) { 188 if (strchr(argv[i], '*') != NULL) { 189 match = MATCH_GLOB; 190 break; 191 } 192 } 193 } 194 195 if (pkg_jobs_add(jobs, match, argv, argc) == EPKG_FATAL) 196 goto cleanup; 197 198 if (pkg_jobs_solve(jobs) != EPKG_OK) { 199 fprintf(stderr, "Cannot perform request\n"); 200 retcode = EXIT_FAILURE; 201 goto cleanup; 202 } 203 204 if (pkg_jobs_has_lockedpkgs(jobs)) { 205 printf("The following package(s) are locked or vital and may not "); 206 printf("be removed:\n\n"); 207 pkg_jobs_iter_lockedpkgs(jobs, print_pkg, &locked_pkgs); 208 putchar('\n'); 209 } 210 211 /* check if we have something to deinstall */ 212 if ((nbactions = pkg_jobs_count(jobs)) == 0) { 213 if (argc == 0) { 214 if (!quiet) 215 printf("Nothing to do.\n"); 216 217 retcode = EXIT_SUCCESS; 218 goto cleanup; 219 } 220 if (!quiet) { 221 printf("%d packages requested for removal: " 222 "%d locked, %d missing\n", 223 argc, locked_pkgs, argc - locked_pkgs); 224 } 225 if (locked_pkgs > 0) { 226 retcode = EPKG_LOCKED; 227 } else { 228 retcode = EXIT_FAILURE; 229 } 230 goto cleanup; 231 } 232 233 if (!quiet || dry_run) { 234 if (!quiet) { 235 print_jobs_summary(jobs, 236 "Deinstallation has been requested for the following %d packages " 237 "(of %d packages in the universe):\n\n", nbactions, 238 pkg_jobs_total(jobs)); 239 } 240 if (dry_run) { 241 retcode = EXIT_SUCCESS; 242 goto cleanup; 243 } 244 rc = query_yesno(false, 245 "\nProceed with deinstalling packages? "); 246 } 247 else 248 rc = yes; 249 250 if (!rc || (retcode = pkg_jobs_apply(jobs)) != EPKG_OK) 251 goto cleanup; 252 253 if (messages != NULL) { 254 fflush(messages->fp); 255 printf("%s", messages->buf); 256 } 257 pkgdb_compact(db); 258 pkgcli_autoremove(db, autoremove_flag); 259 260 retcode = EXIT_SUCCESS; 261 262 cleanup: 263 pkgdb_release_lock(db, lock_type); 264 pkg_jobs_free(jobs); 265 pkgdb_close(db); 266 267 return (retcode); 268 }