Branch data 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 <stdlib.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 : 20 : do_lock(struct pkgdb *db, struct pkg *pkg)
58 : : {
59 [ + + ]: 20 : if (pkg_is_locked(pkg)) {
60 [ - + ]: 4 : if (!quiet)
61 : 4 : pkg_printf("%n-%v: already locked\n",
62 : 4 : pkg, pkg);
63 : 4 : return (EPKG_OK);
64 : : }
65 : :
66 [ + - ]: 16 : if (!query_yesno(false, "%n-%v: lock this package? ",
67 : 16 : pkg, pkg))
68 : 0 : return (EPKG_OK);
69 : :
70 [ + - ]: 16 : if (!quiet)
71 : 16 : pkg_printf("Locking %n-%v\n", pkg, pkg);
72 : :
73 : 16 : return (pkgdb_set(db, pkg, PKG_SET_LOCKED, (int)true));
74 : 20 : }
75 : :
76 : :
77 : : static int
78 : 16 : do_unlock(struct pkgdb *db, struct pkg *pkg)
79 : : {
80 [ + + ]: 16 : if (!pkg_is_locked(pkg)) {
81 [ - + ]: 4 : if (!quiet)
82 : 4 : pkg_printf("%n-%v: already unlocked\n", pkg, pkg);
83 : 4 : return (EPKG_OK);
84 : : }
85 : :
86 [ + - ]: 12 : if (!query_yesno(false, "%n-%v: unlock this package? ",
87 : 12 : pkg, pkg))
88 : 0 : return (EPKG_OK);
89 : :
90 [ + - ]: 12 : if (!quiet)
91 : 12 : pkg_printf("Unlocking %n-%v\n", pkg, pkg);
92 : :
93 : 12 : return (pkgdb_set(db, pkg, PKG_SET_LOCKED, (int)false));
94 : 16 : }
95 : :
96 : : static int
97 : 28 : do_lock_unlock(struct pkgdb *db, int match, const char *pkgname,
98 : : enum action action)
99 : : {
100 : 28 : struct pkgdb_it *it = NULL;
101 : 28 : struct pkg *pkg = NULL;
102 : : int retcode;
103 : 28 : int exitcode = EXIT_SUCCESS;
104 : :
105 [ - + ]: 28 : 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 (EXIT_FAILURE);
110 : : }
111 : :
112 [ + - ]: 28 : if ((it = pkgdb_query(db, pkgname, match)) == NULL) {
113 : 0 : exitcode = EXIT_FAILURE;
114 : 0 : goto cleanup;
115 : : }
116 : :
117 [ + + ]: 64 : while (pkgdb_it_next(it, &pkg, 0) == EPKG_OK) {
118 [ + + ]: 36 : if (action == LOCK)
119 : 20 : retcode = do_lock(db, pkg);
120 : : else
121 : 16 : retcode = do_unlock(db, pkg);
122 : :
123 [ - + ]: 36 : if (retcode != EPKG_OK) {
124 : 0 : exitcode = EXIT_FAILURE;
125 : 0 : goto cleanup;
126 : : }
127 : : }
128 : :
129 : : cleanup:
130 : 28 : pkg_free(pkg);
131 : 28 : pkgdb_it_free(it);
132 : :
133 : 28 : pkgdb_release_lock(db, PKGDB_LOCK_EXCLUSIVE);
134 : :
135 : 28 : return (exitcode);
136 : 28 : }
137 : :
138 : : int
139 : 36 : exec_lock(int argc, char **argv)
140 : : {
141 : 36 : return (exec_lock_unlock(argc, argv, LOCK));
142 : : }
143 : :
144 : : int
145 : 12 : exec_unlock(int argc, char **argv)
146 : : {
147 : 12 : return (exec_lock_unlock(argc, argv, UNLOCK));
148 : : }
149 : :
150 : : static int
151 : 20 : list_locked(struct pkgdb *db, bool has_locked)
152 : : {
153 : 20 : struct pkgdb_it *it = NULL;
154 : 20 : struct pkg *pkg = NULL;
155 : 20 : bool gotone = false;
156 : :
157 [ + - ]: 20 : if ((it = pkgdb_query_cond(db, " WHERE locked=1", NULL, MATCH_ALL)) == NULL) {
158 : 0 : pkgdb_close(db);
159 : 0 : return (EXIT_FAILURE);
160 : : }
161 : :
162 [ + - - + ]: 20 : if (!quiet && !has_locked)
163 : 20 : printf("Currently locked packages:\n");
164 : :
165 [ + + ]: 36 : while (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC) == EPKG_OK) {
166 : 16 : gotone = true;
167 [ + - ]: 16 : if (has_locked)
168 : 0 : break;
169 : 16 : pkg_printf("%n-%v\n", pkg, pkg);
170 : : }
171 : :
172 : 20 : pkg_free(pkg);
173 : 20 : pkgdb_it_free(it);
174 : :
175 [ - + ]: 20 : if (has_locked)
176 : 0 : return (gotone ? EXIT_SUCCESS : EXIT_FAILURE);
177 : :
178 : 20 : return (EXIT_SUCCESS);
179 : 20 : }
180 : :
181 : : static int
182 : 48 : exec_lock_unlock(int argc, char **argv, enum action action)
183 : : {
184 : 48 : struct pkgdb *db = NULL;
185 : 48 : int match = MATCH_EXACT;
186 : : int retcode, i;
187 : 48 : int exitcode = EXIT_SUCCESS;
188 : : int ch;
189 : 48 : bool show_locked = false;
190 : 48 : bool read_only = false;
191 : 48 : bool has_locked_packages = false;
192 : :
193 : 48 : struct option longopts[] = {
194 : : { "all", no_argument, NULL, 'a' },
195 : : { "case-sensitive", no_argument, NULL, 'C' },
196 : : { "glob", no_argument, NULL, 'g' },
197 : : { "show-locked", no_argument, NULL, 'l' },
198 : : { "quiet", no_argument, NULL, 'q' },
199 : : { "regex", no_argument, NULL, 'x' },
200 : : { "yes", no_argument, NULL, 'y' },
201 : : { "has-locked-packages",no_argument, NULL, 1 },
202 : : { NULL, 0, NULL, 0 },
203 : : };
204 : :
205 [ + + ]: 104 : while ((ch = getopt_long(argc, argv, "+aCgilqxy", longopts, NULL)) != -1) {
206 [ + - - - : 56 : switch (ch) {
+ - - + -
- ]
207 : : case 'a':
208 : 8 : match = MATCH_ALL;
209 : 8 : break;
210 : : case 'C':
211 : 0 : pkgdb_set_case_sensitivity(true);
212 : 0 : break;
213 : : case 'g':
214 : 0 : match = MATCH_GLOB;
215 : 0 : break;
216 : : case 'i':
217 : 0 : pkgdb_set_case_sensitivity(false);
218 : 0 : break;
219 : : case 'l':
220 : 20 : show_locked = true;
221 : 20 : break;
222 : : case 'q':
223 : 0 : quiet = true;
224 : 0 : break;
225 : : case 'x':
226 : 0 : match = MATCH_REGEX;
227 : 0 : break;
228 : : case 'y':
229 : 28 : yes = true;
230 : 28 : break;
231 : : case 1:
232 : 0 : show_locked = true;
233 : 0 : has_locked_packages = true;
234 : 0 : break;
235 : : default:
236 : 0 : usage_lock();
237 : 0 : return (EXIT_FAILURE);
238 : : }
239 : : }
240 : 48 : argc -= optind;
241 : 48 : argv += optind;
242 : :
243 : : /* Allow 'pkg lock -l' (or 'pkg unlock -l') without any
244 : : * package arguments to just display what packages are
245 : : * currently locked. In this case, we only need a read_only
246 : : * connection to the DB. */
247 : :
248 [ + + + - : 48 : if (show_locked && match != MATCH_ALL && argc == 0)
+ - ]
249 : 20 : read_only = true;
250 : :
251 [ + + + + : 48 : if (!show_locked && match != MATCH_ALL && argc == 0) {
- + ]
252 : 0 : usage_lock();
253 : 0 : return (EXIT_FAILURE);
254 : : }
255 : :
256 [ + + ]: 48 : if (read_only)
257 : 20 : retcode = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_LOCAL);
258 : : else
259 : 28 : retcode = pkgdb_access(PKGDB_MODE_READ|PKGDB_MODE_WRITE,
260 : : PKGDB_DB_LOCAL);
261 [ - + ]: 48 : if (retcode == EPKG_ENODB) {
262 [ # # ]: 0 : if (match == MATCH_ALL)
263 : 0 : return (EXIT_SUCCESS);
264 [ # # ]: 0 : if (!quiet)
265 : 0 : warnx("No packages installed. Nothing to do!");
266 : 0 : return (EXIT_SUCCESS);
267 [ - + ]: 48 : } else if (retcode == EPKG_ENOACCESS) {
268 : 0 : warnx("Insufficient privileges to modify the package database");
269 : 0 : return (EXIT_FAILURE);
270 [ - + ]: 48 : } else if (retcode != EPKG_OK) {
271 : 0 : warnx("Error accessing the package database");
272 : 0 : return (EXIT_FAILURE);
273 : : }
274 : :
275 : 48 : retcode = pkgdb_open(&db, PKGDB_DEFAULT);
276 [ - + ]: 48 : if (retcode != EPKG_OK)
277 : 0 : return (EXIT_FAILURE);
278 : :
279 [ + + ]: 48 : if (!read_only) {
280 [ + + ]: 28 : if (match == MATCH_ALL) {
281 : 8 : exitcode = do_lock_unlock(db, match, NULL, action);
282 : 8 : } else {
283 [ + + ]: 40 : for (i = 0; i < argc; i++) {
284 : 20 : retcode = do_lock_unlock(db, match, argv[i], action);
285 [ + - ]: 20 : if (retcode != EXIT_SUCCESS)
286 : 0 : exitcode = retcode;
287 : 20 : }
288 : : }
289 : 28 : }
290 : :
291 [ + + ]: 48 : if (show_locked)
292 : 20 : exitcode = list_locked(db, has_locked_packages);
293 : :
294 : 48 : pkgdb_close(db);
295 : :
296 : 48 : return (exitcode == EPKG_OK ? EXIT_SUCCESS : EXIT_FAILURE);
297 : 48 : }
|