Line data Source code
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 : * 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 <err.h>
31 : #include <getopt.h>
32 : #include <stdio.h>
33 : #include <string.h>
34 : #include <sysexits.h>
35 : #include <unistd.h>
36 :
37 : #include <pkg.h>
38 :
39 : #include "pkgcli.h"
40 :
41 : void
42 0 : usage_delete(void)
43 : {
44 0 : fprintf(stderr, "Usage: pkg delete [-DfnqRy] [-Cgix] <pkg-name> ...\n");
45 0 : fprintf(stderr, " pkg delete [-Dnqy] -a\n\n");
46 0 : fprintf(stderr, "For more information see 'pkg help delete'.\n");
47 0 : }
48 :
49 : int
50 4 : exec_delete(int argc, char **argv)
51 : {
52 4 : struct pkg_jobs *jobs = NULL;
53 4 : struct pkgdb *db = NULL;
54 4 : match_t match = MATCH_EXACT;
55 4 : pkg_flags f = PKG_FLAG_NONE;
56 4 : bool recursive_flag = false, rc = false;
57 4 : int retcode = EX_SOFTWARE;
58 : int ch;
59 : int i;
60 4 : int lock_type = PKGDB_LOCK_ADVISORY;
61 :
62 4 : struct option longopts[] = {
63 : { "all", no_argument, NULL, 'a' },
64 : { "case-sensitive", no_argument, NULL, 'C' },
65 : { "no-deinstall-script", no_argument, NULL, 'D' },
66 : { "force", no_argument, NULL, 'f' },
67 : { "glob", no_argument, NULL, 'g' },
68 : { "case-insensitive", no_argument, NULL, 'i' },
69 : { "dry-run", no_argument, NULL, 'n' },
70 : { "quiet", no_argument, NULL, 'q' },
71 : { "recursive", no_argument, NULL, 'R' },
72 : { "regex", no_argument, NULL, 'x' },
73 : { "yes", no_argument, NULL, 'y' },
74 : { NULL, 0, NULL, 0 },
75 : };
76 :
77 4 : nbactions = nbdone = 0;
78 :
79 12 : while ((ch = getopt_long(argc, argv, "+aCDfginqRxy", longopts, NULL)) != -1) {
80 4 : switch (ch) {
81 : case 'a':
82 0 : match = MATCH_ALL;
83 0 : break;
84 : case 'C':
85 0 : pkgdb_set_case_sensitivity(true);
86 0 : break;
87 : case 'D':
88 0 : f |= PKG_FLAG_NOSCRIPT;
89 0 : break;
90 : case 'f':
91 0 : f |= PKG_FLAG_FORCE;
92 0 : force = true;
93 0 : break;
94 : case 'g':
95 0 : match = MATCH_GLOB;
96 0 : break;
97 : case 'i':
98 0 : pkgdb_set_case_sensitivity(false);
99 0 : break;
100 : case 'n':
101 0 : f |= PKG_FLAG_DRY_RUN;
102 0 : lock_type = PKGDB_LOCK_READONLY;
103 0 : dry_run = true;
104 0 : break;
105 : case 'q':
106 0 : quiet = true;
107 0 : break;
108 : case 'R':
109 0 : recursive_flag = true;
110 0 : break;
111 : case 'x':
112 0 : match = MATCH_REGEX;
113 0 : break;
114 : case 'y':
115 4 : yes = true;
116 4 : break;
117 : default:
118 0 : usage_delete();
119 0 : return (EX_USAGE);
120 : }
121 : }
122 :
123 4 : argc -= optind;
124 4 : argv += optind;
125 :
126 4 : if (argc < 1 && match != MATCH_ALL) {
127 0 : usage_delete();
128 0 : return (EX_USAGE);
129 : }
130 :
131 4 : if (dry_run)
132 0 : retcode = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_LOCAL);
133 : else
134 4 : retcode = pkgdb_access(PKGDB_MODE_READ|PKGDB_MODE_WRITE,
135 : PKGDB_DB_LOCAL);
136 :
137 4 : if (retcode == EPKG_ENODB) {
138 0 : warnx("No packages installed. Nothing to do!");
139 0 : return (EX_OK);
140 4 : } else if (retcode == EPKG_ENOACCESS) {
141 0 : warnx("Insufficient privileges to delete packages");
142 0 : return (EX_NOPERM);
143 4 : } else if (retcode != EPKG_OK) {
144 0 : warnx("Error accessing the package database");
145 0 : return (EX_SOFTWARE);
146 : }
147 :
148 4 : if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK)
149 0 : return (EX_IOERR);
150 :
151 4 : if (pkgdb_obtain_lock(db, lock_type) != EPKG_OK) {
152 0 : pkgdb_close(db);
153 0 : warnx("Cannot get an advisory lock on a database, it is locked by another process");
154 0 : return (EX_TEMPFAIL);
155 : }
156 :
157 :
158 4 : if (pkg_jobs_new(&jobs, PKG_JOBS_DEINSTALL, db) != EPKG_OK) {
159 0 : pkgdb_close(db);
160 0 : return (EX_IOERR);
161 : }
162 :
163 : /*
164 : * By default delete packages recursively.
165 : * If force mode is enabled then we try to remove packages non-recursively.
166 : * However, if -f and -R flags are both enabled then we return to
167 : * recursive deletion.
168 : */
169 4 : if (!force || recursive_flag)
170 4 : f |= PKG_FLAG_RECURSIVE;
171 :
172 4 : pkg_jobs_set_flags(jobs, f);
173 :
174 4 : if (match == MATCH_EXACT) {
175 8 : for (i = 0; i < argc; i++) {
176 4 : if (strchr(argv[i], '*') != NULL) {
177 0 : match = MATCH_GLOB;
178 0 : break;
179 : }
180 : }
181 : }
182 :
183 4 : if (pkg_jobs_add(jobs, match, argv, argc) == EPKG_FATAL)
184 0 : goto cleanup;
185 :
186 4 : if (pkg_jobs_solve(jobs) != EPKG_OK) {
187 0 : fprintf(stderr, "Cannot perform request\n");
188 0 : retcode = EX_NOPERM;
189 0 : goto cleanup;
190 : }
191 :
192 : /* check if we have something to deinstall */
193 4 : if ((nbactions = pkg_jobs_count(jobs)) == 0) {
194 0 : if (argc == 0) {
195 0 : if (!quiet)
196 0 : printf("Nothing to do.\n");
197 0 : retcode = EX_OK;
198 : } else {
199 0 : fprintf(stderr, "Package(s) not found!\n");
200 0 : retcode = EX_DATAERR;
201 : }
202 0 : goto cleanup;
203 : }
204 :
205 4 : if (!quiet || dry_run) {
206 4 : if (!quiet) {
207 4 : print_jobs_summary(jobs,
208 : "Deinstallation has been requested for the following %d packages "
209 : "(of %d packages in the universe):\n\n", nbactions,
210 : pkg_jobs_total(jobs));
211 : }
212 4 : if (dry_run) {
213 0 : retcode = EX_OK;
214 0 : goto cleanup;
215 : }
216 4 : rc = query_yesno(false,
217 : "\nProceed with deinstalling packages? ");
218 : }
219 : else
220 0 : rc = yes;
221 :
222 4 : if (!rc || (retcode = pkg_jobs_apply(jobs)) != EPKG_OK)
223 : goto cleanup;
224 :
225 4 : pkgdb_compact(db);
226 :
227 4 : retcode = EX_OK;
228 :
229 : cleanup:
230 4 : pkgdb_release_lock(db, lock_type);
231 4 : pkg_jobs_free(jobs);
232 4 : pkgdb_close(db);
233 :
234 4 : return (retcode);
235 : }
|