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