Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/src/lock.c
2065 views
1
/*-
2
* Copyright (c) 2012-2014 Matthew Seaman <[email protected]>
3
* Copyright (c) 2015-2025 Baptiste Daroussin <[email protected]>
4
*
5
* SPDX-License-Identifier: BSD-2-Clause
6
*/
7
8
#include <err.h>
9
#include <getopt.h>
10
#include <stdio.h>
11
#include <stdlib.h>
12
#include <unistd.h>
13
14
#include <pkg.h>
15
16
#include "pkgcli.h"
17
18
static int exec_lock_unlock(int, char**, int (*lockfct)(struct pkgdb *, struct pkg *, bool batch));
19
static int do_lock(struct pkgdb *db, struct pkg *pkg, bool batch);
20
static int do_unlock(struct pkgdb *db, struct pkg *pkg, bool batch);
21
22
void
23
usage_lock(void)
24
{
25
fprintf(stderr, "Usage: pkg lock [-lqy] [-a|[-Cgix] <pkg-name>]\n");
26
fprintf(stderr, " pkg lock --has-locked-packages\n");
27
fprintf(stderr, " pkg unlock [-lqy] [-a|[-Cgix] <pkg-name>]\n");
28
fprintf(stderr, "For more information see 'pkg help lock'.\n");
29
}
30
31
static int
32
do_lock(struct pkgdb *db, struct pkg *pkg, bool batch)
33
{
34
if (pkg_is_locked(pkg)) {
35
if (batch)
36
return (EPKG_OK);
37
if (!quiet)
38
pkg_printf("%n-%v: already locked\n",
39
pkg, pkg);
40
return (EPKG_FATAL);
41
}
42
43
if (!query_yesno(false, "%n-%v: lock this package? ",
44
pkg, pkg))
45
return (EPKG_OK);
46
47
if (!quiet)
48
pkg_printf("Locking %n-%v\n", pkg, pkg);
49
50
return (pkgdb_set(db, pkg, PKG_SET_LOCKED, (int)true));
51
}
52
53
54
static int
55
do_unlock(struct pkgdb *db, struct pkg *pkg, bool batch)
56
{
57
if (!pkg_is_locked(pkg)) {
58
if (batch)
59
return (EPKG_OK);
60
if (!quiet)
61
pkg_printf("%n-%v: already unlocked\n", pkg, pkg);
62
return (EPKG_FATAL);
63
}
64
65
if (!query_yesno(false, "%n-%v: unlock this package? ",
66
pkg, pkg))
67
return (EPKG_OK);
68
69
if (!quiet)
70
pkg_printf("Unlocking %n-%v\n", pkg, pkg);
71
72
return (pkgdb_set(db, pkg, PKG_SET_LOCKED, (int)false));
73
}
74
75
static int
76
do_lock_unlock(struct pkgdb *db, int match, const char *pkgname,
77
int (*lockfct)(struct pkgdb *, struct pkg *, bool))
78
{
79
struct pkgdb_it *it = NULL;
80
struct pkg *pkg = NULL;
81
int retcode;
82
int exitcode = EXIT_SUCCESS;
83
bool gotone = false;
84
vec_t(struct pkg *)pkgs = vec_init();
85
86
if (pkgdb_obtain_lock(db, PKGDB_LOCK_EXCLUSIVE) != EPKG_OK) {
87
pkgdb_close(db);
88
warnx("Cannot get an exclusive lock on database. "
89
"It is locked by another process");
90
return (EXIT_FAILURE);
91
}
92
93
if ((it = pkgdb_query(db, pkgname, match)) == NULL) {
94
exitcode = EXIT_FAILURE;
95
goto cleanup;
96
}
97
98
while (pkgdb_it_next(it, &pkg, 0) == EPKG_OK) {
99
gotone = true;
100
vec_push(&pkgs, pkg);
101
pkg = NULL;
102
}
103
vec_foreach(pkgs, i) {
104
retcode = lockfct(db, pkgs.d[i], match != MATCH_EXACT);
105
if (retcode != EPKG_OK) {
106
exitcode = EXIT_FAILURE;
107
goto cleanup;
108
}
109
}
110
111
/* No package was found matching that name. */
112
if (gotone == false)
113
exitcode = EXIT_FAILURE;
114
115
cleanup:
116
vec_free_and_free(&pkgs, pkg_free);
117
pkgdb_it_free(it);
118
119
pkgdb_release_lock(db, PKGDB_LOCK_EXCLUSIVE);
120
121
return (exitcode);
122
}
123
124
int
125
exec_lock(int argc, char **argv)
126
{
127
return (exec_lock_unlock(argc, argv, do_lock));
128
}
129
130
int
131
exec_unlock(int argc, char **argv)
132
{
133
return (exec_lock_unlock(argc, argv, do_unlock));
134
}
135
136
static int
137
list_locked(struct pkgdb *db, bool has_locked)
138
{
139
struct pkgdb_it *it = NULL;
140
struct pkg *pkg = NULL;
141
bool gotone = false;
142
143
if ((it = pkgdb_query_cond(db, " WHERE locked=1", NULL, MATCH_ALL)) == NULL) {
144
pkgdb_close(db);
145
return (EXIT_FAILURE);
146
}
147
148
while (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC) == EPKG_OK) {
149
if (!gotone) {
150
gotone = true;
151
if (has_locked) {
152
break;
153
} else {
154
if (!quiet) {
155
printf("Currently locked packages:\n");
156
}
157
}
158
}
159
pkg_printf("%n-%v\n", pkg, pkg);
160
}
161
162
if (!gotone && !quiet && !has_locked)
163
printf("No locked packages were found\n");
164
165
pkg_free(pkg);
166
pkgdb_it_free(it);
167
168
return (gotone ? EXIT_SUCCESS : EXIT_FAILURE);
169
}
170
171
static int
172
exec_lock_unlock(int argc, char **argv, int (*lockfct)(struct pkgdb *, struct pkg *, bool))
173
{
174
struct pkgdb *db = NULL;
175
int match = MATCH_EXACT;
176
int retcode, i;
177
int exitcode = EXIT_SUCCESS;
178
int ch;
179
bool show_locked = false;
180
bool read_only = false;
181
bool has_locked_packages = false;
182
183
struct option longopts[] = {
184
{ "all", no_argument, NULL, 'a' },
185
{ "case-sensitive", no_argument, NULL, 'C' },
186
{ "glob", no_argument, NULL, 'g' },
187
{ "show-locked", no_argument, NULL, 'l' },
188
{ "quiet", no_argument, NULL, 'q' },
189
{ "regex", no_argument, NULL, 'x' },
190
{ "yes", no_argument, NULL, 'y' },
191
{ "has-locked-packages",no_argument, NULL, 1 },
192
{ NULL, 0, NULL, 0 },
193
};
194
195
while ((ch = getopt_long(argc, argv, "+aCgilqxy", longopts, NULL)) != -1) {
196
switch (ch) {
197
case 'a':
198
match = MATCH_ALL;
199
break;
200
case 'C':
201
pkgdb_set_case_sensitivity(true);
202
break;
203
case 'g':
204
match = MATCH_GLOB;
205
break;
206
case 'i':
207
pkgdb_set_case_sensitivity(false);
208
break;
209
case 'l':
210
show_locked = true;
211
break;
212
case 'q':
213
quiet = true;
214
break;
215
case 'x':
216
match = MATCH_REGEX;
217
break;
218
case 'y':
219
yes = true;
220
break;
221
case 1:
222
show_locked = true;
223
has_locked_packages = true;
224
break;
225
default:
226
usage_lock();
227
return (EXIT_FAILURE);
228
}
229
}
230
argc -= optind;
231
argv += optind;
232
233
/* Allow 'pkg lock -l' (or 'pkg unlock -l') without any
234
* package arguments to just display what packages are
235
* currently locked. In this case, we only need a read_only
236
* connection to the DB. */
237
238
if (show_locked && match != MATCH_ALL && argc == 0)
239
read_only = true;
240
241
if (!show_locked && match != MATCH_ALL && argc == 0) {
242
usage_lock();
243
return (EXIT_FAILURE);
244
}
245
246
if (read_only)
247
retcode = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_LOCAL);
248
else
249
retcode = pkgdb_access(PKGDB_MODE_READ|PKGDB_MODE_WRITE,
250
PKGDB_DB_LOCAL);
251
if (retcode == EPKG_ENODB) {
252
if (match == MATCH_ALL)
253
return (EXIT_SUCCESS);
254
if (!quiet)
255
warnx("No packages installed. Nothing to do!");
256
return (EXIT_SUCCESS);
257
} else if (retcode == EPKG_ENOACCESS) {
258
warnx("Insufficient privileges to modify the package database");
259
return (EXIT_FAILURE);
260
} else if (retcode != EPKG_OK) {
261
warnx("Error accessing the package database");
262
return (EXIT_FAILURE);
263
}
264
265
retcode = pkgdb_open(&db, PKGDB_DEFAULT);
266
if (retcode != EPKG_OK)
267
return (EXIT_FAILURE);
268
269
if (!read_only) {
270
if (match == MATCH_ALL) {
271
exitcode = do_lock_unlock(db, match, NULL, lockfct);
272
} else {
273
for (i = 0; i < argc; i++) {
274
exitcode = do_lock_unlock(db, match, argv[i], lockfct);
275
}
276
}
277
}
278
279
if (show_locked)
280
exitcode = list_locked(db, has_locked_packages);
281
282
pkgdb_close(db);
283
284
return (exitcode);
285
}
286
287