Line data Source code
1 : /*-
2 : * Copyright (c) 2012-2014 Matthew Seaman <matthew@FreeBSD.org>
3 : * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org>
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions
8 : * are met:
9 : * 1. Redistributions of source code must retain the above copyright
10 : * notice, this list of conditions and the following disclaimer
11 : * in this position and unchanged.
12 : * 2. Redistributions in binary form must reproduce the above copyright
13 : * notice, this list of conditions and the following disclaimer in the
14 : * documentation and/or other materials provided with the distribution.
15 : *
16 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
17 : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 : * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
20 : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 : */
27 :
28 : #include <err.h>
29 : #include <getopt.h>
30 : #include <stdio.h>
31 : #include <sysexits.h>
32 : #include <unistd.h>
33 :
34 : #include <pkg.h>
35 :
36 : #include "pkgcli.h"
37 :
38 : enum action {
39 : LOCK,
40 : UNLOCK,
41 : };
42 :
43 : static int exec_lock_unlock(int, char**, enum action);
44 : static int do_lock(struct pkgdb *db, struct pkg *pkg);
45 : static int do_unlock(struct pkgdb *db, struct pkg *pkg);
46 :
47 : void
48 0 : usage_lock(void)
49 : {
50 0 : fprintf(stderr, "Usage: pkg lock [-lqy] [-a|[-Cgix] <pkg-name>]\n");
51 0 : fprintf(stderr, " pkg lock --has-locked-packages\n");
52 0 : fprintf(stderr, " pkg unlock [-lqy] [-a|[-Cgix] <pkg-name>]\n");
53 0 : fprintf(stderr, "For more information see 'pkg help lock'.\n");
54 0 : }
55 :
56 : static int
57 4 : do_lock(struct pkgdb *db, struct pkg *pkg)
58 : {
59 4 : if (pkg_is_locked(pkg)) {
60 1 : if (!quiet)
61 1 : pkg_printf("%n-%v: already locked\n",
62 : pkg, pkg);
63 1 : return (EPKG_OK);
64 : }
65 :
66 3 : if (!query_yesno(false, "%n-%v: lock this package? ",
67 : pkg, pkg))
68 0 : return (EPKG_OK);
69 :
70 3 : if (!quiet)
71 3 : pkg_printf("Locking %n-%v\n", pkg, pkg);
72 :
73 3 : return (pkgdb_set(db, pkg, PKG_SET_LOCKED, (int)true));
74 : }
75 :
76 :
77 : static int
78 4 : do_unlock(struct pkgdb *db, struct pkg *pkg)
79 : {
80 4 : if (!pkg_is_locked(pkg)) {
81 1 : if (!quiet)
82 1 : pkg_printf("%n-%v: already unlocked\n", pkg, pkg);
83 1 : return (EPKG_OK);
84 : }
85 :
86 3 : if (!query_yesno(false, "%n-%v: unlock this package? ",
87 : pkg, pkg))
88 0 : return (EPKG_OK);
89 :
90 3 : if (!quiet)
91 3 : pkg_printf("Unlocking %n-%v\n", pkg, pkg);
92 :
93 3 : return (pkgdb_set(db, pkg, PKG_SET_LOCKED, (int)false));
94 : }
95 :
96 : static int
97 6 : do_lock_unlock(struct pkgdb *db, int match, const char *pkgname,
98 : enum action action)
99 : {
100 6 : struct pkgdb_it *it = NULL;
101 6 : struct pkg *pkg = NULL;
102 : int retcode;
103 6 : int exitcode = EX_OK;
104 :
105 6 : if (pkgdb_obtain_lock(db, PKGDB_LOCK_EXCLUSIVE) != EPKG_OK) {
106 0 : pkgdb_close(db);
107 0 : warnx("Cannot get an exclusive lock on database. "
108 : "It is locked by another process");
109 0 : return (EX_TEMPFAIL);
110 : }
111 :
112 6 : if ((it = pkgdb_query(db, pkgname, match)) == NULL) {
113 0 : exitcode = EX_IOERR;
114 0 : goto cleanup;
115 : }
116 :
117 20 : while ((retcode = pkgdb_it_next(it, &pkg, 0)) == EPKG_OK) {
118 8 : if (action == LOCK)
119 4 : retcode = do_lock(db, pkg);
120 : else
121 4 : retcode = do_unlock(db, pkg);
122 :
123 8 : if (retcode != EPKG_OK) {
124 0 : exitcode = EX_IOERR;
125 0 : goto cleanup;
126 : }
127 : }
128 :
129 : cleanup:
130 6 : pkg_free(pkg);
131 6 : pkgdb_it_free(it);
132 :
133 6 : pkgdb_release_lock(db, PKGDB_LOCK_EXCLUSIVE);
134 :
135 6 : return (exitcode);
136 : }
137 :
138 : int
139 7 : exec_lock(int argc, char **argv)
140 : {
141 7 : return (exec_lock_unlock(argc, argv, LOCK));
142 : }
143 :
144 : int
145 3 : exec_unlock(int argc, char **argv)
146 : {
147 3 : return (exec_lock_unlock(argc, argv, UNLOCK));
148 : }
149 :
150 : static int
151 4 : list_locked(struct pkgdb *db, bool has_locked)
152 : {
153 4 : struct pkgdb_it *it = NULL;
154 4 : struct pkg *pkg = NULL;
155 4 : bool gotone = false;
156 :
157 4 : if ((it = pkgdb_query(db, " where locked=1", MATCH_CONDITION)) == NULL) {
158 0 : pkgdb_close(db);
159 0 : return (EX_UNAVAILABLE);
160 : }
161 :
162 4 : if (!quiet && !has_locked)
163 4 : printf("Currently locked packages:\n");
164 :
165 11 : while (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC) == EPKG_OK) {
166 3 : gotone = true;
167 3 : if (has_locked)
168 0 : break;
169 3 : pkg_printf("%n-%v\n", pkg, pkg);
170 : }
171 :
172 4 : pkg_free(pkg);
173 4 : pkgdb_it_free(it);
174 :
175 4 : if (has_locked)
176 0 : return (gotone ? EXIT_SUCCESS : EXIT_FAILURE);
177 :
178 4 : return (EX_OK);
179 : }
180 :
181 : static int
182 10 : exec_lock_unlock(int argc, char **argv, enum action action)
183 : {
184 10 : struct pkgdb *db = NULL;
185 : const char *pkgname;
186 10 : int match = MATCH_EXACT;
187 : int retcode;
188 10 : int exitcode = EX_OK;
189 : int ch;
190 10 : bool show_locked = false;
191 10 : bool read_only = false;
192 10 : bool has_locked_packages = false;
193 :
194 10 : struct option longopts[] = {
195 : { "all", no_argument, NULL, 'a' },
196 : { "case-sensitive", no_argument, NULL, 'C' },
197 : { "glob", no_argument, NULL, 'g' },
198 : { "show-locked", no_argument, NULL, 'l' },
199 : { "quiet", no_argument, NULL, 'q' },
200 : { "regex", no_argument, NULL, 'x' },
201 : { "yes", no_argument, NULL, 'y' },
202 : { "has-locked-packages",no_argument, NULL, 1 },
203 : { NULL, 0, NULL, 0 },
204 : };
205 :
206 32 : while ((ch = getopt_long(argc, argv, "+aCgilqxy", longopts, NULL)) != -1) {
207 12 : switch (ch) {
208 : case 'a':
209 2 : match = MATCH_ALL;
210 2 : break;
211 : case 'C':
212 0 : pkgdb_set_case_sensitivity(true);
213 0 : break;
214 : case 'g':
215 0 : match = MATCH_GLOB;
216 0 : break;
217 : case 'i':
218 0 : pkgdb_set_case_sensitivity(false);
219 0 : break;
220 : case 'l':
221 4 : show_locked = true;
222 4 : break;
223 : case 'q':
224 0 : quiet = true;
225 0 : break;
226 : case 'x':
227 0 : match = MATCH_REGEX;
228 0 : break;
229 : case 'y':
230 6 : yes = true;
231 6 : break;
232 : case 1:
233 0 : show_locked = true;
234 0 : has_locked_packages = true;
235 0 : break;
236 : default:
237 0 : usage_lock();
238 0 : return (EX_USAGE);
239 : }
240 : }
241 10 : argc -= optind;
242 10 : argv += optind;
243 :
244 : /* Allow 'pkg lock -l' (or 'pkg unlock -l') without any
245 : * package arguments to just display what packages are
246 : * currently locked. In this case, we only need a read_only
247 : * connection to the DB. */
248 :
249 10 : if (show_locked && match != MATCH_ALL && argc == 0)
250 4 : read_only = true;
251 :
252 10 : if (!show_locked && match != MATCH_ALL && argc == 0) {
253 0 : usage_lock();
254 0 : return (EX_USAGE);
255 : }
256 :
257 10 : if (match == MATCH_ALL)
258 2 : pkgname = NULL;
259 : else
260 8 : pkgname = argv[0];
261 :
262 10 : if (read_only)
263 4 : retcode = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_LOCAL);
264 : else
265 6 : retcode = pkgdb_access(PKGDB_MODE_READ|PKGDB_MODE_WRITE,
266 : PKGDB_DB_LOCAL);
267 10 : if (retcode == EPKG_ENODB) {
268 0 : if (match == MATCH_ALL)
269 0 : return (EX_OK);
270 0 : if (!quiet)
271 0 : warnx("No packages installed. Nothing to do!");
272 0 : return (EX_OK);
273 10 : } else if (retcode == EPKG_ENOACCESS) {
274 0 : warnx("Insufficient privileges to modify the package database");
275 0 : return (EX_NOPERM);
276 10 : } else if (retcode != EPKG_OK) {
277 0 : warnx("Error accessing the package database");
278 0 : return (EX_SOFTWARE);
279 : }
280 :
281 10 : retcode = pkgdb_open(&db, PKGDB_DEFAULT);
282 10 : if (retcode != EPKG_OK)
283 0 : return (EX_IOERR);
284 :
285 10 : if (!read_only)
286 6 : exitcode = do_lock_unlock(db, match, pkgname, action);
287 :
288 10 : if (show_locked)
289 4 : exitcode = list_locked(db, has_locked_packages);
290 :
291 10 : pkgdb_close(db);
292 :
293 10 : return (exitcode);
294 : }
|